From 5f0561f338957f9dac3fda9241c402ff691b969e Mon Sep 17 00:00:00 2001
From: "ben.franksen" <ben.franksen@online.de>
Date: Sun, 7 Nov 2010 22:16:20 +0000
Subject: [PATCH] re-wrote variable type and declaration handling in compiler

Also added string typedef to generated code.
---
 src/snc/Makefile      |   1 +
 src/snc/analysis.c    |  54 ++++++------
 src/snc/gen_code.c    |  57 +++++++------
 src/snc/gen_ss_code.c |  79 ++++++++++++------
 src/snc/gen_tables.c  |  39 ++++-----
 src/snc/parse.c       |  56 -------------
 src/snc/parse.h       |   8 ++
 src/snc/snl.lem       |  59 +++++++------
 src/snc/types.h       |  45 ++--------
 src/snc/var_types.c   | 187 ++++++++++++++++++++++++++++++++++++++++++
 src/snc/var_types.h   |  56 +++++++++++++
 11 files changed, 424 insertions(+), 217 deletions(-)
 create mode 100644 src/snc/var_types.c
 create mode 100644 src/snc/var_types.h

diff --git a/src/snc/Makefile b/src/snc/Makefile
index 75071427..f0285f5d 100644
--- a/src/snc/Makefile
+++ b/src/snc/Makefile
@@ -19,6 +19,7 @@ snc_SRCS += snl.c           # generated by lemon
 
 snc_SRCS += snc_main.c      # main program
 snc_SRCS += parse.c         # parse routines
+snc_SRCS += var_types.c     # declarations
 snc_SRCS += analysis.c      # analysis routines
 snc_SRCS += gen_code.c      # code generation
 snc_SRCS += gen_ss_code.c   # code generation (state sets)
diff --git a/src/snc/analysis.c b/src/snc/analysis.c
index fc8fa491..7a9d7814 100644
--- a/src/snc/analysis.c
+++ b/src/snc/analysis.c
@@ -270,6 +270,14 @@ static void analyse_declaration(SymTable st, Expr *scope, Expr *defn)
 	report("declaration: %s\n", vp->name);
 #endif
 
+	if (scope->type != D_PROG && vp->type->tag <= V_EVFLAG)
+	{
+		error_at_expr(defn,
+			"%s can only be declared at the top-level\n",
+			vp->type->tag == V_NONE ? "foreign variables"
+			: "event flags");
+	}
+
 	VarList *var_list = *pvar_list_from_scope(scope);
 
 	if (!sym_table_insert(st, vp->name, var_list, vp))
@@ -300,7 +308,8 @@ static void analyse_assign(SymTable st, ChanList *chan_list, Expr *scope, Expr *
 		error_at_expr(defn, "variable '%s' not declared\n", name);
 		return;
 	}
-	if (vp->type == V_NONE)
+	assert(vp->type);
+	if (!type_assignable(vp->type))
 	{
 		error_at_expr(defn, "this type of variable cannot be assigned to a pv\n", name);
 		return;
@@ -345,7 +354,7 @@ static void assign_single(
 	}
 	vp->assign = M_SINGLE;
 	vp->chan.single = new_channel(
-		chan_list, vp, vp->length1 * vp->length2, 0);
+		chan_list, vp, type_array_length1(vp->type) * type_array_length2(vp->type), 0);
 	vp->chan.single->name = pv_name->value;
 }
 
@@ -361,18 +370,18 @@ static void assign_elem(
 	assert(defn);
 	assert(vp);
 	assert(pv_name);
-	assert(n_subscr <= vp->length1);
+	assert(n_subscr <= type_array_length1(vp->type));
 
 	if (vp->assign == M_NONE)
 	{
 		int n;
 
 		vp->assign = M_MULTI;
-		vp->chan.multi = (Chan **)calloc(vp->length1, sizeof(Chan *));
-		for (n = 0; n < vp->length1; n++)
+		vp->chan.multi = (Chan **)calloc(type_array_length1(vp->type), sizeof(Chan *));
+		for (n = 0; n < type_array_length1(vp->type); n++)
 		{
 			vp->chan.multi[n] = new_channel(
-				chan_list, vp, vp->length2, n);
+				chan_list, vp, type_array_length2(vp->type), n);
 		}
 	}
 	assert(vp->assign == M_MULTI);
@@ -408,7 +417,7 @@ static void assign_subscript(
 	report("assign %s[%s] to '%s';\n", vp->name, subscr->value, pv_name);
 #endif
 
-	if (vp->class != VC_ARRAY1 && vp->class != VC_ARRAY2)
+	if (vp->type->tag != V_ARRAY)
 	{
 		error_at_expr(defn, "variable '%s' is not an array\n", vp->name);
 		return;
@@ -418,7 +427,7 @@ static void assign_subscript(
 		error_at_expr(defn, "variable '%s' already assigned\n", vp->name);
 		return;
 	}
-	if (!strtoui(subscr->value, vp->length1, &n_subscr))
+	if (!strtoui(subscr->value, type_array_length1(vp->type), &n_subscr))
 	{
 		error_at_expr(subscr, "subscript in '%s[%s]' out of range\n",
 			vp->name, subscr->value);
@@ -449,7 +458,7 @@ static void assign_list(
 	report("assign %s to {", vp->name);
 #endif
 
-	if (vp->class != VC_ARRAY1 && vp->class != VC_ARRAY2)
+	if (vp->type->tag != V_ARRAY)
 	{
 		error_at_expr(defn, "variable '%s' is not an array\n", vp->name);
 		return;
@@ -497,7 +506,7 @@ static void monitor_var(Expr *defn, Var *vp)
 	{
 		uint n;
 		assert(vp->assign == M_MULTI);
-		for (n = 0; n < vp->length1; n++)
+		for (n = 0; n < type_array_length1(vp->type); n++)
 		{
 			vp->chan.multi[n]->monitor = TRUE;
 		}
@@ -517,12 +526,12 @@ static void monitor_elem(Expr *defn, Var *vp, Expr *subscr)
 	report("monitor %s[%s];\n", vp->name, subscr->value);
 #endif
 
-	if (vp->class != VC_ARRAY1 && vp->class != VC_ARRAY2)
+	if (vp->type->tag != V_ARRAY)
 	{
 		error_at_expr(defn, "variable '%s' is not an array\n", vp->name);
 		return;
 	}
-	if (!strtoui(subscr->value, vp->length1, &n_subscr))
+	if (!strtoui(subscr->value, type_array_length1(vp->type), &n_subscr))
 	{
 		error_at_expr(subscr, "subscript in '%s[%s]' out of range\n",
 			vp->name, subscr->value);
@@ -632,7 +641,7 @@ static void sync_var(Expr *defn, Var *vp, Var *evp)
 		uint n;
 		assert(vp->assign == M_MULTI);	/* else */
 		vp->sync = M_SINGLE;
-		for (n = 0; n < vp->length1; n++)
+		for (n = 0; n < type_array_length1(vp->type); n++)
 		{
 			assert(vp->chan.multi[n]->monitor);
 			assert(!vp->chan.multi[n]->sync);
@@ -657,12 +666,12 @@ static void sync_elem(Expr *defn, Var *vp, Expr *subscr, Var *evp)
 	report("sync %s[%d] to %s;\n", vp->name, subscr->value, evp->name);
 #endif
 
-	if (vp->class != VC_ARRAY1 && vp->class != VC_ARRAY2)
+	if (vp->type->tag != V_ARRAY)
 	{
 		error_at_expr(defn, "variable '%s' is not an array\n", vp->name);
 		return;
 	}
-	if (!strtoui(subscr->value, vp->length1, &n_subscr))
+	if (!strtoui(subscr->value, type_array_length1(vp->type), &n_subscr))
 	{
 		error_at_expr(subscr, "subscript in '%s[%s]' out of range\n",
 			vp->name, subscr->value);
@@ -730,7 +739,7 @@ static void analyse_sync(SymTable st, Expr *scope, Expr *defn)
 		error_at_expr(defn, "event flag '%s' not declared\n", ef_name);
 		return;
 	}
-	if (evp->class != VC_EVFLAG)
+	if (evp->type->tag != V_EVFLAG)
 	{
 		error_at_expr(defn, "variable '%s' is not a event flag\n", ef_name);
 		return;
@@ -786,7 +795,7 @@ static void syncq_var(Expr *defn, Var *vp, SyncQ *qp)
 		uint n;
 		assert(vp->assign == M_MULTI);	/* else */
 		vp->syncq = M_SINGLE;
-		for (n = 0; n < vp->length1; n++)
+		for (n = 0; n < type_array_length1(vp->type); n++)
 		{
 			assert(vp->chan.multi[n]->monitor);
 			assert(!vp->chan.multi[n]->syncq);
@@ -811,12 +820,12 @@ static void syncq_elem(Expr *defn, Var *vp, Expr *subscr, SyncQ *qp)
 	report("syncq %s[%d] to %s;\n", vp->name, subscr->value, qp->ef_var->name);
 #endif
 
-	if (vp->class != VC_ARRAY1 && vp->class != VC_ARRAY2)
+	if (vp->type->tag != V_ARRAY)
 	{
 		error_at_expr(defn, "variable '%s' is not an array\n", vp->name);
 		return;
 	}
-	if (!strtoui(subscr->value, vp->length1, &n_subscr))
+	if (!strtoui(subscr->value, type_array_length1(vp->type), &n_subscr))
 	{
 		error_at_expr(subscr, "subscript in '%s[%s]' out of range\n",
 			vp->name, subscr->value);
@@ -886,7 +895,7 @@ static void analyse_syncq(SymTable st, SyncQList *syncq_list, Expr *scope, Expr
 		error_at_expr(defn, "event flag '%s' not declared\n", ef_name);
 		return;
 	}
-	if (evp->class != VC_EVFLAG)
+	if (evp->type->tag != V_EVFLAG)
 	{
 		error_at_expr(defn, "variable '%s' is not a event flag\n", ef_name);
 		return;
@@ -1045,9 +1054,6 @@ static int connect_variable(Expr *ep, Expr *scope, void *parg)
 		vp = new(Var);
 		vp->name = ep->value;
 		vp->type = V_NONE;	/* undeclared type */
-		vp->class = VC_FOREIGN;
-		vp->length1 = 1;
-		vp->length2 = 1;
 		vp->value = 0;
 		/* add this variable to the top-level scope, NOT the current scope */
 		while (var_list->parent_scope) {
@@ -1291,7 +1297,7 @@ static uint assign_ef_bits(Expr *scope)
 	/* Assign event flag numbers (starting at 1) */
 	foreach (vp, var_list->first)
 	{
-		if (vp->class == VC_EVFLAG)
+		if (vp->type->tag == V_EVFLAG)
 		{
 			vp->chan.evflag->index = ++num_event_flags;
 		}
diff --git a/src/snc/gen_code.c b/src/snc/gen_code.c
index 6ee6f484..67d37244 100644
--- a/src/snc/gen_code.c
+++ b/src/snc/gen_code.c
@@ -20,8 +20,6 @@
 #include	"snc_main.h"
 #include	"gen_code.h"
 
-static const int impossible = 0;
-
 static void gen_preamble(char *prog_name, int opt_main);
 static void gen_user_var(Program *p);
 static void gen_global_c_code(Expr *global_c_list);
@@ -36,8 +34,7 @@ static int assert_var_declared(Expr *ep, Expr *scope, void *parg)
 	assert(ep->type == E_VAR);
 	assert(ep->extra.e_var != 0);
 	assert(ep->extra.e_var->decl != 0 ||
-		(ep->extra.e_var->type == V_NONE &&
-	 	ep->extra.e_var->class == VC_FOREIGN));
+		ep->extra.e_var->type->tag == V_NONE);
 	return TRUE;		/* there are no children anyway */
 }
 
@@ -89,11 +86,11 @@ static void gen_preamble(char *prog_name, int opt_main)
 
 	/* Includes */
 	printf("#include <string.h>\n");
+	printf("#include <stdio.h>\n");
 	printf("#include \"seqCom.h\"\n");
 
-	/* The following definition should be consistent with db_access.h */
-	printf("\n");
-	printf("#define MAX_STRING_SIZE 40\n");
+	/* The string typedef */
+	printf("\ntypedef char string[MAX_STRING_SIZE];\n");
 
 	/* Main program (if "main" option set) */
 	if (opt_main) {
@@ -125,13 +122,33 @@ static void gen_preamble(char *prog_name, int opt_main)
 	}
 }
 
+static void gen_array_pointer(Type *t, unsigned last_tag, char *name)
+{
+	switch (t->tag)
+	{
+	case V_POINTER:
+		if (last_tag == V_ARRAY)
+			printf("(");
+		printf("*");
+		gen_array_pointer(t->val.pointer.value_type, t->tag, name);
+		if (last_tag == V_ARRAY)
+			printf(")");
+		break;
+	case V_ARRAY:
+		gen_array_pointer(t->val.array.elem_type, t->tag, name);
+		printf("[%d]", t->val.array.num_elems);
+		break;
+	default:
+		printf("%s", name);
+	}
+}
+
 void gen_var_decl(Var *vp)
 {
 	char	*type_str;
+	Type	*t = vp->type;
 
-	assert(vp->type != V_NONE);
-
-	switch (vp->type)
+	switch (type_base_type(vp->type))
 	{
 	case V_CHAR:	type_str = "char";		break;
 	case V_INT:	type_str = "int";		break;
@@ -143,28 +160,18 @@ void gen_var_decl(Var *vp)
 	case V_USHORT:	type_str = "unsigned short";	break;
 	case V_FLOAT:	type_str = "float";		break;
 	case V_DOUBLE:	type_str = "double";		break;
-	case V_STRING:	type_str = "char";		break;
-	case V_NONE:
-	default:
-		assert(impossible);
+	case V_STRING:	type_str = "string";		break;
+	default:	type_str = 0;			break;
 	}
 	printf("%s\t", type_str);
-	if (vp->class == VC_POINTER || vp->class == VC_ARRAYP)
-		printf("*");
-	printf("%s", vp->name);
-	if (vp->class == VC_ARRAY1 || vp->class == VC_ARRAYP)
-		printf("[%d]", vp->length1);
-	else if (vp->class == VC_ARRAY2)
-		printf("[%d][%d]", vp->length1, vp->length2);
-	if (vp->type == V_STRING)
-		printf("[MAX_STRING_SIZE]");
+	gen_array_pointer(t, V_NONE, vp->name);
 }
 
 /* Generate the UserVar struct containing all program variables with
    'infinite' (global) lifetime. These are: variables declared at the
    top-level, inside a state set, and inside a state. Note that state
    set and state local variables are _visible_ only inside the block
-   where they are declared, but still have gobal lifetime. To avoid
+   where they are declared, but still have global lifetime. To avoid
    name collisions, generate a nested struct for each state set, and
    for each state in a state set. */
 static void gen_user_var(Program *p)
@@ -179,7 +186,7 @@ static void gen_user_var(Program *p)
 	/* Convert internal type to `C' type */
 	foreach (vp, p->prog->extra.e_prog->first)
 	{
-		if (vp->decl && vp->type != V_NONE)
+		if (vp->decl && vp->type->tag >= V_CHAR)
 		{
 			gen_line_marker(vp->decl);
 			if (!opt_reent) printf("static");
diff --git a/src/snc/gen_ss_code.c b/src/snc/gen_ss_code.c
index fbd35a81..3b482150 100644
--- a/src/snc/gen_ss_code.c
+++ b/src/snc/gen_ss_code.c
@@ -259,7 +259,7 @@ static void gen_local_var_decls(Expr *scope, int level)
 	/* Convert internal type to `C' type */
 	foreach (vp, var_list->first)
 	{
-		if (vp->decl && vp->type != V_NONE)
+		if (vp->decl && vp->type->tag != V_NONE)
 		{
 			gen_line_marker(vp->decl);
 			indent(level);
@@ -268,12 +268,14 @@ static void gen_local_var_decls(Expr *scope, int level)
 			/* optional initialisation */
 			if (vp->value)
 			{
-				if (vp->type == V_STRING)
+#if 0
+				if (vp->type->tag == V_STRING)
 				{
 					error_at_expr(vp->decl,
 					  "initialisation not allowed for variables of this type");
 					return;
 				}
+#endif
 				printf(" = ");
 				gen_expr(OTHER_STMT, vp->value, 0);
 			}
@@ -455,11 +457,11 @@ static void gen_var_access(Var *vp)
 #endif
 	assert((1<<vp->scope->type) & scope_mask);
 
-	if (vp->class == VC_EVFLAG)
+	if (vp->type->tag == V_EVFLAG)
 	{
 		printf("%d", vp->chan.evflag->index);
 	}
-	else if (vp->type == V_NONE)
+	else if (vp->type->tag == V_NONE)
 	{
 		printf("%s", vp->name);
 	}
@@ -483,16 +485,28 @@ static void gen_var_access(Var *vp)
 	}
 }
 
+void gen_string_assign(int stmt_type, Expr *left, Expr *right, int level)
+{
+	printf("strncpy(");
+	gen_expr(stmt_type, left, level);
+	printf(", ");
+	gen_expr(stmt_type, right, level);
+	printf(", MAX_STRING_SIZE-1)");
+}
+
 int special_assign_op(int stmt_type, Expr *ep, int level)
 {
-	if (ep->binop_left->type == E_VAR
-		&& ep->binop_left->extra.e_var->type == V_STRING)
+	Expr *left = ep->binop_left;
+	Expr *right = ep->binop_right;
+	if (
+		(left->type == E_VAR &&
+		left->extra.e_var->type->tag == V_STRING)
+		|| (left->type == E_SUBSCR
+		&& left->subscr_operand->type == E_VAR
+		&& type_base_type(left->subscr_operand->extra.e_var->type) == V_STRING)
+	)
 	{
-		printf("strncpy(");
-		gen_var_access(ep->binop_left->extra.e_var);
-		printf(", ");
-		gen_expr(stmt_type, ep->binop_right, level);
-		printf(", MAX_STRING_SIZE-1)");
+		gen_string_assign(stmt_type, left, right, level);
 		return TRUE;
 	}
 	return FALSE;
@@ -590,6 +604,12 @@ static void gen_expr(
 	case E_VAR:
 		gen_var_access(ep->extra.e_var);
 		break;
+	case E_SUBSCR:
+		gen_expr(stmt_type, ep->subscr_operand, 0);
+		printf("[");
+		gen_expr(stmt_type, ep->subscr_index, 0);
+		printf("]");
+		break;
 	case E_CONST:
 		if (special_const(stmt_type, ep))
 			break;
@@ -640,12 +660,6 @@ static void gen_expr(
 		gen_expr(stmt_type, ep->post_operand, 0);
 		printf("%s", ep->value);
 		break;
-	case E_SUBSCR:
-		gen_expr(stmt_type, ep->subscr_operand, 0);
-		printf("[");
-		gen_expr(stmt_type, ep->subscr_index, 0);
-		printf("]");
-		break;
 	/* C-code can be either definition, statement, or expression */
 	case T_TEXT:
 		indent(level);
@@ -798,7 +812,7 @@ static void gen_ef_func(
 		error_at_expr(ep, "%s cannot be used in a when condition\n", fname);
 		return;
 	}
-	if (vp->class != VC_EVFLAG)
+	if (vp->type->tag != V_EVFLAG)
 	{
 		error_at_expr(ep, "argument to '%s' must be an event flag\n", fname);
 		return;
@@ -944,7 +958,7 @@ static void gen_pv_func(
 	{
 		if (ap->type != E_SUBSCR)
 		{
-			printf(", %d", vp->length1);
+			printf(", %d", type_array_length1(vp->type));
 		}
 		else
 		{
@@ -986,18 +1000,29 @@ static int iter_user_var_init(Expr *dp, Expr *scope, void *parg)
 	assert(vp);
 	if (vp->value && vp->decl)
 	{
-		if (vp->type == V_NONE || vp->type == V_STRING)
+		if (vp->type->tag < V_CHAR)
 		{
 			error_at_expr(vp->decl,
 			  "initialisation not allowed for variables of this type");
-			return FALSE;
 		}
-		gen_line_marker(dp);
-		indent(1);
-		gen_var_access(vp);
-		printf(" = ");
-		gen_expr(OTHER_STMT, vp->value, 0);
-		printf(";\n");
+		else if (type_base_type(vp->type) == V_STRING)
+		{
+			Expr *ep = new(Expr);
+			ep->type = E_VAR;
+			ep->extra.e_var = vp;
+			indent(1);
+			gen_string_assign(OTHER_STMT, ep, vp->value, 0);
+			printf(";\n");
+		}
+		else
+		{
+			gen_line_marker(dp);
+			indent(1);
+			gen_var_access(vp);
+			printf(" = ");
+			gen_expr(OTHER_STMT, vp->value, 0);
+			printf(";\n");
+		}
 	}
 	return FALSE;		/* do not descend into children */
 }
diff --git a/src/snc/gen_tables.c b/src/snc/gen_tables.c
index 2b208611..19abc9d7 100644
--- a/src/snc/gen_tables.c
+++ b/src/snc/gen_tables.c
@@ -100,15 +100,15 @@ static void gen_channel(Chan *cp, int num_event_flags, int opt_reent)
 
 	vp = cp->var;
 	/* Figure out text needed to handle subscripts */
-	if (vp->class == VC_ARRAY1 || vp->class == VC_ARRAYP)
+	if (vp->assign == M_MULTI)
 		sprintf(elem_str, "[%d]", cp->index);
-	else if (vp->class == VC_ARRAY2)
-		sprintf(elem_str, "[%d][0]", cp->index);
 	else
 		elem_str[0] = '\0';
-	if (vp->type == V_STRING)
+#if 0
+	if (vp->type->tag == V_STRING)
 		suffix = "[0]";
 	else
+#endif
 		suffix = "";
 	pv_name = cp->name;
 	mon_flag = cp->monitor;
@@ -135,7 +135,7 @@ static void gen_channel(Chan *cp, int num_event_flags, int opt_reent)
  	/* variable name with optional elem num */
 	printf("\"%s%s\", ", vp->name, elem_str);
  	/* variable type */
-	printf("\n    \"%s\", ", pv_type_str(vp->type));
+	printf("\n    \"%s\", ", pv_type_str(type_base_type(vp->type)));
 	/* count, for requests */
 	printf("%d, ", cp->count);
 	/* event number */
@@ -148,7 +148,7 @@ static void gen_channel(Chan *cp, int num_event_flags, int opt_reent)
 	if (!cp->syncq)
 		printf("0, 0, 0");
 	else
-		printf("%d, %d, %d", 1, cp->syncq->size, cp->syncq->index);
+		printf("1, %d, %d", cp->syncq->size, cp->syncq->index);
 	printf("}");
 }
 
@@ -304,10 +304,8 @@ static void gen_ss_table(SymTable st, Expr *ss_list)
 	num_ss = 0;
 	foreach (ssp, ss_list)
 	{
-		Expr *err_sp;
-
 		if (num_ss > 0)
-			printf("\n\n");
+			printf("\n");
 		num_ss++;
 		printf("\t/* State set \"%s\" */ {\n", ssp->value);
 		printf("\t/* ss name */           \"%s\",\n", ssp->value);
@@ -329,8 +327,8 @@ static void gen_ss_table(SymTable st, Expr *ss_list)
 static void gen_state_event_mask(Expr *sp, int num_event_flags,
 	bitMask *event_words, int num_event_words)
 {
-	int		n;
-	Expr		*tp;
+	int	n;
+	Expr	*tp;
 
 	for (n = 0; n < num_event_words; n++)
 		event_words[n] = 0;
@@ -374,11 +372,14 @@ static int iter_event_mask_scalar(Expr *ep, Expr *scope, void *parg)
 	assert(vp != 0);
 
 	/* this subroutine handles only the scalar variables and event flags */
+#if 0
 	if (vp->class != VC_SCALAR && vp->class != VC_EVFLAG)
+#endif
+	if (vp->type->tag < V_CHAR || vp->type->tag >= V_POINTER)
 		return FALSE;		/* no children anyway */
 
 	/* event flag? */
-	if (vp->class == VC_EVFLAG)
+	if (vp->type->tag == V_EVFLAG)
 	{
 #ifdef DEBUG
 		report("  iter_event_mask_scalar: evflag: %s, ef_num=%d\n",
@@ -408,8 +409,6 @@ static int iter_event_mask_scalar(Expr *ep, Expr *scope, void *parg)
 	}
 	else
 	{
-		/* otherwise would not be class VC_SCALAR */
-		assert(vp->length1 == 1);
 #ifdef DEBUG
 		report("  iter_event_mask_scalar: var: %s, event bit=%d\n",
 			vp->name, vp->index + cp->index + num_event_flags + 1);
@@ -450,7 +449,7 @@ static int iter_event_mask_array(Expr *ep, Expr *scope, void *parg)
 	assert(vp != 0);
 
 	/* this subroutine handles only the array variables */
-	if (vp->class != VC_ARRAY1 && vp->class != VC_ARRAY2 && vp->class != VC_ARRAYP)
+	if (vp->type->tag != V_ARRAY)
 		return TRUE;
 
 	if (vp->assign == M_NONE)
@@ -469,13 +468,15 @@ static int iter_event_mask_array(Expr *ep, Expr *scope, void *parg)
 	}
 	else
 	{
+		unsigned length1 = type_array_length1(vp->type);
+
 		assert(vp->assign == M_MULTI);
 		/* an array variable subscripted with a constant */
 		if (e_ix && e_ix->type == E_CONST)
 		{
 			uint ix;
 
-			if (!strtoui(e_ix->value, vp->length1, &ix))
+			if (!strtoui(e_ix->value, length1, &ix))
 			{
 				error_at_expr(e_ix,
 					"subscript in '%s[%s]' out of range\n",
@@ -495,7 +496,7 @@ static int iter_event_mask_array(Expr *ep, Expr *scope, void *parg)
 		else if (e_ix)	/* subscript is an expression */
 		{
 			/* must descend for the array variable (see below) and
-		   	   possible array vars inside subscript expression */
+			   possible array vars inside subscript expression */
 			return TRUE;
 		}
 		else /* no subscript */
@@ -505,9 +506,9 @@ static int iter_event_mask_array(Expr *ep, Expr *scope, void *parg)
 #ifdef DEBUG
 			report("  iter_event_mask_array: %s, event bits=%d..%d\n",
 				vp->name, vp->index + num_event_flags + 1,
-				vp->index + num_event_flags + vp->length1);
+				vp->index + num_event_flags + length1);
 #endif
-			for (ix = 0; ix < vp->length1; ix++)
+			for (ix = 0; ix < length1; ix++)
 			{
 				bitSet(event_words, vp->index + ix + num_event_flags + 1);
 			}
diff --git a/src/snc/parse.c b/src/snc/parse.c
index 86fca89d..c720b901 100644
--- a/src/snc/parse.c
+++ b/src/snc/parse.c
@@ -23,62 +23,6 @@
 #include "parse.h"
 #include "snc_main.h"
 
-/* Parsing a variable declaration */
-Expr *decl(
-	int	type,		/* variable type (e.g. V_FLOAT) */
-	int	class,		/* variable class (e.g. VC_ARRAY) */
-	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) */
-	Expr	*init		/* initial value or NULL */
-)
-{
-	Expr	*ep;
-	Var	*vp;
-	int	length1 = 1, length2 = 1;
-
-	if (s_length1 != NULL)
-	{
-		length1 = atoi(s_length1);
-		if (length1 <= 0) {
-			error_at(var.file, var.line,
-				"invalid array size (must be >= 1)\n");
-			length1 = 1;
-		}
-	}
-	if (s_length2 != NULL)
-	{
-		length2 = atoi(s_length2);
-		if (length2 <= 0) {
-			error_at(var.file, var.line,
-				"invalid array size (must be >= 1)\n");
-			length2 = 1;
-		}
-	}
-	vp = new(Var);
-	vp->name = var.str;
-	vp->class = class;
-	if (class == VC_EVFLAG)
-	{
-		vp->chan.evflag = new(EvFlag);
-	}
-	vp->type = type;
-	vp->length1 = length1;
-	vp->length2 = length2;
-	vp->value = init;
-
-	ep = expr(D_DECL, var, init);
-	ep->extra.e_decl = vp;
-#ifdef	DEBUG
-	report_at_expr(ep, "decl: name=%s, type=%d, class=%d, "
-		"length1=%d, length2=%d, value=%s\n",
-		vp->name, vp->type, vp->class,
-		vp->length1, vp->length2, vp->value);
-#endif	/*DEBUG*/
-	vp->decl = ep;
-	return ep;
-}
-
 /* Expr is the generic syntax tree node */
 Expr *expr(
 	int	type,
diff --git a/src/snc/parse.h b/src/snc/parse.h
index df1fcee3..216f6c0d 100644
--- a/src/snc/parse.h
+++ b/src/snc/parse.h
@@ -20,6 +20,7 @@ Expr *expr(
 	...
 );
 
+#if 0
 Expr *decl(
 	int	type,		/* variable type (e.g. V_FLOAT) */
 	int	class,		/* variable class (e.g. VC_ARRAY) */
@@ -28,6 +29,7 @@ Expr *decl(
 	char	*s_length2,	/* array lth (2nd dim, [n]x[m] arrays only) */
 	Expr	*value		/* initial value or NULL */
 );
+#endif
 
 Expr *opt_defn(
 	Token	name,
@@ -45,4 +47,10 @@ boolean strtoui(
 	uint *pnumber		/* location for result if successful */
 );
 
+Expr *decl_add_base_type(Expr *ds, int tag);
+Expr *decl_add_init(Expr *d, Expr *init);
+Expr *decl_create(Token name);
+Expr *decl_postfix_array(Expr *d, char *s);
+Expr *decl_prefix_pointer(Expr *d);
+
 #endif	/*INCLparseh*/
diff --git a/src/snc/snl.lem b/src/snc/snl.lem
index 67465f00..6ea7a644 100644
--- a/src/snc/snl.lem
+++ b/src/snc/snl.lem
@@ -101,9 +101,7 @@ global_defn(p) ::= assign(x).		{ p = x; }
 global_defn(p) ::= monitor(x).		{ p = x; }
 global_defn(p) ::= sync(x).		{ p = x; }
 global_defn(p) ::= syncq(x).		{ p = x; }
-global_defn(p) ::= decl(x).		{ p = x; }
-global_defn(p) ::= evflag_decl(x).	{ p = x; }
-global_defn(p) ::= foreign_decl(x).	{ p = x; }
+global_defn(p) ::= declaration(x).	{ p = x; }
 global_defn(p) ::= option(x).		{ p = x; }
 global_defn(p) ::= c_code(x).		{ p = x; }
 
@@ -148,24 +146,27 @@ opt_subscript(p) ::= .			{ p = 0; }
 %type subscript {Token}
 subscript(p) ::= LBRACKET INTCON(n) RBRACKET. { p = n; }
 
-foreign_decl(p) ::= DECLARE NAME(v) SEMICOLON.
-			{ p = decl(V_NONE,   VC_FOREIGN, v, 0, 0, 0); }
-
-evflag_decl(p) ::= EVFLAG NAME(v) SEMICOLON.
-			{ p = decl(V_NONE, VC_EVFLAG, v, 0, 0, 0); }
-
-decl(p) ::= type(t) NAME(v) SEMICOLON.
-			{ p = decl(t, VC_SCALAR,  v, 0,  0,  0); }
-decl(p) ::= type(t) NAME(v) EQUAL expr(x) SEMICOLON.
-			{ p = decl(t, VC_SCALAR,  v, 0,  0, x); }
-decl(p) ::= type(t) NAME(v) subscript(s) SEMICOLON.
-			{ 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.str, s2.str, 0); }
-decl(p) ::= type(t) ASTERISK NAME(v) SEMICOLON.
-			{ 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.str,  0,  0); }
+// Declarations
+
+declaration(p) ::= type(t) init_declarators(ds) SEMICOLON.
+						{ p = decl_add_base_type(ds, t); }
+
+init_declarators(p) ::= init_declarator(x).	{ p = x; }
+init_declarators(p) ::= init_declarators(xs) COMMA init_declarator(x).
+						{ p = link_expr(xs, x); }
+
+init_declarator(p) ::= declarator(x).		{ p = decl_add_init(x, 0); }
+init_declarator(p) ::= declarator(x) EQUAL expr(i).
+						{ p = decl_add_init(x, i); }
+
+declarator(p) ::= ASTERISK declarator(x).	{ p = decl_prefix_pointer(x); }
+declarator(p) ::= direct_declarator(x).		{ p = x; }
+
+direct_declarator(p) ::= NAME(n).		{ p = decl_create(n); }
+direct_declarator(p) ::= LPAREN declarator(x) RPAREN.
+						{ p = x; }
+direct_declarator(p) ::= direct_declarator(x) subscript(s).
+						{ p = decl_postfix_array(x, s.str); }
 
 %type type {int}
 type(p) ::= CHAR.				{ p = V_CHAR;	}
@@ -179,6 +180,10 @@ type(p) ::= UNSIGNED LONG.			{ p = V_ULONG;	}
 type(p) ::= FLOAT.				{ p = V_FLOAT;	}
 type(p) ::= DOUBLE.				{ p = V_DOUBLE;	}
 type(p) ::= STRING.				{ p = V_STRING;	}
+type(p) ::= EVFLAG.				{ p = V_EVFLAG;	}
+type(p) ::= DECLARE.				{ p = V_NONE;	}
+
+// Option spec
 
 option(p) ::= OPTION option_value(v) NAME(n) SEMICOLON.
 						{ p = opt_defn(n, v); }
@@ -189,12 +194,6 @@ option_value(p) ::= SUB(t).			{ p = t; }
 
 // State sets and states
 
-//global_entry_code(p) ::= ENTRY block(xs).	{ p = xs.right; }
-//global_entry_code(p) ::= .			{ p = 0; }
-
-//global_exit_code(p) ::= EXIT block(xs).		{ p = xs.right; }
-//global_exit_code(p) ::= .			{ p = 0; }
-
 state_sets(p) ::= state_sets(xs) state_set(x).	{ p = link_expr(xs, x); }
 state_sets(p) ::= state_set(x).			{ p = x; }
 
@@ -210,7 +209,7 @@ ss_defn(p) ::= assign(x).			{ p = x; }
 ss_defn(p) ::= monitor(x).			{ p = x; }
 ss_defn(p) ::= sync(x).				{ p = x; }
 ss_defn(p) ::= syncq(x).			{ p = x; }
-ss_defn(p) ::= decl(x).				{ p = x; }
+ss_defn(p) ::= declaration(x).			{ p = x; }
 
 states(p) ::= states(xs) state(x).		{ p = link_expr(xs, x); }
 states(p) ::= state(x).				{ p = x; }
@@ -231,7 +230,7 @@ state_defn(p) ::= assign(x).			{ p = x; }
 state_defn(p) ::= monitor(x).			{ p = x; }
 state_defn(p) ::= sync(x).			{ p = x; }
 state_defn(p) ::= syncq(x).			{ p = x; }
-state_defn(p) ::= decl(x).			{ p = x; }
+state_defn(p) ::= declaration(x).		{ p = x; }
 state_defn(p) ::= option(x).			{ p = x; }
 
 entry(p) ::= ENTRY(t) block(b).			{ p = expr(D_ENTRY, t, b.left, b.right); }
@@ -258,7 +257,7 @@ block_defns(p) ::= block_defns(ds) block_defn(d). {
 }
 block_defns(p) ::= .				{ p = 0; }
 
-block_defn(p) ::= decl(x).			{ p = x; }
+block_defn(p) ::= declaration(x).		{ p = x; }
 block_defn(p) ::= c_code(x).			{ p = x; }
 
 // Statements
diff --git a/src/snc/types.h b/src/snc/types.h
index 8b41124b..d44aa557 100644
--- a/src/snc/types.h
+++ b/src/snc/types.h
@@ -14,8 +14,12 @@
 
 #include <epicsVersion.h>
 
+#include "var_types.h"
+
 #ifndef	TRUE
 #define	TRUE 1
+#endif
+#ifndef	FALSE
 #define	FALSE 0
 #endif
 
@@ -140,12 +144,10 @@ struct variable				/* Variable or function definition */
 	Var	*next;			/* link to next variable in list */
 	char	*name;			/* variable name */
 	Expr	*value;			/* initial value or NULL */
-	uint	type:4;			/* var type, one of enum var_type */
-	uint	class:4;		/* var class, one of enum var_class */
-	uint	length1;		/* 1st dim. array lth (default=1) */
-	uint	length2;		/* 2nd dim. array lth (default=1) */
-	Expr	*decl;			/* declaration of this variable (or NULL) */
-	Expr	*scope;			/* declaration of this variable (or NULL) */
+	Expr	*decl;			/* declaration of this variable
+					   (or NULL if not declared) */
+	Expr	*scope;			/* scope of this variable */
+	Type	*type;			/* type of this variable */
 	/* channel stuff */
 	uint	assign:2;		/* assigned: one of enum multiplicity */
 	uint	monitor:2;		/* monitored: one of enum multiplicity */
@@ -161,7 +163,7 @@ struct variable				/* Variable or function definition */
 /* Laws (Invariants):
 L1: sync == M_MULTI || syncq == M_MULTI => monitor == M_MULTI => assign == M_MULTI
 L2: assign == M_NONE => monitor == M_NONE => sync == M_NONE && syncq == M_NONE
-L3: assign == M_MULTI => class == VC_ARRAY1 || class == VC_ARRAY2
+L3: assign == M_MULTI => type->tag == V_ARRAY
 L4: sync == M_SINGLE || syncq == M_SINGLE => monitor == M_SINGLE
 */
 
@@ -257,35 +259,6 @@ struct program
 
 #define expr_type_name(e)	expr_type_info[(e)->type].name
 
-/* Variable (element) types */
-enum var_type
-{
-	V_NONE,			/* no base type */
-	V_CHAR,			/* char */
-	V_SHORT,		/* short */
-	V_INT,			/* int */
-	V_LONG,			/* long */
-	V_FLOAT,		/* float */
-	V_DOUBLE,		/* double */
-	V_STRING,		/* string (array of 40 char) */
-	V_UCHAR,		/* unsigned char */
-	V_USHORT,		/* unsigned short */
-	V_UINT,			/* unsigned int */
-	V_ULONG			/* unsigned long */
-};
-
-/* Variable classes */
-enum var_class
-{
-	VC_SCALAR,		/* scalar variable */
-	VC_ARRAY1,		/* 1-dimensional array */
-	VC_ARRAY2,		/* 2-dimensional array */
-	VC_POINTER,		/* pointer */
-	VC_ARRAYP,		/* array of pointers */
-	VC_EVFLAG,		/* event flag */
-	VC_FOREIGN		/* C-code variable, unknown type */
-};
-
 /* for channel assign, monitor, sync, and syncq */
 enum multiplicity
 {
diff --git a/src/snc/var_types.c b/src/snc/var_types.c
new file mode 100644
index 00000000..9c8411e3
--- /dev/null
+++ b/src/snc/var_types.c
@@ -0,0 +1,187 @@
+/* Copyright 2010 Helmholtz-Zentrum Berlin f. Materialien und Energie GmbH
+   (see file Copyright.HZB included in this distribution)
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "snc_main.h"
+#include "parse.h"
+
+/* #define DEBUG */
+
+static void retrofit_base_type(unsigned tag, Type *t, Expr *d)
+{
+    assert(tag < V_POINTER);        /* pre-condition */
+    assert(t != NULL);
+    assert(t->tag >= V_POINTER);    /* pre-condition */
+    switch (t->tag) {
+    case V_ARRAY:
+        if (tag == V_NONE) {
+            error_at_expr(d, "cannot declare array of foreign variables\n");
+            break;
+        }
+        if (tag == V_EVFLAG) {
+            error_at_expr(d, "cannot declare array of event flags\n");
+            break;
+        }
+        if (t->val.array.elem_type == NULL) {
+            t->val.array.elem_type  = new(Type);
+            t->val.array.elem_type->tag = tag;
+        } else {
+            retrofit_base_type(tag, t->val.array.elem_type, d);
+        }
+        break;
+    case V_POINTER:
+        if (tag == V_NONE) {
+            error_at_expr(d, "cannot declare pointer to foreign variable\n");
+            break;
+        }
+        if (tag == V_EVFLAG) {
+            error_at_expr(d, "cannot declare pointer to event flag\n");
+            break;
+        }
+        if (t->val.pointer.value_type == NULL) {
+            t->val.pointer.value_type  = new(Type);
+            t->val.pointer.value_type->tag = tag;
+        } else {
+            retrofit_base_type(tag, t->val.pointer.value_type, d);
+        }
+        break;
+    default:
+        break;                      /* dummy to pacify compiler */
+    }
+}
+
+Expr *decl_add_base_type(Expr *ds, int tag)
+{
+    Expr *d;
+
+    foreach(d, ds) {
+        Var *var = d->extra.e_decl;
+
+        assert(d->type == D_DECL);      /* pre-condition */
+        if (var->type == NULL) {
+            var->type = new(Type);
+            var->type->tag = tag;
+        } else {
+            retrofit_base_type(tag, var->type, d);
+        }
+        if (tag == V_EVFLAG)
+            var->chan.evflag = new(EvFlag);
+#ifdef DEBUG
+        fprintf(stderr, "base_type(%d) for name = %s\n", tag, var->name);
+#endif
+    }
+    return ds;
+}
+
+Expr *decl_add_init(Expr *d, Expr *init)
+{
+    assert(d->type == D_DECL);          /* pre-condition */
+    d->extra.e_decl->value = init;
+    return d;
+}
+
+Expr *decl_create(Token name)
+{
+    Expr *d = expr(D_DECL, name, 0);
+    Var *var = new(Var);
+
+#ifdef DEBUG
+    fprintf(stderr, "name(%s)\n", name.str);
+#endif
+    assert(d->type == D_DECL);          /* expr() post-condition */
+    var->name = name.str;
+    d->extra.e_decl = var;
+    var->decl = d;
+    return d;
+}
+
+Expr *decl_postfix_array(Expr *d, char *s)
+{
+    int l = atoi(s);
+    Type *t = new(Type);
+
+#ifdef DEBUG
+    fprintf(stderr, "array\n");
+#endif
+    assert(d->type == D_DECL);          /* pre-condition */
+    if (l <= 0) {
+        error_at_expr(d, "invalid array size (must be >= 1)\n");
+        l = 1;
+    }
+    t->tag = V_ARRAY;
+    t->val.array.num_elems = l;
+    t->val.array.elem_type = d->extra.e_decl->type;
+    d->extra.e_decl->type = t;
+    return d;
+}
+
+Expr *decl_prefix_pointer(Expr *d)
+{
+    Type *t = new(Type);
+
+#ifdef DEBUG
+    fprintf(stderr, "pointer\n");
+#endif
+    assert(d->type == D_DECL);          /* pre-condition */
+    t->tag = V_POINTER;
+    t->val.pointer.value_type = d->extra.e_decl->type;
+    d->extra.e_decl->type = t;
+    return d;
+}
+
+unsigned type_base_type(Type *t)
+{
+    switch (t->tag) {
+    case V_ARRAY:
+        return type_base_type(t->val.array.elem_type);
+    case V_POINTER:
+        return type_base_type(t->val.pointer.value_type);
+    default:
+        return t->tag;
+    }
+}
+
+unsigned type_array_length1(Type *t)
+{
+    switch (t->tag) {
+    case V_ARRAY:
+        return t->val.array.num_elems;
+    default:
+        return 1;
+    }
+}
+
+unsigned type_array_length2(Type *t)
+{
+    switch (t->tag) {
+    case V_ARRAY:
+        return type_array_length1(t->val.array.elem_type);
+    default:
+        return 1;
+    }
+}
+
+static unsigned type_assignable_array(Type *t, int depth)
+{
+    if (depth > 2)
+        return FALSE;
+    switch (t->tag) {
+    case V_NONE:
+    case V_EVFLAG:
+    case V_POINTER:
+        return FALSE;
+    case V_ARRAY:
+        return type_assignable_array(t->val.array.elem_type, depth + 1);
+    default:
+        return TRUE;
+    }
+}
+
+unsigned type_assignable(Type *t)
+{
+    return type_assignable_array(t, 0);
+}
diff --git a/src/snc/var_types.h b/src/snc/var_types.h
new file mode 100644
index 00000000..943faca7
--- /dev/null
+++ b/src/snc/var_types.h
@@ -0,0 +1,56 @@
+/* Copyright 2010 Helmholtz-Zentrum Berlin f. Materialien und Energie GmbH
+   (see file Copyright.HZB included in this distribution)
+*/
+#ifndef INCLvar_typesh
+#define INCLvar_typesh
+
+enum type_tag {
+    V_NONE,
+    V_EVFLAG,
+    V_CHAR,
+    V_UCHAR,
+    V_SHORT,
+    V_USHORT,
+    V_INT,
+    V_UINT,
+    V_LONG,
+    V_ULONG,
+    V_FLOAT,
+    V_DOUBLE,
+    V_STRING,
+    V_ENUM,
+    V_POINTER,
+    V_ARRAY,
+};
+
+struct array_type {
+    unsigned    num_elems;
+    struct type *elem_type;
+};
+
+struct pointer_type {
+    struct type *value_type;
+};
+
+struct enum_type {
+    unsigned    num_names;
+    char        **names;
+};
+
+typedef struct type Type;
+
+struct type {
+    enum type_tag tag;
+    union {
+        struct pointer_type pointer;
+        struct array_type   array;
+        struct enum_type    enumeration;
+    } val;
+};
+
+unsigned type_base_type(Type *t);
+unsigned type_array_length1(Type *t);
+unsigned type_array_length2(Type *t);
+unsigned type_assignable(Type *t);
+
+#endif /*INCLvar_typesh */
-- 
GitLab