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