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