From e9cd900501eab60e4ad5751517de5de7277836f7 Mon Sep 17 00:00:00 2001 From: "benjamin.franksen" <benjamin.franksen@helmholtz-berlin.de> Date: Mon, 11 Jun 2012 09:48:22 +0000 Subject: [PATCH] snc: added foreign types and type casts --- src/snc/analysis.c | 32 ++++----- src/snc/analysis.h | 4 +- src/snc/expr.h | 5 +- src/snc/gen_code.c | 2 +- src/snc/gen_ss_code.c | 20 ++++-- src/snc/gen_tables.c | 46 ++++++------ src/snc/snl.lem | 92 ++++++++++++++++++------ src/snc/snl.re | 4 ++ src/snc/types.h | 58 ++++++++------- src/snc/var_types.c | 159 +++++++++++++++++++++++++++--------------- src/snc/var_types.h | 86 ++++++++++++++++++++--- 11 files changed, 346 insertions(+), 162 deletions(-) diff --git a/src/snc/analysis.c b/src/snc/analysis.c index f999d393..399787c7 100644 --- a/src/snc/analysis.c +++ b/src/snc/analysis.c @@ -295,11 +295,12 @@ 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) + if (scope->type != D_PROG && + (vp->type->tag == T_NONE || vp->type->tag == T_EVFLAG)) { error_at_expr(defn, "%s can only be declared at the top-level\n", - vp->type->tag == V_NONE ? "foreign variables" + vp->type->tag == T_NONE ? "foreign variables" : "event flags"); } @@ -462,7 +463,7 @@ static void assign_subscript( report("assign %s[%s] to '%s';\n", vp->name, subscr->value, pv_name); #endif - if (vp->type->tag != V_ARRAY) /* establish L3 */ + if (vp->type->tag != T_ARRAY) /* establish L3 */ { error_at_expr(defn, "variable '%s' is not an array\n", vp->name); return; @@ -502,7 +503,7 @@ static void assign_multi( report("assign %s to {", vp->name); #endif - if (vp->type->tag != V_ARRAY) /* establish L3 */ + if (vp->type->tag != T_ARRAY) /* establish L3 */ { error_at_expr(defn, "variable '%s' is not an array\n", vp->name); return; @@ -581,7 +582,7 @@ static void monitor_elem(Expr *defn, Var *vp, Expr *subscr) report("monitor %s[%s];\n", vp->name, subscr->value); #endif - if (vp->type->tag != V_ARRAY) /* establish L3 */ + if (vp->type->tag != T_ARRAY) /* establish L3 */ { error_at_expr(defn, "variable '%s' is not an array\n", vp->name); return; @@ -720,7 +721,7 @@ 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->type->tag != V_ARRAY) /* establish L3 */ + if (vp->type->tag != T_ARRAY) /* establish L3 */ { error_at_expr(defn, "variable '%s' is not an array\n", vp->name); return; @@ -795,7 +796,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->type->tag != V_EVFLAG) + if (evp->type->tag != T_EVFLAG) { error_at_expr(defn, "variable '%s' is not a event flag\n", ef_name); return; @@ -861,7 +862,7 @@ static void syncq_elem(Expr *defn, Var *vp, Expr *subscr, SyncQ *qp) assert(vp->syncq != M_SINGLE); /* call */ - if (vp->type->tag != V_ARRAY) /* establish L3 */ + if (vp->type->tag != T_ARRAY) /* establish L3 */ { error_at_expr(defn, "variable '%s' is not an array\n", vp->name); return; @@ -950,7 +951,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->type->tag != V_EVFLAG) + if (evp->type->tag != T_EVFLAG) { error_at_expr(defn, "variable '%s' is not a event flag\n", ef_name); return; @@ -1070,7 +1071,7 @@ Var *find_var(SymTable st, char *name, Expr *scope) /* Connect a variable in an expression (E_VAR) to the Var structure. If there is no such structure, e.g. because the variable has not been - declared, then allocate one, assign type V_NONE, and assign the + declared, then allocate one, assign type T_NONE, and assign the top-level scope for the variable. */ static int connect_variable(Expr *ep, Expr *scope, void *parg) { @@ -1113,7 +1114,7 @@ static int connect_variable(Expr *ep, Expr *scope, void *parg) vp = new(Var); vp->name = ep->value; vp->type = new(Type); - vp->type->tag = V_NONE; /* undeclared type */ + vp->type->tag = T_NONE; /* undeclared type */ vp->init = 0; /* add this variable to the top-level scope, NOT the current scope */ while (var_list->parent_scope) { @@ -1132,8 +1133,7 @@ static void connect_variables(SymTable st, Expr *scope) #ifdef DEBUG report("**begin** connect_variables\n"); #endif - traverse_expr_tree(scope, 1u<<E_VAR, ~has_sub_expr_mask, - 0, connect_variable, &st); + traverse_expr_tree(scope, 1u<<E_VAR, 0, 0, connect_variable, &st); #ifdef DEBUG report("**end** connect_variables\n"); #endif @@ -1141,8 +1141,8 @@ static void connect_variables(SymTable st, Expr *scope) void traverse_expr_tree( Expr *ep, /* start expression */ - uint call_mask, /* when to call iteratee */ - uint stop_mask, /* when to stop descending */ + TypeMask call_mask, /* when to call iteratee */ + TypeMask stop_mask, /* when to stop descending */ Expr *scope, /* current scope, 0 at top-level */ expr_iter *iteratee, /* function to call */ void *parg /* argument to pass to function */ @@ -1429,7 +1429,7 @@ static uint assign_ef_bits(Expr *scope) /* Assign event flag numbers (starting at 1) */ foreach (vp, var_list->first) { - if (vp->type->tag == V_EVFLAG) + if (vp->type->tag == T_EVFLAG) { vp->chan.evflag->index = ++num_event_flags; } diff --git a/src/snc/analysis.h b/src/snc/analysis.h index 2b981afc..a3718c84 100644 --- a/src/snc/analysis.h +++ b/src/snc/analysis.h @@ -31,8 +31,8 @@ typedef int expr_iter(Expr *ep, Expr *scope, void *parg); void traverse_expr_tree( Expr *ep, /* start expression */ - uint call_mask, /* when to call iteratee */ - uint stop_mask, /* when to stop descending */ + TypeMask call_mask, /* when to call iteratee */ + TypeMask stop_mask, /* when to stop descending */ Expr *scope, /* current scope, 0 at top-level */ expr_iter *iteratee, /* function to call */ void *parg /* argument to pass to function */ diff --git a/src/snc/expr.h b/src/snc/expr.h index c615c0f2..605c812e 100644 --- a/src/snc/expr.h +++ b/src/snc/expr.h @@ -15,6 +15,7 @@ in the file LICENSE that is included with this distribution. #include "types.h" +/* defined in expr.c */ Expr *expr( uint type, /* E_BINOP, E_ASGNOP, etc */ Token tok, /* "==", "+=", var name, constant, etc. */ @@ -37,8 +38,10 @@ uint strtoui( uint *pnumber /* location for result if successful */ ); -Expr *decl_add_base_type(Expr *ds, uint tag); +/* defined in var_types.c */ +Expr *decl_add_base_type(Expr *ds, Type t); Expr *decl_add_init(Expr *d, Expr *init); +Expr *abstract_decl_create(void); Expr *decl_create(Token name); Expr *decl_postfix_array(Expr *d, char *s); Expr *decl_prefix_pointer(Expr *d); diff --git a/src/snc/gen_code.c b/src/snc/gen_code.c index d2a273d2..a1b43207 100644 --- a/src/snc/gen_code.c +++ b/src/snc/gen_code.c @@ -36,7 +36,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->tag == V_NONE); + ep->extra.e_var->type->tag == T_NONE); return TRUE; /* there are no children anyway */ } diff --git a/src/snc/gen_ss_code.c b/src/snc/gen_ss_code.c index 070059c9..c13da734 100644 --- a/src/snc/gen_ss_code.c +++ b/src/snc/gen_ss_code.c @@ -150,7 +150,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->tag != V_NONE) + if (vp->decl && vp->type->tag != T_NONE) { gen_line_marker(vp->decl); indent(level); @@ -177,7 +177,7 @@ static void gen_type_default(Type *type) case V_STRING: printf("\"\""); break; - case V_ARRAY: + case T_ARRAY: printf("{"); for (n=0; n<type->val.array.num_elems; n++) { @@ -368,13 +368,13 @@ static void gen_var_access(Var *vp) report("var_access: %s, scope=(%s,%s)\n", vp->name, expr_type_name(vp->scope), vp->scope->value); #endif - assert((1u<<vp->scope->type) & scope_mask); + assert(is_scope(vp->scope)); - if (vp->type->tag == V_EVFLAG) + if (vp->type->tag == T_EVFLAG) { printf("%d/*%s*/", vp->chan.evflag->index, vp->name); } - else if (vp->type->tag == V_NONE) + else if (vp->type->tag == T_NONE) { printf("%s", vp->name); } @@ -544,6 +544,14 @@ static void gen_expr( gen_expr(context, ep->paren_expr, 0); printf(")"); break; + case E_CAST: + printf("("); + /* gen_type_expr(ep->cast_type); */ + assert(ep->cast_type->type == D_DECL); + gen_var_decl(ep->cast_type->extra.e_decl); + printf(")"); + gen_expr(context, ep->cast_operand, 0); + break; case E_PRE: printf("%s", ep->value); gen_expr(context, ep->pre_operand, 0); @@ -642,7 +650,7 @@ static void gen_ef_arg( } vp = ap->extra.e_var; assert(vp->type); - if (vp->type->tag != V_EVFLAG) + if (vp->type->tag != T_EVFLAG) { error_at_expr(ap, "argument to built-in function %s must be an event flag\n", func_name); diff --git a/src/snc/gen_tables.c b/src/snc/gen_tables.c index 7f8f63de..e53e2c91 100644 --- a/src/snc/gen_tables.c +++ b/src/snc/gen_tables.c @@ -104,26 +104,30 @@ static void gen_channel(Chan *cp, uint num_event_flags, int opt_reent) Var *vp = cp->var; char elem_str[20] = ""; uint ef_num; - enum type_tag type = type_base_type(vp->type); + Type *basetype = base_type(vp->type); - if (type == V_LONG || type == V_ULONG) + if (basetype->tag == T_PRIM) { - printf( + enum prim_type_tag type = basetype->val.prim; + if (type == V_LONG || type == V_ULONG) + { + printf( "#if LONG_MAX > 0x7fffffffL\n" - ); - gen_line_marker(vp->decl); - printf( + ); + gen_line_marker(vp->decl); + printf( "#error variable '" - ); - gen_var_decl(vp); - printf("'" + ); + gen_var_decl(vp); + printf("'" " cannot be assigned to a PV (on the chosen target system)\\\n" " because Channel Access does not support integral types longer than 4 bytes.\\\n" " You can use '%s' instead, or the fixed size type '%s'.\n" "#endif\n", - type == V_LONG ? "int" : "unsigned int", - type == V_LONG ? "int32_t" : "uint32_t" - ); + type == V_LONG ? "int" : "unsigned int", + type == V_LONG ? "int32_t" : "uint32_t" + ); + } } if (vp->assign == M_MULTI) @@ -155,7 +159,8 @@ static void gen_channel(Chan *cp, uint num_event_flags, int opt_reent) /* variable name with optional elem num */ printf("\"%s%s\", ", vp->name, elem_str); /* variable type */ - printf("\"%s\", ", type_name(type_base_type(vp->type))); + assert(base_type(vp->type)->tag == T_PRIM); + printf("\"%s\", ", prim_type_name[base_type(vp->type)->val.prim]); /* count, for requests */ printf("%d, ", cp->count); /* event number */ @@ -380,12 +385,7 @@ static int iter_event_mask_scalar(Expr *ep, Expr *scope, void *parg) vp = ep->extra.e_var; assert(vp != 0); - /* this subroutine handles only the scalar variables and event flags */ - if (vp->type->tag < V_EVFLAG || vp->type->tag >= V_POINTER) - return FALSE; /* no children anyway */ - - /* event flag? */ - if (vp->type->tag == V_EVFLAG) + if (vp->type->tag == T_EVFLAG) { #ifdef DEBUG report(" iter_event_mask_scalar: evflag: %s, ef_num=%d\n", @@ -394,6 +394,10 @@ static int iter_event_mask_scalar(Expr *ep, Expr *scope, void *parg) bitSet(event_words, vp->chan.evflag->index); return FALSE; /* no children anyway */ } + if (vp->type->tag != T_PRIM) + return FALSE; /* no children anyway */ + + assert(vp->type->tag == T_PRIM); /* if not associated with channel, return */ if (vp->assign == M_NONE) @@ -441,9 +445,11 @@ static int iter_event_mask_array(Expr *ep, Expr *scope, void *parg) assert(vp != 0); /* this subroutine handles only the array variables */ - if (vp->type->tag != V_ARRAY) + if (vp->type->tag != T_ARRAY) return TRUE; + assert(vp->type->tag == T_ARRAY); + if (vp->assign == M_NONE) { return FALSE; diff --git a/src/snc/snl.lem b/src/snc/snl.lem index 3142f7db..190f12df 100644 --- a/src/snc/snl.lem +++ b/src/snc/snl.lem @@ -80,6 +80,7 @@ in the file LICENSE that is included with this distribution. %left LSHIFT RSHIFT. %left ADD SUB. %left ASTERISK SLASH MOD. +%right CAST. %right NOT INCR DECR PRE. %left LBRACKET RBRACKET POINTER PERIOD POST. // LPAREN RPAREN not listed as we do not support indirect calls. */ @@ -176,8 +177,10 @@ subscript(p) ::= LBRACKET INTCON(n) RBRACKET. { p = n; } // Declarations -declaration(p) ::= type(t) init_declarators(ds) SEMICOLON. +declaration(p) ::= basetype(t) init_declarators(ds) SEMICOLON. { p = decl_add_base_type(ds, t); } +declaration(p) ::= FOREIGN init_declarators(ds) SEMICOLON. + { p = decl_add_base_type(ds, mk_no_type()); } init_declarators(p) ::= init_declarator(x). { p = x; } init_declarators(p) ::= init_declarators(xs) COMMA init_declarator(x). @@ -198,6 +201,8 @@ direct_declarator(p) ::= direct_declarator(x) subscript(s). // Initializer // Note: comma operator not allowed in 'expr'. +init_expr(p) ::= LPAREN(tc) type_expr(c) RPAREN LBRACE(tx) init_exprs(x) RBRACE. + { p = expr(E_CAST, tc, c, expr(E_INIT, tx, x)); } init_expr(p) ::= LBRACE(t) init_exprs(x) RBRACE.{ p = expr(E_INIT, t, x); } init_expr(p) ::= expr(x). { p = x; } @@ -205,28 +210,66 @@ init_exprs(p) ::= init_exprs(xs) COMMA init_expr(x). { p = link_expr(xs, x); } init_exprs(p) ::= init_expr(x). { p = x; } init_exprs(p) ::= . { p = 0; } -%type type {int} -type(p) ::= CHAR. { p = V_CHAR; } -type(p) ::= SHORT. { p = V_SHORT; } -type(p) ::= INT. { p = V_INT; } -type(p) ::= LONG. { p = V_LONG; } -type(p) ::= UNSIGNED CHAR. { p = V_UCHAR; } -type(p) ::= UNSIGNED SHORT. { p = V_USHORT; } -type(p) ::= UNSIGNED INT. { p = V_UINT; } -type(p) ::= UNSIGNED LONG. { p = V_ULONG; } - -type(p) ::= INT8T. { p = V_INT8T; } -type(p) ::= UINT8T. { p = V_UINT8T; } -type(p) ::= INT16T. { p = V_INT16T; } -type(p) ::= UINT16T. { p = V_UINT16T;} -type(p) ::= INT32T. { p = V_INT32T; } -type(p) ::= UINT32T. { p = V_UINT32T;} - -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) ::= FOREIGN. { p = V_NONE; } +// Type expressions + +// C standard calls this specifier-qualifier-list +%type basetype {Type} +basetype(p) ::= CHAR. { p = mk_prim_type(V_CHAR); } +basetype(p) ::= SHORT. { p = mk_prim_type(V_SHORT); } +basetype(p) ::= INT. { p = mk_prim_type(V_INT); } +basetype(p) ::= LONG. { p = mk_prim_type(V_LONG); } +basetype(p) ::= UNSIGNED CHAR. { p = mk_prim_type(V_UCHAR); } +basetype(p) ::= UNSIGNED SHORT. { p = mk_prim_type(V_USHORT); } +basetype(p) ::= UNSIGNED INT. { p = mk_prim_type(V_UINT); } +basetype(p) ::= UNSIGNED LONG. { p = mk_prim_type(V_ULONG); } + +basetype(p) ::= INT8T. { p = mk_prim_type(V_INT8T); } +basetype(p) ::= UINT8T. { p = mk_prim_type(V_UINT8T); } +basetype(p) ::= INT16T. { p = mk_prim_type(V_INT16T); } +basetype(p) ::= UINT16T. { p = mk_prim_type(V_UINT16T); } +basetype(p) ::= INT32T. { p = mk_prim_type(V_INT32T); } +basetype(p) ::= UINT32T. { p = mk_prim_type(V_UINT32T); } + +basetype(p) ::= FLOAT. { p = mk_prim_type(V_FLOAT); } +basetype(p) ::= DOUBLE. { p = mk_prim_type(V_DOUBLE); } +basetype(p) ::= STRING. { p = mk_prim_type(V_STRING); } +basetype(p) ::= EVFLAG. { p = mk_ef_type(); } + +basetype(p) ::= ENUM NAME(x). { p = mk_foreign_type(F_ENUM, x.str); } +basetype(p) ::= STRUCT NAME(x). { p = mk_foreign_type(F_STRUCT, x.str); } +basetype(p) ::= UNION NAME(x). { p = mk_foreign_type(F_UNION, x.str); } +basetype(p) ::= TYPENAME NAME(x). { p = mk_foreign_type(F_TYPENAME, x.str); } + +type_expr(p) ::= basetype(t) opt_abstract_declarator(d). { + p = decl_add_base_type(d, t); +} + +opt_abstract_declarator(p) ::= . { + p = abstract_decl_create(); +} +opt_abstract_declarator(p) ::= abstract_declarator(x). { + p = x; +} + +abstract_declarator(p) ::= ASTERISK. { + p = decl_prefix_pointer(abstract_decl_create()); +} +abstract_declarator(p) ::= ASTERISK direct_abstract_declarator(x). { + p = decl_prefix_pointer(x); +} +abstract_declarator(p) ::= direct_abstract_declarator(x). { + p = x; +} + +direct_abstract_declarator(p) ::= LPAREN abstract_declarator(x) RPAREN. { + p = x; +} +direct_abstract_declarator(p) ::= direct_abstract_declarator(x) subscript(s). { + p = decl_postfix_array(x, s.str); +} +direct_abstract_declarator(p) ::= subscript(s). { + p = decl_postfix_array(abstract_decl_create(), s.str); +} // Option spec @@ -372,6 +415,9 @@ expr(p) ::= TILDE(t) expr(x). [PRE] { p = expr(E_PRE, t, x); } expr(p) ::= INCR(t) expr(x). [PRE] { p = expr(E_PRE, t, x); } expr(p) ::= DECR(t) expr(x). [PRE] { p = expr(E_PRE, t, x); } +// Type Cast +expr(p) ::= LPAREN(t) type_expr(c) RPAREN expr(x). [CAST] { p = expr(E_CAST, t, c, x); } + // Binary Operators, left-to-right 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); } diff --git a/src/snc/snl.re b/src/snc/snl.re index 7105ef8d..cb2a7868 100644 --- a/src/snc/snl.re +++ b/src/snc/snl.re @@ -237,6 +237,7 @@ snl: "double" { TYPEWORD(DOUBLE, "double"); } "else" { KEYWORD(ELSE, "else"); } "entry" { KEYWORD(ENTRY, "entry"); } + "enum" { TYPEWORD(ENUM, "enum"); } "evflag" { TYPEWORD(EVFLAG, "evflag"); } "exit" { KEYWORD(EXIT, "exit"); } "float" { TYPEWORD(FLOAT, "float"); } @@ -252,10 +253,13 @@ snl: "ss" { KEYWORD(SS, "ss"); } "state" { KEYWORD(STATE, "state"); } "string" { KEYWORD(STRING, "string"); } + "struct" { TYPEWORD(STRUCT, "struct"); } "syncQ" { KEYWORD(SYNCQ, "syncQ"); } "syncq" { KEYWORD(SYNCQ, "syncq"); } "sync" { KEYWORD(SYNC, "sync"); } "to" { KEYWORD(TO, "to"); } + "typename" { TYPEWORD(TYPENAME, "typename"); } + "union" { TYPEWORD(UNION, "union"); } "unsigned" { TYPEWORD(UNSIGNED, "unsigned"); } "when" { KEYWORD(WHEN, "when"); } "while" { KEYWORD(WHILE, "while"); } diff --git a/src/snc/types.h b/src/snc/types.h index 7d5accb7..2078c272 100644 --- a/src/snc/types.h +++ b/src/snc/types.h @@ -41,6 +41,7 @@ typedef struct sync_queue_list SyncQList; typedef struct var_list VarList; typedef struct expr_pair ExprPair; +typedef unsigned int TypeMask; typedef unsigned int uint; struct sym_table @@ -111,14 +112,14 @@ struct expression /* generic syntax node */ Expr *next; /* list node: next expression */ Expr *last; /* list node: last expression */ Expr **children; /* array of children [left,right,...] */ - uint type; /* expression type (E_XXX) */ + TypeMask type; /* expression type (E_XXX) */ char *value; /* operator or value string */ int line_num; /* originating line number */ const char *src_file; /* originating source file */ union /* extra data, depends on type */ { - Var *e_var; /* variable definiton */ - Var *e_decl; /* variable definiton */ + Var *e_var; /* variable reference */ + Var *e_decl; /* variable declaration */ uint e_delay; /* delay id */ uint e_option; /* option value (1 or 0) */ VarList *e_prog; /* top-level definitions */ @@ -165,7 +166,7 @@ L1c: syncq == M_MULTI => assign == M_MULTI L2a: assign == M_NONE => monitor == M_NONE L2b: assign == M_NONE => sync == M_NONE L2c: assign == M_NONE => syncq == M_NONE -L3: assign == M_MULTI => type->tag == V_ARRAY +L3: assign == M_MULTI => type->tag == T_ARRAY */ struct channel /* channel assignment info */ @@ -235,31 +236,25 @@ struct program /* Generic iteration on lists */ #define foreach(e,l) for (e = l; e != 0; e = e->next) +/* Commonly used sets of expression types */ + /* Expression types that are scopes. By definition, a scope is an expression that allows variable declarations as (immediate) subexpressions. */ -#define scope_mask ( (1u<<D_PROG) | (1u<<D_SS) | (1u<<D_STATE)\ - | (1u<<D_ENTEX) | (1u<<D_WHEN) | (1u<<S_CMPND) ) - +#define scope_mask ( (1u<<D_PROG) | (1u<<D_SS) | (1u<<D_STATE)\ + | (1u<<D_ENTEX) | (1u<<D_WHEN) | (1u<<S_CMPND) ) +/* Whether an expression is a scope */ #define is_scope(e) (((1u<<((e)->type)) & scope_mask) != 0) -/* Expressions types that may have sub-scopes */ -#define has_sub_scope_mask ( (1u<<D_ENTEX) | (1u<<D_PROG) | (1u<<D_SS)\ - | (1u<<D_STATE) | (1u<<D_WHEN) | (1u<<S_CMPND) | (1u<<S_FOR)\ - | (1u<<S_IF) | (1u<<S_STMT) | (1u<<S_WHILE) ) -/* Expressions types that may have sub-expressions */ -#define has_sub_expr_mask ( (1u<<D_DECL) | (1u<<D_ENTEX) | (1u<<D_PROG)\ - | (1u<<D_SS) | (1u<<D_STATE) | (1u<<D_SYNC) | (1u<<D_SYNCQ)\ - | (1u<<D_WHEN) | (1u<<E_BINOP) | (1u<<E_DELAY)\ - | (1u<<E_FUNC) | (1u<<E_INIT) | (1u<<E_PAREN) | (1u<<E_POST)\ - | (1u<<E_PRE) | (1u<<E_SUBSCR) | (1u<<E_TERNOP) | (1u<<E_VAR)\ - | (1u<<S_CHANGE) | (1u<<S_CMPND) | (1u<<S_FOR) | (1u<<S_IF)\ - | (1u<<S_STMT) | (1u<<S_WHILE) ) +/* Expression types that may have sub-scopes */ +#define has_sub_scope_mask ( (1u<<D_ENTEX) | (1u<<D_PROG) | (1u<<D_SS)\ + | (1u<<D_STATE) | (1u<<D_WHEN) | (1u<<S_CMPND) | (1u<<S_FOR)\ + | (1u<<S_IF) | (1u<<S_STMT) | (1u<<S_WHILE) ) /* Expression types that are actually expressions i.e. no definitions or statements. These are the ones that start with E_. */ -#define expr_mask ( (1u<<E_BINOP) | (1u<<E_CONST) | (1u<<E_DELAY)\ +#define expr_mask ( (1u<<E_BINOP) | (1u<<E_CAST) | (1u<<E_CONST) | (1u<<E_DELAY)\ | (1u<<E_FUNC) | (1u<<E_INIT)\ - | (1u<<E_PAREN) | (1u<<E_POST) | (1u<<E_PRE) | (1u<<E_STRING)\ - | (1u<<E_SUBSCR) | (1u<<E_TERNOP) | (1u<<E_VAR) | (1u<<T_TEXT) ) + | (1u<<E_PAREN) | (1u<<E_POST) | (1u<<E_PRE) | (1u<<E_STRING)\ + | (1u<<E_SUBSCR) | (1u<<E_TERNOP) | (1u<<E_VAR) | (1u<<T_TEXT) ) #define expr_type_name(e) expr_type_info[(e)->type].name @@ -287,6 +282,7 @@ enum expr_type /* description [child expressions...] */ D_WHEN, /* when statement [cond,defns,stmts] */ E_BINOP, /* binary operator [left,right] */ + E_CAST, /* type cast [operand] */ E_CONST, /* numeric (inkl. character) constant [] */ E_DELAY, /* delay function call [args] */ E_FUNC, /* function call [args] */ @@ -318,6 +314,8 @@ enum expr_type /* description [child expressions...] */ #define assign_pvs children[1] #define binop_left children[0] #define binop_right children[1] +#define cast_type children[0] +#define cast_operand children[1] #define cmpnd_defns children[0] #define cmpnd_stmts children[1] #define decl_init children[0] @@ -366,6 +364,14 @@ enum expr_type /* description [child expressions...] */ #define while_cond children[0] #define while_stmt children[1] +/* Accessors for var_lists (only for scopes) */ +#define prog_var_list extra.e_prog +#define ss_var_list extra.e_ss->var_list +#define state_var_list extra.e_state->var_list +#define when_var_list extra.e_when->var_list +#define entex_var_list extra.e_entex; +#define cmpnd_var_list extra.e_cmpnd; + #ifndef expr_type_GLOBAL extern #endif @@ -389,6 +395,7 @@ expr_type_info[] { "D_SYNCQ", 3 }, { "D_WHEN", 3 }, { "E_BINOP", 2 }, + { "E_CAST", 2 }, { "E_CONST", 0 }, { "E_DELAY", 1 }, { "E_FUNC", 1 }, @@ -407,10 +414,9 @@ expr_type_info[] { "S_JUMP", 0 }, { "S_STMT", 1 }, { "S_WHILE", 2 }, - { "T_TEXT", 0 } -}; -#else -; + { "T_TEXT", 0 }, +} #endif +; #endif /*INCLtypesh*/ diff --git a/src/snc/var_types.c b/src/snc/var_types.c index 9df808b2..f0d7a6ed 100644 --- a/src/snc/var_types.c +++ b/src/snc/var_types.c @@ -8,43 +8,21 @@ in the file LICENSE that is included with this distribution. #include <assert.h> #include <stdlib.h> #include <stdio.h> +#include <string.h> #include "main.h" +#define var_types_GLOBAL #include "expr.h" +#undef var_types_GLOBAL /* #define DEBUG */ -const char *type_name(unsigned tag) -{ - switch (tag) { - case V_NONE: return "foreign"; - case V_EVFLAG: return "evflag"; - case V_CHAR: return "char"; - case V_UCHAR: return "unsigned char"; - case V_SHORT: return "short"; - case V_USHORT: return "unsigned short"; - case V_INT: return "int"; - case V_UINT: return "unsigned int"; - case V_LONG: return "long"; - case V_ULONG: return "unsigned long"; - case V_INT8T: return "epicsInt8"; - case V_UINT8T: return "epicsUInt8"; - case V_INT16T: return "epicsInt16"; - case V_UINT16T: return "epicsUInt16"; - case V_INT32T: return "epicsInt32"; - case V_UINT32T: return "epicsUInt32"; - case V_FLOAT: return "float"; - case V_DOUBLE: return "double"; - case V_STRING: return "string"; - case V_ENUM: return "enumeration"; - default: return ""; - } -} +static const int impossible = FALSE; -Expr *decl_add_base_type(Expr *ds, unsigned tag) +/* Add a common base type to all types in a multi-variable declaration */ +Expr *decl_add_base_type(Expr *ds, Type basetype) { Expr *d; - static const int impossible = FALSE; foreach(d, ds) { Var *var; @@ -53,37 +31,39 @@ Expr *decl_add_base_type(Expr *ds, unsigned tag) assert(d->type == D_DECL); /* pre-condition */ var = d->extra.e_decl; assert(var); - t->tag = tag; + /* structure copy */ + *t = basetype; t->parent = var->type; /* now roll back the stack of type expressions */ while(t->parent) { switch (t->parent->tag) { - case V_ARRAY: - if (tag == V_NONE) { + case T_ARRAY: + if (basetype.tag == T_NONE) { error_at_expr(d, "cannot declare array of foreign variables\n"); } - if (tag == V_EVFLAG) { + if (basetype.tag == T_EVFLAG) { error_at_expr(d, "cannot declare array of event flags\n"); } t->parent->val.array.elem_type = t; break; - case V_POINTER: - if (tag == V_NONE) { + case T_POINTER: + if (basetype.tag == T_NONE) { error_at_expr(d, "cannot declare pointer to foreign variable\n"); } - if (tag == V_EVFLAG) { + if (basetype.tag == T_EVFLAG) { error_at_expr(d, "cannot declare pointer to event flag\n"); } t->parent->val.pointer.value_type = t; break; - default: assert(impossible); + default: + assert(impossible); } t = t->parent; } assert(!t->parent); t->parent = bt; var->type = t; - if (tag == V_EVFLAG) + if (basetype.tag == T_EVFLAG) var->chan.evflag = new(EvFlag); } return ds; @@ -100,21 +80,27 @@ Expr *decl_add_init(Expr *d, Expr *init) return d; } -Expr *decl_create(Token name) +Expr *decl_create(Token id) { - Expr *d = expr(D_DECL, name, 0); + Expr *d = expr(D_DECL, id, 0); Var *var = new(Var); #ifdef DEBUG - report("decl_create: name(%s)\n", name.str); + report("decl_create: name(%s)\n", id.str); #endif assert(d->type == D_DECL); /* expr() post-condition */ - var->name = name.str; + var->name = id.str; d->extra.e_decl = var; var->decl = d; return d; } +Expr *abstract_decl_create(void) +{ + Token t = {0,0,0}; + return decl_create(t); +} + Expr *decl_postfix_array(Expr *d, char *s) { Type *t = new(Type); @@ -130,7 +116,7 @@ Expr *decl_postfix_array(Expr *d, char *s) report("decl_postfix_array %u\n", num_elems); #endif - t->tag = V_ARRAY; + t->tag = T_ARRAY; t->val.array.num_elems = num_elems; t->parent = d->extra.e_decl->type; d->extra.e_decl->type = t; @@ -145,16 +131,60 @@ Expr *decl_prefix_pointer(Expr *d) report("decl_prefix_pointer\n"); #endif assert(d->type == D_DECL); /* pre-condition */ - t->tag = V_POINTER; + t->tag = T_POINTER; t->parent = d->extra.e_decl->type; d->extra.e_decl->type = t; return d; } + +Type mk_prim_type(enum prim_type_tag tag) +{ + Type t; + + memset(&t, 0, sizeof(Type)); + + t.tag = T_PRIM; + t.val.prim = tag; + return t; +} + +Type mk_foreign_type(enum foreign_type_tag tag, char *name) +{ + Type t; + + memset(&t, 0, sizeof(Type)); + + t.tag = T_FOREIGN; + t.val.foreign.tag = tag; + t.val.foreign.name = name; + return t; +} + +Type mk_ef_type() +{ + Type t; + + memset(&t, 0, sizeof(Type)); + + t.tag = T_EVFLAG; + return t; +} + +Type mk_no_type() +{ + Type t; + + memset(&t, 0, sizeof(Type)); + + t.tag = T_NONE; + return t; +} + unsigned type_array_length1(Type *t) { switch (t->tag) { - case V_ARRAY: + case T_ARRAY: return t->val.array.num_elems; default: return 1; @@ -164,7 +194,7 @@ unsigned type_array_length1(Type *t) unsigned type_array_length2(Type *t) { switch (t->tag) { - case V_ARRAY: + case T_ARRAY: return type_array_length1(t->val.array.elem_type); default: return 1; @@ -176,12 +206,15 @@ 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: + case T_NONE: + case T_FOREIGN: + case T_POINTER: + case T_EVFLAG: return FALSE; - case V_ARRAY: + case T_ARRAY: return type_assignable_array(t->val.array.elem_type, depth + 1); + case T_PRIM: + /* make the compiler happy: */ default: return TRUE; } @@ -192,11 +225,11 @@ unsigned type_assignable(Type *t) return type_assignable_array(t, 0); } -static void gen_array_pointer(Type *t, unsigned last_tag, char *name) +static void gen_array_pointer(Type *t, enum type_tag last_tag, char *name) { - int paren = last_tag == V_ARRAY; + int paren = last_tag == T_ARRAY; switch (t->tag) { - case V_POINTER: + case T_POINTER: if (paren) printf("("); printf("*"); @@ -204,12 +237,14 @@ static void gen_array_pointer(Type *t, unsigned last_tag, char *name) if (paren) printf(")"); break; - case V_ARRAY: + case T_ARRAY: gen_array_pointer(t->parent, t->tag, name); printf("[%d]", t->val.array.num_elems); break; default: - printf("%s", name); + if (name) + printf("%s", name); + break; } } @@ -217,6 +252,18 @@ void gen_type(Type *t, char *name) { Type *bt = base_type(t); - printf("%s ", type_name(bt->tag)); - gen_array_pointer(bt->parent, V_NONE, name); + switch (bt->tag) { + case T_EVFLAG: + printf("evflag "); + break; + case T_PRIM: + printf("%s ", prim_type_name[bt->val.prim]); + break; + case T_FOREIGN: + printf("%s%s ", foreign_type_prefix[bt->val.foreign.tag], bt->val.foreign.name); + break; + default: + assert(impossible); + } + gen_array_pointer(bt->parent, T_NONE, name); } diff --git a/src/snc/var_types.h b/src/snc/var_types.h index 023ec80e..5ea2ed98 100644 --- a/src/snc/var_types.h +++ b/src/snc/var_types.h @@ -8,8 +8,15 @@ in the file LICENSE that is included with this distribution. #define INCLvar_typesh enum type_tag { - V_NONE, - V_EVFLAG, + T_NONE, /* undeclared (or declared as foreign) variable */ + T_EVFLAG, /* event flags */ + T_PRIM, /* primitive types: numbers, char, string */ + T_FOREIGN, /* foreign types (declared in C code) */ + T_POINTER, + T_ARRAY, +}; + +enum prim_type_tag { V_CHAR, V_UCHAR, V_SHORT, @@ -27,9 +34,13 @@ enum type_tag { V_FLOAT, V_DOUBLE, V_STRING, - V_ENUM, - V_POINTER, - V_ARRAY, +}; + +enum foreign_type_tag { + F_ENUM, + F_STRUCT, + F_UNION, + F_TYPENAME, }; struct array_type { @@ -41,9 +52,9 @@ struct pointer_type { struct type *value_type; }; -struct enum_type { - unsigned num_names; - char **names; +struct foreign_type { + enum foreign_type_tag tag; + char *name; }; typedef struct type Type; @@ -51,19 +62,72 @@ typedef struct type Type; struct type { enum type_tag tag; union { + enum prim_type_tag prim; + struct foreign_type foreign; struct pointer_type pointer; struct array_type array; - struct enum_type enumeration; } val; struct type *parent; }; -const char *type_name (unsigned tag); -#define type_base_type(t) (t->parent->tag) +/* base type for any combination of pointers and arrays */ #define base_type(t) (t->parent) + +/* array length in 1st and 2nd dimension */ unsigned type_array_length1(Type *t); unsigned type_array_length2(Type *t); + +/* whether type can be assign'ed to a PV */ unsigned type_assignable(Type *t); + +/* generate code for a type, name is an optional variable name */ void gen_type(Type *t, char *name); +/* creating types */ +Type mk_prim_type(enum prim_type_tag tag); +Type mk_foreign_type(enum foreign_type_tag tag, char *name); +Type mk_ef_type(); +Type mk_no_type(); + +#ifndef var_types_GLOBAL +extern +#endif +const char *prim_type_name[] +#ifdef var_types_GLOBAL += { + "char", + "unsigned char", + "short", + "unsigned short", + "int", + "unsigned int", + "long", + "unsigned long", + "epicsInt8", + "epicsUInt8", + "epicsInt16", + "epicsUInt16", + "epicsInt32", + "epicsUInt32", + "float", + "double", + "string", +} +#endif +; + +#ifndef var_types_GLOBAL +extern +#endif +const char *foreign_type_prefix[] +#ifdef var_types_GLOBAL += { + "enum ", + "struct ", + "union ", + "", +} +#endif +; + #endif /*INCLvar_typesh */ -- GitLab