From f06fb83f9cb74e825d17fe5889ecbed709dcad92 Mon Sep 17 00:00:00 2001 From: Mark Anderson Date: Thu, 4 Apr 1991 15:56:19 +0000 Subject: [PATCH] Initial revision --- src/sequencer/README | 4 + src/sequencer/Version | 1 + src/sequencer/gen_ss_code.c | 400 +++++++++++++++++++++++ src/sequencer/makeSeqVersion | 10 + src/sequencer/makeVersion | 10 + src/sequencer/parse.c | 594 +++++++++++++++++++++++++++++++++++ src/sequencer/parse.h | 148 +++++++++ src/sequencer/phase2.c | 475 ++++++++++++++++++++++++++++ src/sequencer/seq_ca.c | 152 +++++++++ src/sequencer/seq_mac.c | 288 +++++++++++++++++ src/sequencer/seq_main.c | 420 +++++++++++++++++++++++++ src/sequencer/seq_qry.c | 91 ++++++ src/sequencer/seq_task.c | 245 +++++++++++++++ src/sequencer/snc.y | 239 ++++++++++++++ src/sequencer/snc_lex.l | 164 ++++++++++ src/sequencer/snc_main.c | 194 ++++++++++++ 16 files changed, 3435 insertions(+) create mode 100644 src/sequencer/README create mode 100755 src/sequencer/Version create mode 100644 src/sequencer/gen_ss_code.c create mode 100755 src/sequencer/makeSeqVersion create mode 100755 src/sequencer/makeVersion create mode 100644 src/sequencer/parse.c create mode 100644 src/sequencer/parse.h create mode 100644 src/sequencer/phase2.c create mode 100644 src/sequencer/seq_ca.c create mode 100644 src/sequencer/seq_mac.c create mode 100644 src/sequencer/seq_main.c create mode 100644 src/sequencer/seq_qry.c create mode 100644 src/sequencer/seq_task.c create mode 100644 src/sequencer/snc.y create mode 100644 src/sequencer/snc_lex.l create mode 100644 src/sequencer/snc_main.c diff --git a/src/sequencer/README b/src/sequencer/README new file mode 100644 index 000000000..2a5e8e276 --- /dev/null +++ b/src/sequencer/README @@ -0,0 +1,4 @@ +### +### 3 Apr. 1991 (MDA) moved seq.c to seq_main.c for consistency with +### snc, and for ease of use in Imakefiles... +### diff --git a/src/sequencer/Version b/src/sequencer/Version new file mode 100755 index 000000000..9edc58bb1 --- /dev/null +++ b/src/sequencer/Version @@ -0,0 +1 @@ +1.6.4 diff --git a/src/sequencer/gen_ss_code.c b/src/sequencer/gen_ss_code.c new file mode 100644 index 000000000..eea07ef6b --- /dev/null +++ b/src/sequencer/gen_ss_code.c @@ -0,0 +1,400 @@ +/************************************************************************** + GTA PROJECT AT division + Copyright, 1990, The Regents of the University of California. + Los Alamos National Laboratory + + @(#)gen_ss_code.c 1.3 1/16/91 + DESCRIPTION: gen_ss_code.c -- routines to generate state set code + ENVIRONMENT: UNIX +***************************************************************************/ +#include +#include "parse.h" +#include "seq.h" + +/*+************************************************************************ +* NAME: gen_ss_code +* +* CALLING SEQUENCE +* type argument I/O description +* --------------------------------------------------- +* +* RETURNS: +* +* FUNCTION: Generate state set C code from tables. +* +* NOTES: All inputs are external globals. +*-*************************************************************************/ + +#define EVENT_STMT 1 +#define ACTION_STMT 2 +#define DELAY_STMT 3 + +gen_ss_code() +{ + extern LIST ss_list; + StateSet *ssp; + State *sp; + + /* For each state set ... */ + for (ssp = firstSS(&ss_list); ssp != NULL; ssp = nextSS(ssp)) + { + /* For each state ... */ + for (sp = firstState(&ssp->S_list); sp != NULL; sp = nextState(sp)) + { + /* Generate delay processing function */ + gen_delay_func(sp, ssp); + + /* Generate event processing function */ + gen_event_func(sp, ssp); + + /* Generate action processing function */ + gen_action_func(sp, ssp); + } + } +} + + +/* Generate action processing functions: + Each state has one action routine. It's name is derived from the + state set name and the state name. +*/ +gen_action_func(sp, ssp) +State *sp; +StateSet *ssp; /* Parent state set */ +{ + Trans *tp; + Action *ap; + int trans_num; + extern char *prog_name; + + printf("\n/* Action function for state \"%s\" in state set \"%s\" */\n", + sp->state_name, ssp->ss_name); + /* action function declaration with ss_ptr as parameter */ + printf("static a_%s_%s(sprog, ss_ptr)\nSPROG *sprog;\nSSCB\t*ss_ptr;\n{\n", + ssp->ss_name, sp->state_name); + /* "switch" stmt based on the transition number */ + printf("\tswitch(ss_ptr->trans_num)\n\t{\n"); + trans_num = 0; + /* For each transition (when statement) ... */ + for (tp = firstTrans(&sp->T_list); tp != NULL; tp = nextTrans(tp)) + { + /* "case" for each transition */ + printf("\tcase %d:\n", trans_num); + /* For each action statement insert action code */ + for (ap = firstAction(&tp->A_list); ap != NULL; + ap = nextAction(ap)) + { + print_line_num(ap->line_num); + switch (ap->type) + { + case A_STMT: + printf("\t\t"); + /* Evaluate statements */ + eval_expr(ACTION_STMT, ap->stmt.expr, sp); + printf(";\n"); + break; + case A_CCODE: + printf("%s\n", ap->stmt.c_code); + break; + } + } + /* end of case */ + printf("\t\treturn;\n"); + trans_num++; + } + /* end of switch stmt */ + printf("\t}\n"); + /* end of function */ + printf("}\n"); + return; +} + +/* Generate a C function that checks events for a particular state */ +gen_event_func(sp, ssp) +State *sp; +StateSet *ssp; +{ + Trans *tp; + int index, trans_num; + + printf("\n/* Event function for state \"%s\" in state set \"%s\" */\n", + sp->state_name, ssp->ss_name); + printf("static e_%s_%s(sprog, ss_ptr)\n", ssp->ss_name, sp->state_name); + printf("SPROG\t*sprog;\n"); + printf("SSCB\t*ss_ptr;\n{\n"); + trans_num = 0; + sp->ndelay = 0; + /* For each transition generate an "if" statement ... */ + for (tp = firstTrans(&sp->T_list); tp != NULL; tp = nextTrans(tp)) + { + print_line_num(tp->line_num); + printf("\tif ("); + eval_expr(EVENT_STMT, tp->event_expr, sp); + /* an event triggered, set next state */ + printf(")\n\t{\n"); + /* index is the transition number (0, 1, ...) */ + index = state_block_index_from_name(ssp, tp->new_state_name); + if (index < 0) + { + fprintf(stderr, "Line %d: ", tp->line_num); + fprintf(stderr, "No state %s in state set %s\n", + tp->new_state_name, ssp->ss_name); + index = 0; /* default to 1-st state */ + printf("\t\t/* state %s does not exist */\n", + tp->new_state_name); + } + printf("\t\tss_ptr->next_state = ss_ptr->states + %d;\n", index); + printf("\t\tss_ptr->trans_num = %d;\n", trans_num); + printf("\t\treturn TRUE;\n\t}\n"); + trans_num++; + } + printf("\treturn FALSE;\n"); + printf("}\n"); +} + +/* Generate delay processing function for a state */ +gen_delay_func(sp, ssp) +State *sp; +StateSet *ssp; +{ + Trans *tp; + + printf("\n/* Delay function for state \"%s\" in state set \"%s\" */\n", + sp->state_name, ssp->ss_name); + printf("static d_%s_%s(sprog, ss_ptr)\n", ssp->ss_name, sp->state_name); + printf("SPROG\t*sprog;\n"); + printf("SSCB\t*ss_ptr;\n{\n"); + sp->ndelay = 0; + /* For each transition ... */ + for (tp = firstTrans(&sp->T_list); tp != NULL; tp = nextTrans(tp)) + { + print_line_num(tp->line_num); + eval_delay(tp->event_expr, sp); + } + printf("}\n"); + if (sp->ndelay > ssp->ndelay) + ssp->ndelay = sp->ndelay; /* max # delay calls in ss */ + return; +} + + +/* Evaluate an expression. + Checks for special functions: + efSet(ef) and efGet(ef) -> set corresponding bit in ef_mask. + pvPut() & pvGet -> replace variable with ptr to db struct. +*/ +eval_expr(stmt_type, ep, sp) +int stmt_type; /* EVENT_STMT, ACTION_STMT, or DELAY_STMT */ +Expr *ep; /* ptr to expression */ +State *sp; /* ptr to current State struct */ +{ + Expr *epf; + int nparams; + + switch(ep->type) + { + case E_VAR: + printf("%s", ep->value.var->name); + break; + case E_CONST: + printf("%s", ep->value.const); + break; + case E_STRING: + printf("\"%s\"", ep->value.const); + break; + case E_FUNC: + if (special_func(stmt_type, ep, sp)) + break; + printf("%s(", ep->value.const); + for (epf = ep->right, nparams = 0; epf != 0; + epf = epf->next, nparams++) + { + if (nparams > 0) + printf(" ,"); + eval_expr(stmt_type, epf, sp); + } + printf(") "); + break; + case E_BINOP: + eval_expr(stmt_type, ep->left, sp); + printf("%s", ep->value.const); + eval_expr(stmt_type, ep->right, sp); + break; + case E_PAREN: + printf("("); + eval_expr(stmt_type, ep->right, sp); + printf(")"); + break; + case E_UNOP: + printf("%s", ep->value.const); + eval_expr(stmt_type, ep->right, sp); + break; + case E_SUBSCR: + eval_expr(stmt_type, ep->left, sp); + printf("["); + eval_expr(stmt_type, ep->right, sp); + printf("]"); + break; + default: + if (stmt_type == EVENT_STMT) + printf("TRUE"); /* empty event statement defaults to TRUE */ + else + printf(" "); + break; + } +} + +enum fcode { F_NONE, F_EFSET, F_EFTEST, F_PVGET, F_PVPUT, F_DELAY }; + +enum fcode func_name_to_code(fname) +char *fname; +{ + if (strcmp(fname, "efSet") == 0) + return F_EFSET; + if (strcmp(fname, "efTest") == 0) + return F_EFTEST; + if (strcmp(fname, "pvPut") == 0) + return F_PVPUT; + if (strcmp(fname, "pvGet") == 0) + return F_PVGET; + if (strcmp(fname, "delay") == 0) + return F_DELAY; + return F_NONE; +} + +/* Process special function (returns TRUE if this is a special function) */ +special_func(stmt_type, ep, sp) +int stmt_type; /* ACTION_STMT or EVENT_STMT */ +Expr *ep; /* ptr to function in the expression */ +State *sp; /* current State struct */ +{ + char *fname; /* function name */ + Expr *ep1; /* 1-st parameter */ + Chan *cp; + Var *vp; + enum fcode func_code; + + fname = ep->value.const; + func_code = func_name_to_code(fname); + if (func_code == F_NONE) + return FALSE; /* not a special function */ + + ep1 = ep->right; /* ptr to 1-st parameters */ + if ( (ep1 != 0) && (ep1->type == E_VAR) ) + { + vp = ep1->value.var; + cp = vp->chan; + } + else + { + vp = 0; + cp = 0; + } + + if (func_code == F_EFSET || func_code == F_EFTEST) + { + if (vp->type != V_EVFLAG) + { + fprintf(stderr, "Line %d: ", ep->line_num); + fprintf(stderr, + "Parameter to efSet() and efTest() must be an event flag\n"); + } + else if (func_code == F_EFSET && stmt_type == EVENT_STMT) + { + fprintf(stderr, "Line %d: ", ep->line_num); + fprintf(stderr, + "efSet() cannot be used as an event.\n"); + } + else + { + printf("%s(%s)", fname, vp->name); + /* OR the ef bit with ef mask in State struct */ + sp->event_flag_mask |= 1 << (vp->ef_num); + } + return TRUE; + } + else if (func_code == F_PVPUT || func_code == F_PVGET) + { + if (cp == 0) + { + fprintf(stderr, "Line %d: ", ep->line_num); + fprintf(stderr, + "Parameter to pvPut/pvGet must be DB variable.\n"); + } + else if (stmt_type == EVENT_STMT) + { + fprintf(stderr, + "pvPut/pvGet cannot be used as an event.\n"); + } + else + { + printf("%s(%d)", fname, cp->index); + } + return TRUE; + } + else if (func_code == F_DELAY) + { /* Test for delay: "test_delay(delay_id)" */ + printf("test_delay(%d)", sp->ndelay++); + return TRUE; + } + else + return FALSE; /* not a special function */ +} + +/* Evaluate delay expression. + This is similar to eval_expr() except that all output + is supressed until a delay() function is found. All + parameters are then processed with eval_expr(). +*/ +eval_delay(ep, sp) +Expr *ep; /* ptr to expression */ +State *sp; /* ptr to current State struct */ +{ + Expr *epf; + +#ifdef DEBUG + fprintf(stderr, "eval_delay: type=%d\n", ep->type); +#endif DEBUG + switch(ep->type) + { + case E_FUNC: +#ifdef DEBUG + fprintf(stderr, "fn=%s\n", ep->value.const); +#endif DEBUG + if (strcmp(ep->value.const, "delay") == 0) + { /* delay function found: replace with special + function & parameters, then evaluate 1-st + parameter only + */ + printf("\tstart_delay(%d, ", sp->ndelay++); + epf = ep->right; /* paramter */ + eval_expr(EVENT_STMT, epf, sp); + printf(");\n"); + } + else + { + for (epf = ep->right; epf != 0; epf = epf->next) + { + eval_delay(epf, sp); + } + } + break; + case E_BINOP: + eval_delay(ep->left, sp); + eval_delay(ep->right, sp); + break; + case E_PAREN: + eval_delay(ep->right, sp); + break; + case E_UNOP: + eval_delay(ep->right, sp); + break; + case E_SUBSCR: + eval_delay(ep->left, sp); + eval_delay(ep->right, sp); + break; + default: + break; + } +} + diff --git a/src/sequencer/makeSeqVersion b/src/sequencer/makeSeqVersion new file mode 100755 index 000000000..dc794fce0 --- /dev/null +++ b/src/sequencer/makeSeqVersion @@ -0,0 +1,10 @@ +#!/bin/csh -f +# +# makeSeqVersion - create the sequencer version module +# +set VERSION = `cat Version` +set DATE = `date` +echo '/* seqVersion.c - version & date */' +echo '/* Created by makeVersion */' +echo 'char *seqVersion = "@(#)SEQ Version '${VERSION}': '${DATE}'";' + diff --git a/src/sequencer/makeVersion b/src/sequencer/makeVersion new file mode 100755 index 000000000..7111fd3a7 --- /dev/null +++ b/src/sequencer/makeVersion @@ -0,0 +1,10 @@ +#!/bin/csh -f +# +# makeVersion - create the snc version module +# +set VERSION = `cat Version` +set DATE = `date` +echo '/* sncVersion.c - version & date */' +echo '/* Created by makeVersion */' +echo 'char *sncVersion = "@(#)SNC Version '${VERSION}': '${DATE}'";' + diff --git a/src/sequencer/parse.c b/src/sequencer/parse.c new file mode 100644 index 000000000..0f383d76e --- /dev/null +++ b/src/sequencer/parse.c @@ -0,0 +1,594 @@ +/* #define DEBUG 1 */ +/************************************************************************** + GTA PROJECT AT division + Copyright, 1990, The Regents of the University of California. + Los Alamos National Laboratory + + @(#)parse.c 1.1 10/16/90 + 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 +***************************************************************************/ + +/*====================== Includes, globals, & defines ====================*/ +#include +#include +#include "parse.h" /* defines linked list structures */ +#include +#include "db_access.h" + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif TRUE + +int debug_print_flag = 0; /* Debug level (set by source file) */ + +int line_num; /* Current line number */ + +char *prog_name; /* ptr to program name (string) */ + +char *prog_param; /* parameter string for program stmt */ + +LIST defn_c_list; /* definition C code */ + +LIST ss_list; /* start of state-set list */ + +LIST var_list; /* start of variable list */ + +LIST chan_list; /* start of DB channel list */ + +LIST state_list; /* temporary state list */ + +LIST action_list; /* temporary action list */ + +LIST trans_list; /* temporary transition list */ + +char *global_c_code; /* global C code following state program */ + /*+************************************************************************ +* NAME: snc_init +* +* CALLING SEQUENCE: none +* +* RETURNS: +* +* FUNCTION: Initialize state program tables & linked lists +* +* NOTES: +*-*************************************************************************/ +init_snc() +{ + lstInit(&defn_c_list); + lstInit(&ss_list); + lstInit(&var_list); + lstInit(&chan_list); + lstInit(&state_list); + lstInit(&action_list); + lstInit(&trans_list); + return; +} + /*+************************************************************************ +* NAME: program_name +* +* CALLING SEQUENCE: none +* type argument I/O description +* ----------------------------------------------------------------- +* char *pname I ptr to program name string +* +* RETURNS: +* +* FUNCTION: Save program name for global use. +* +*-*************************************************************************/ +program_name(pname, pparam) +char *pname, *pparam; +{ + extern char *prog_name, *prog_param; + + prog_name = pname; + prog_param = pparam; +#ifdef DEBUG + printf("program name = %s\n", prog_name); +#endif + return; +} + +/* Parsing a declaration statement */ +decl_stmt(type, name, s_length, value) +int type; /* variable type (e.g. V_FLOAT) */ +char *name; /* ptr to variable name */ +char *s_length; /* array lth (NULL=single element) */ +char *value; /* initial value or NULL */ +{ + Var *vp; + int length; + + if (s_length == 0) + length = 0; + else if (type == V_STRING) + length = MAX_STRING_SIZE; + else + { + length = atoi(s_length); + if (length < 0) + length = 0; + } +#ifdef DEBUG + printf("variable decl: type=%d, name=%s, length=%d\n", type, name, length); +#endif + /* See if variable already declared */ + vp = (Var *)find_var(name); + if (vp != 0) + { + fprintf(stderr, "variable %s already declared, line %d\n", + name, line_num); + return; + } + /* Build a struct for this variable */ + vp = allocVar(); + lstAdd(&var_list, (NODE *)vp); + vp->name = name; + vp->type = type; + vp->length = length; + vp->value = value; /* initial value or NULL */ + return; +} + +/* "Assign" statement: assign a variable to a DB channel. + elem_num is ignored in this version) */ +assign_stmt(name, lower_lim, upper_lim, db_name) +char *name; /* ptr to variable name */ +char *lower_lim; /* ptr to lower array limit */ +char *upper_lim; /* ptr to upper array limit */ +char *db_name; /* ptr to db name */ +{ + Chan *cp; + Var *vp; + int range_low, range_high, length; + + /* Find the variable */ + vp = (Var *)find_var(name); + if (vp == 0) + { + fprintf(stderr, "assign: variable %s not declared, line %d\n", + name, line_num); + return; + } + + /* Build structure for this channel */ + cp = allocChan(); + lstAdd(&chan_list, (NODE *)cp); + cp->var = vp; /* make connection to variable */ + vp->chan = cp; /* reverse ptr */ + cp->db_name = db_name; /* DB name */ + + /* convert specified range REMOVED********* */ + length = vp->length; + if (length == 0) + length = 1; /* not an array */ + if (vp->type == V_STRING) + length = 1; /* db treats strings as length 1 */ + cp->length = length; + cp->offset = 0; + cp->mon_flag = FALSE; /* assume no monitor */ + cp->ef_var = NULL; /* assume no sync event flag */ + return; +} + +/* Build the range string, e.g. "0", and "9" into "0,9" */ +char * +range(low, high) +char *low, *high; +{ + static char range_str[30]; + sprintf(range_str, "%s,%s", low, high); + return range_str; +} + + +/* Parsing a "monitor" statement */ +monitor_stmt(name, offset, delta) +char *name; /* variable name (should be assigned) */ +char *offset; /* array offset */ +char *delta; /* monitor delta */ +{ + Chan *cp; + int offs; + + /* Pick up array offset */ + if (offset == 0) + offs = 0; + else + offs = atoi(offset); + if (offs < 0) + offs = 0; + /* Find a channel assigned to this variable */ + cp = (Chan *)find_chan(name, offs); + if (cp == 0) + { + fprintf(stderr, "monitor: variable %s[%s] not assigned, line %d\n", + name, offset, line_num); + return; + } + + /* Enter monitor parameters */ + cp->mon_flag = TRUE; + cp->delta = atof(delta); + return; +} + +/* Parsing "sync" statement */ +sync_stmt(name, offset, ef_name) +char *name; +char *offset; +char *ef_name; +{ + Chan *cp; + Var *vp; + int offs; + + /* Find the variable */ + if (offset == 0) + offs = 0; + else + offs = atoi(offset); + if (offs < 0) + offs = 0; + cp = (Chan *)find_chan(name, offs); + if (cp == 0) + { + fprintf(stderr, "sync: variable %s[%s] not assigned, line %d\n", + name, offset, line_num); + return; + } + /* Find the event flag varible */ + vp = (Var *)find_var(ef_name); + if (vp == 0 || vp->type != V_EVFLAG) + { + fprintf(stderr, "sync: e-f variable %s not declared, line %d\n", + ef_name, line_num); + return; + } + cp->ef_var = vp; + + return; +} + +/* Definition C code */ +defn_c_stmt(c_str) +char *c_str; +{ + Action *ap; +#ifdef DEBUG + printf("defn_c_stmt\n"); +#endif + ap = allocAction(); + lstAdd(&defn_c_list, (NODE *)ap); + ap->type = A_CCODE; + ap->stmt.c_code = c_str; + ap->line_num = line_num; + + return; +} + +/* Parsing "ss" statement */ +state_set(ss_name) +char *ss_name; +{ + StateSet *ssp; + +# ifdef DEBUG + printf("state_set: ss_name=%s\n", ss_name); +#endif + /* Is this state set already declared ? */ + if (find_state_set(ss_name) != NULL) + { + fprintf(stderr, "Duplicate state set name: %s, line %d\n", + ss_name, line_num); + return; + } + + /* create and fill in state-set block */ + ssp = allocSS(); + lstAdd(&ss_list, (NODE *)ssp); + ssp->ss_name = ss_name; + /* move temporary state list into this node */ +#ifdef DEBUG + printf(" # states = %d\n", lstCount(&state_list)); +#endif DEBUG + ssp->S_list = state_list; + lstInit(&state_list); + + return; +} + + +state_block(state_name) +char *state_name; +{ + State *sp; + +#ifdef DEBUG + printf("state_block: state_name=%s\n", state_name); +#endif + sp = firstState(&state_list); + if (find_state(state_name, sp) != NULL) + { + fprintf(stderr, "Duplicate state name: %s, line %d\n", + state_name, line_num); + return; + } + + sp = allocState(); + lstAdd(&state_list, (NODE *)sp); + sp->state_name = state_name; + /* move tmp transition list into this node */ + sp->T_list = trans_list; + lstInit(&trans_list); + return; +} + +/* Parsing transition part of "when" clause */ +transition(new_state_name, event_expr) +char *new_state_name; +Expr *event_expr; /* event expression */ +{ + Trans *tp; + +#ifdef DEBUG + printf("transition: new_state_name=%s\n", new_state_name); +#endif + tp = allocTrans(); + lstAdd(&trans_list, (NODE *)tp); + tp->new_state_name = new_state_name; + tp->line_num = line_num; + /* move tmp action list into this node */ + tp->A_list = action_list; + tp->event_expr = event_expr; + lstInit(&action_list); + + return; +} + +/* Action statement (lvalue = expression;) or (function())*/ +action_stmt(ep) +Expr *ep; /* ptr to expression */ +{ + Action *ap; +#ifdef DEBUG + printf("action_function\n"); +#endif + ap = allocAction(); + lstAdd(&action_list, (NODE *)ap); + ap->type = A_STMT; + ap->stmt.expr = ep; + ap->line_num = line_num; + + return; +} + +/* Action statement: in-line C code */ +action_c_stmt(c_str) +char *c_str; +{ + Action *ap; +#ifdef DEBUG + printf("action_c_stmt\n"); +#endif + ap = allocAction(); + lstAdd(&action_list, (NODE *)ap); + ap->type = A_CCODE; + ap->stmt.c_code = c_str; + ap->line_num = line_num; + + return; +} + + +/* Find a variable by name; returns a pointer to the Var struct; + returns 0 if the variable is not found. */ +find_var(name) +char *name; +{ + Var *vp; + +#ifdef DEBUG + printf("find_var, name=%s: ", name); +#endif + vp = firstVar(&var_list); + while (vp != NULL) + { + if (strcmp(vp->name, name) == 0) + { +#ifdef DEBUG + printf("found\n"); +#endif + return (int)vp; + } + vp = nextVar(vp); + } +#ifdef DEBUG + printf("not found\n"); +#endif + return 0; +} + +/* Find channel with same variable name and same offset */ +find_chan(name, offset) +char *name; /* variable name */ +int offset;/* array offset */ +{ + Chan *cp; + Var *vp; + int chan_offs; + + if (offset < 0) + offset = 0; + for (cp = firstChan(&chan_list); cp != NULL; cp = nextChan(cp)) + { + vp = cp->var; + if (vp == 0) + continue; + chan_offs = cp->offset; + if (chan_offs < 0) + chan_offs = 0; + if (strcmp(vp->name, name) == 0 && chan_offs == offset) + { + return (int)cp; + } + } + return 0; +} + +/* Given the name of a state, find ptr to the state struct */ +find_state(state_name, sp) +char *state_name; /* state name we're looking for */ +State *sp; /* start of state list */ +{ + for (; sp != NULL; sp = nextState(sp)) + { + if (strcmp(sp->state_name, state_name) == 0) + return (int)sp; + } + return NULL; /* not found */ +} + +/* Given the name of a state set, find ptr to state set struc */ +find_state_set(ss_name) +char *ss_name; /* state set name we're looking for */ +{ + StateSet *ssp; + extern LIST ss_list; + + for (ssp = firstSS(&ss_list); ssp != NULL; ssp = nextSS(ssp)) + { + if (strcmp(ssp->ss_name, ss_name) == 0) + return (int)ssp; + } + return NULL; /* not found */ +} + +/* Set debug print flag */ +set_debug_print(flag) +char *flag; +{ + debug_print_flag = atoi(flag); +} + +/* Parsing "program" statement */ +program(c_code) +char *c_code; +{ + global_c_code = c_code; + phase2(); + + exit(0); +} + +/* Build an expression list (hierarchical) */ +Expr *expression(type, value, left, right) +int type; +char *value; +Expr *left, *right; +{ + Expr *ep; + + /* alloc a block for this item or expression */ +#ifdef DEBUG + fprintf(stderr, "expression: type=%d, value=%s, left=%d, right=%d\n", + type, value, left, right); +#endif + ep = allocExpr(); + ep->type = type; + ep->value.const = value; + ep->left = left; + ep->right = right; + ep->line_num = line_num; + + switch (type) + { + case E_VAR: /* variable or pre-defined constant */ + if (pre_defined_const(ep)) + { + ep->type = E_CONST; + break; /* defined constant */ + } + /* find the variable */ + ep->value.var = (Var *)find_var(value); + if (ep->value.var == 0) + { + fprintf(stderr, "variable \"%s\" not declared, line no. %d\n", + value, ep->line_num); + } + break; + + case E_CONST: /* number const */ + break; + + case E_STRING: /* string const */ + break; + + case E_BINOP: /* binary op. ( left_expr OP rt_expr ) */ + break; + + case E_UNOP: /* unary op. */ + break; + + case E_PAREN: /* parenthetical expr. */ + break; + + case E_FUNC: + break; + + case E_EMPTY: /* empty */ + break; + + case E_SUBSCR: /* subscript */ + break; + + default: /* any other */ + fprintf(stderr, "? %d: %s, line no. %d\n", type, value, line_num); + break; + } + + return ep; +} + +/* Check for defined constant */ +pre_defined_const(ep) +Expr *ep; +{ + if ( (strcmp(ep->value.const, "TRUE") == 0) + || (strcmp(ep->value.const, "FALSE") == 0) ) + return TRUE; + else + return FALSE; +} + +/* Add a parameter (expression) to end of list */ +Expr *parameter(ep, p_list) +Expr *ep; +Expr *p_list; /* current list */ +{ + Expr *ep1; + + ep->next = 0; + if (p_list == 0) + return ep; + + ep1 = p_list; + while (ep1->next != 0) + ep1 = ep1->next; + ep1->next = ep; + return p_list; +} + +/*#define PHASE2*/ +#ifdef PHASE2 +phase2() +{ + fprintf(stderr, "phase2() - dummy\07\n"); +} +#endif PHASE2 diff --git a/src/sequencer/parse.h b/src/sequencer/parse.h new file mode 100644 index 000000000..6ffc8c98e --- /dev/null +++ b/src/sequencer/parse.h @@ -0,0 +1,148 @@ +/************************************************************************** + GTA PROJECT AT division + Copyright, 1989, The Regents of the University of California. + Los Alamos National Laboratory + + @(#)parse.h 1.1 10/16/90 + DESCRIPTION: Structures for parsing the state notation language. + ENVIRONMENT: UNIX +***************************************************************************/ +/* 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. +*/ + +#include "lstLib.h" /* VxWorks "list" routines & definitions */ + +struct state_set /* state-set block */ +{ + NODE SS_link; /* link to next state set block */ + char *ss_name; /* state set name */ + LIST S_list; /* link to first state block */ + int ndelay; /* Max # delay calls in state set */ +}; +typedef struct state_set StateSet; + +struct state /* State block */ +{ + NODE S_link; /* link to next state in this SS */ + char *state_name; /* state name */ + int event_flag_mask; /* event flag mask for this state */ + int ndelay; /* # delay calls */ + LIST T_list; /* start of transition list */ +}; +typedef struct state State; + +struct trans /* Transition Block */ +{ + NODE T_link; /* link to next transition block */ + int trans_num; /* transition number */ + int line_num; + char *new_state_name; /* new state name */ + struct expression *event_expr; /* event expression */ + LIST A_list; /* start of action list */ +}; +typedef struct trans Trans; + +struct expression /* Expression block */ +{ + struct expression *next; /* link to next expression */ + struct expression *left; /* ptr to left expression */ + struct expression *right; /* ptr to right expression */ + int type; /* operator or expression type */ + union { /* for variables, functions, & constants */ + struct var *var; /* ptr to variable definition */ + char *name; /* ptr to function name */ + char *const; /* ptr to constant */ + } value; + int line_num; /* line number */ +}; +typedef struct expression Expr; + +struct action /* Action block */ +{ + NODE A_link; /* link to next action (or NULL) */ + int line_num; /* line number of statement */ + int type; /* A_CCODE, A_FUNC, A_STMT */ + union stmt { + Expr *expr; /* ptr to expression (A_STMT) */ + char *c_code; /* ptr to imbedded C code (A_CCODE) */ + } stmt; +}; +typedef struct action Action; + +struct var /* Variable or function definition */ +{ + NODE V_link; /* next variable in list */ + char *name; /* variable name */ + char *value; /* initial value or NULL */ + int type; /* var type */ + int length; /* array lth (0 if not an array) */ + int ef_num; /* event flag bit number */ + struct db_chan *chan; /* ptr to db channel struct or NULL */ +}; +typedef struct var Var; + +struct db_chan /* DB channel */ +{ + NODE D_link; /* next db chan in list */ + char *db_name; /* db name if assigned */ + int index; /* channel array index */ + Var *var; /* ptr to variable definition */ + int offset; /* array offset (normally 0) */ + int length; /* sub-array length */ + int mon_flag; /* TRUE if channel is "monitored" */ + float delta; /* monitor dead-band */ + float timeout; /* monitor timeout (seconds) */ + Var *ef_var; /* ptr to event flag variable for sync */ +}; +typedef struct db_chan Chan; + +/* Linked list definitions to get rid of yucky in-line code */ +#define nextSS(node) (StateSet *)lstNext( (NODE *)node ) +#define firstSS(head) (StateSet *)lstFirst( (LIST *)head ) +#define allocSS() (StateSet *)malloc(sizeof(StateSet)); +#define nextState(node) (State *)lstNext( (NODE *)node ) +#define firstState(head) (State *)lstFirst( (LIST *)head ) +#define allocState() (State *)malloc(sizeof(State)); +#define nextTrans(node) (Trans *)lstNext( (NODE *)node ) +#define firstTrans(head) (Trans *)lstFirst( (LIST *)head ) +#define allocTrans() (Trans *)malloc(sizeof(Trans)); +#define allocExpr() (Expr *)malloc(sizeof(Expr)); +#define nextAction(node) (Action *)lstNext( (NODE *)node ) +#define firstAction(head) (Action *)lstFirst( (LIST *)head ) +#define allocAction() (Action *)malloc(sizeof(Action)); +#define nextVar(node) (Var *)lstNext( (NODE *)node ) +#define allocVar() (Var *)malloc(sizeof(Var)); +#define firstVar(head) (Var *)lstFirst( (LIST *)head ) +#define nextChan(node) (Chan *)lstNext( (NODE *)node ) +#define firstChan(head) (Chan *)lstFirst( (LIST *)head ) +#define allocChan() (Chan *)malloc(sizeof(Chan)); + +/* Variable types */ +#define V_NONE 0 /* not defined */ +#define V_FLOAT 1 /* float */ +#define V_INT 2 /* int */ +#define V_SHORT 3 /* short */ +#define V_CHAR 4 /* char */ +#define V_DOUBLE 5 /* double */ +#define V_STRING 6 /* strings (array of char) */ +#define V_EVFLAG 7 /* event flag */ +#define V_FUNC 8 /* function (not a variable) */ + +/* Expression type */ +#define E_CONST 1 /* numeric constant */ +#define E_VAR 2 /* variable */ +#define E_FUNC 3 /* function */ +#define E_STR 4 /* ptr to string consatant */ +#define E_UNOP 5 /* unary operator: OP expr (-, +, or !) */ +#define E_BINOP 6 /* binary operator: expr OP expr */ +#define E_PAREN 7 /* parenthesis around expression */ +#define E_SUBSCR 8 /* subscript */ +#define E_STRING 9 /* string const */ +#define E_EMPTY 0 /* empty expression */ + +/* Action types */ +#define A_CCODE 1 /* imbedded C code: %% or %{...}% */ +#define A_STMT 2 /* lvalue = expression; or function();*/ diff --git a/src/sequencer/phase2.c b/src/sequencer/phase2.c new file mode 100644 index 000000000..c64c9d80a --- /dev/null +++ b/src/sequencer/phase2.c @@ -0,0 +1,475 @@ +/************************************************************************** + GTA PROJECT AT division + Copyright, 1990, The Regents of the University of California. + Los Alamos National Laboratory + + @(#)phase2.c 1.4 1/16/91 + DESCRIPTION: Phase 2 code generation routines for SNC. + Produces code and tables in C output file. + See also: gen_ss_code.c + ENVIRONMENT: UNIX +***************************************************************************/ + +#include +#include "parse.h" +#include "seq.h" + +/*+************************************************************************ +* NAME: phase2 +* +* CALLING SEQUENCE +* type argument I/O description +* --------------------------------------------------- +* +* RETURNS: n/a +* +* FUNCTION: Generate C code from tables. +* +* NOTES: All inputs are external globals. +*-*************************************************************************/ +int num_vars = 0; /* number of variables declared */ +int num_channels = 0; /* number of db channels */ +int num_ss = 0; /* number of state sets */ +int num_errors = 0; /* number of errors detected in phase 2 processing */ + +phase2() +{ + extern LIST var_list; /* variables (from parse) */ + extern LIST ss_list; /* state sets (from parse) */ + extern char *prog_name; /* program name (from parse) */ + extern char *global_c_code; /* global C code */ + + /* Count number of variables, db channels, and state sets defined */ + num_vars = lstCount((NODE *)&var_list); + num_channels = db_chan_count(); + num_ss = lstCount((NODE *)&ss_list); + + /* Generate preamble code */ + gen_preamble(); + + /* Generate variable declarations */ + gen_var_decl(); + + /* Generate definition C code */ + gen_defn_c_code(); + + /* Assign bits for event flags */ + assign_ef_bits(); + + /* Generate DB blocks */ + gen_db_blocks(); + + /* Generate code for each state set */ + gen_ss_code(); + + /* Generate State Blocks */ + gen_state_blocks(); + + /* Generate State Set control blocks as an array */ + gen_sscb_array(); + + /* Generate state program table */ + gen_state_prog_table(); + + /* Output global C code */ + printf("%s\n", global_c_code); + + exit(0); +} + +/* Generate preamble (includes, defines, etc.) */ +gen_preamble() +{ + printf("/* Program \"%s\" */\n", prog_name); + + /* Include files */ + printf("#include \"seq.h\"\n"); + + /* Local definitions */ + printf("\n#define NUM_SS %d\n", num_ss); + printf("#define NUM_VARS %d\n", num_vars); + printf("#define NUM_CHANNELS %d\n", num_channels); + + /* Forward definition of SPROG structure */ + printf("\nextern SPROG %s;\n", prog_name); + + return; +} + +/* Generate a C variable declaration for each variable declared in SNL */ +gen_var_decl() +{ + extern LIST var_list; + Var *vp; + char *vstr, *vname="User_Var_"; + int nv; + + printf("\n/* Variable declarations */\n"); + for (nv=0, vp = firstVar(&var_list); vp != NULL; nv++, vp = nextVar(vp)) + { + if (vp->type != V_EVFLAG) + printf("#define %s %s.var%d\n", vp->name, vname, nv); + } + printf("static struct %s {\n", vname); + for (nv=0, vp = firstVar(&var_list); vp != NULL; nv++, vp = nextVar(vp)) + { + switch (vp->type) + { + case V_CHAR: + vstr = "char"; + break; + case V_INT: + vstr = "int"; + break; + case V_SHORT: + vstr = "short"; + break; + case V_FLOAT: + vstr = "float"; + break; + case V_DOUBLE: + vstr = "double"; + break; + case V_STRING: + vstr = "char"; + break; + case V_EVFLAG: + vstr = NULL; + break; + default: + vstr = "int"; + break; + } + if (vstr != NULL) + { + printf("\t%s\tvar%d", vstr, nv); + /* Array? */ + if (vp->length > 0) + printf("[%d];\n", vp->length); + else if (vp->type == V_STRING) + printf("[MAX_STRING_SIZE];\n"); + else + printf(";\n"); + } + } + printf("} %s;\n", vname); + return; +} + +/* Generate definition C code (C code in definition section) */ +gen_defn_c_code() +{ + extern LIST defn_c_list; + Action *ap; + + ap = firstAction(&defn_c_list); + if (ap != NULL) + { + printf("\n\t/* C code definitions */\n"); + for (; ap != NULL; ap = nextAction(ap)) + { + print_line_num(ap->line_num); + printf("%s\n", ap->stmt.c_code); + } + } + return; +} + +/* Generate the structure with data for a state program table (SPROG) */ +gen_state_prog_table() +{ + extern char *prog_param; + + printf("\n/* Program parameter list */\n"); + + printf("static char prog_param[] = \"%s\";\n", prog_param); + + printf("\n/* State Program table (global) */\n"); + + printf("SPROG %s = {\n", prog_name); + + printf("\t%d,\t/* magic number */\n", MAGIC); + + printf("\t0,\t/* task id */\n"); + + printf("\t0,\t/* task_is_deleted */\n"); + + printf("\t1,\t/* relative task priority */\n"); + + printf("\t0,\t/* sem_id */\n"); + + printf("\tdb_channels,\t/* *channels */\n"); + + printf("\tNUM_CHANNELS,\t/* nchan */\n"); + + printf("\tsscb,\t/* *sscb */\n"); + + printf("\tNUM_SS,\t/* nss */\n"); + + printf("\t&User_Var_,\t/* ptr to user area */\n"); + + printf("\t4,\t/* user area size */\n"); + + printf("\t\"%s\",\t/* *name */\n", prog_name); + + printf("\tprog_param\t/* *params */\n"); + + printf("};\n"); + + return; +} + +/* Generate database blocks with structure and data for each defined channel */ +gen_db_blocks() +{ + extern LIST chan_list; + Chan *cp; + int nchan; + + printf("\n/* Database Blocks */\n"); + printf("static CHAN db_channels[NUM_CHANNELS] = {\n"); + nchan = 0; + for (cp = firstChan(&chan_list); cp != NULL; cp = nextChan(cp)) + { + /* Only process db variables */ + if (cp->db_name != NULL) + { + if (nchan > 0) + printf(",\n"); + fill_db_block(cp); + nchan++; + } + } + printf("\n};\n"); + return; +} + +/* Fill in a db block with data (all elements for "CHAN" struct) */ +fill_db_block(cp) +Chan *cp; +{ + Var *vp; + char *dbr_type_string; + extern char *prog_name; + int size, ev_flag; + + vp = cp->var; + switch (vp->type) + { + case V_SHORT: + dbr_type_string = "DBR_INT"; + size = sizeof(short); + break; + case V_INT: + dbr_type_string = "DBR_INT"; + size = sizeof(int); + break; + case V_CHAR: + dbr_type_string = "DBR_INT"; + size = sizeof(char); + break; + case V_FLOAT: + dbr_type_string = "DBR_FLOAT"; + size = sizeof(float); + break; + case V_DOUBLE: + dbr_type_string = "DBR_FLOAT"; + size = sizeof(double); + break; + case V_STRING: + dbr_type_string = "DBR_STRING"; + size = sizeof(char); + break; + } + /* fill in the CHAN structure */ + printf("\t\"%s\"", cp->db_name);/* unexpanded db channel name */ + + printf(", (char *) 0"); /* ch'l name after macro expansion */ + + printf(", (chid)0"); /* reserve place for chid */ + + if (vp->type == V_STRING) + printf(", %s", vp->name); /* variable ptr */ + else + printf(", &%s", vp->name); /* variable ptr */ + if (vp->length != 0) + printf("[%d]", cp->offset); /* array offset */ + + printf(", %d", size); /* element size (bytes) */ + + printf(",\n\t %s", dbr_type_string);/* DB request conversion type */ + + printf(", %d", vp->length); /* array length (of the variable) */ + + printf(", %d", cp->mon_flag); /* monitor flag */ + + printf(", %d", cp->length); /* count for db requests */ + + printf(", %g", cp->delta); /* monitor delta */ + + printf(", %g", cp->timeout); /* monitor timeout */ + + printf(", &%s", prog_name); /* ptr to state program structure */ + + vp = cp->ef_var; + if (vp == 0) + ev_flag = 0; + else + ev_flag = 1 << vp->ef_num; + printf(", %d", ev_flag); /* sync event flag */ + + return; +} + +/* Generate structure and data for state blocks (STATE) */ +gen_state_blocks() +{ + extern LIST ss_list; + StateSet *ssp; + State *sp; + int nstates; + + printf("\n/* State Blocks */\n"); + printf("/* action_func, event_func, delay_func, event_flag_mask"); + printf(", *delay, *name */\n"); + + for (ssp = firstSS(&ss_list); ssp != NULL; ssp = nextSS(ssp)) + { + printf("\nstatic STATE state_%s[] = {\n", ssp->ss_name); + nstates = 0; + for (sp = firstState(&ssp->S_list); sp != NULL; sp = nextState(sp)) + { + if (nstates > 0) + printf(",\n\n"); + nstates++; + fill_state_block(sp, ssp->ss_name); + } + printf("\n};\n"); + } + return; +} + +/* Fill in data for a the state block */ +fill_state_block(sp, ss_name) +State *sp; +char *ss_name; +{ + printf("\t/* State \"%s\"*/\n", sp->state_name); + + printf("\ta_%s_%s,\t/* action_function */\n", ss_name, sp->state_name); + + printf("\te_%s_%s,\t/* event_function */\n", ss_name, sp->state_name); + + printf("\td_%s_%s,\t/* delay_function */\n", ss_name, sp->state_name); + + printf("\t%d,\t/* event_flag_mask */\n", sp->event_flag_mask); + + printf("\t\"%s\"\t/* *name */", sp->state_name); + + return; +} + +/* Generate a state set control block (SSCB) for each state set */ +gen_sscb_array() +{ + extern LIST ss_list; + StateSet *ssp; + int nss, nstates, n; + + printf("\n/* State Set Control Blocks */\n"); + printf("static SSCB sscb[NUM_SS] = {\n"); + nss = 0; + for (ssp = firstSS(&ss_list); ssp != NULL; ssp = nextSS(ssp)) + { + if (nss > 0) + printf(",\n\n"); + nss++; + nstates = lstCount((NODE *)&ssp->S_list); + + printf("\t/* State set \"%s\"*/\n", ssp->ss_name); + + printf("\t0, 1, 0,\t/* task_id, task_prioity, sem_id */\n"); + + printf("\t0, 0,\t\t/* event_flag, event_flag_mask */\n"); + + printf("\t%d, state_%s,\t/* num_states, *states */\n", nstates, + ssp->ss_name); + + printf("\tNULL, NULL,\t/* *current_state, *next_state */\n"); + + printf("\t0, FALSE,\t/* trans_number, action_complete */\n"); + + printf("\t%d,\t/* number of time-out structures */\n", ssp->ndelay); + + printf("\t/* array of time-out values: */\n\t"); + for (n = 0; n < MAX_NDELAY; n++) + printf("0,"); + printf("\n"); + + printf("\t0,\t/* time (ticks) when state was entered */\n"); + + printf("\t\"%s\"\t\t/* ss_name */", ssp->ss_name); + } + printf("\n};\n"); + return; +} + +/* Returns number of db channels defined & inserts index into each channel struct */ +db_chan_count() +{ + extern LIST var_list; + int nchan; + Chan *cp; + + nchan = 0; + for (cp = firstChan(&chan_list); cp != NULL; cp = nextChan(cp)) + { + if (cp->db_name != NULL) + { + cp->index = nchan; + nchan++; + } + } + return nchan; +} + + +/* Given a state name and state set struct, find the corresponding + state struct and return its index (1-st one is 0) */ +state_block_index_from_name(ssp, state_name) +StateSet *ssp; +char *state_name; +{ + State *sp; + int index; + + index = 0; + for (sp = firstState(&ssp->S_list); sp != NULL; sp = nextState(sp)) + { + if (strcmp(state_name, sp->state_name) == 0) + return index; + index++; + } + return -1; /* State name non-existant */ +} + +/* Assign bits to event flags */ +assign_ef_bits() +{ + extern LIST var_list; + Var *vp; + int ef_num; + + ef_num = 0; + printf("\n/* Event flags */\n"); + for (vp = firstVar(&var_list); vp != NULL; vp = nextVar(vp)) + { + if (vp->type == V_EVFLAG) + { + vp->ef_num = ef_num; + printf("#define %s (1<<%d)\n", vp->name, ef_num); + ef_num++; + } + } + return; +} diff --git a/src/sequencer/seq_ca.c b/src/sequencer/seq_ca.c new file mode 100644 index 000000000..868ff3e13 --- /dev/null +++ b/src/sequencer/seq_ca.c @@ -0,0 +1,152 @@ +/************************************************************************** + GTA PROJECT AT division + Copyright, 1990, The Regents of the University of California. + Los Alamos National Laboratory + + @(#)seq_ca.c 1.7 2/4/91 + DESCRIPTION: Seq_ca.c: Channel access interface for sequencer + + ENVIRONMENT: VxWorks +***************************************************************************/ + +#include "seq.h" +#include "vxWorks.h" +#include "taskLib.h" + +#define MACRO_STR_LEN (MAX_STRING_SIZE+1) + +/* Connect to the database channels through channel access */ +connect_db_channels(sp_ptr, macro_tbl) +SPROG *sp_ptr; +struct macro *macro_tbl; +{ + CHAN *db_ptr; + int status, i; + + /* Initialize CA task */ + ca_task_initialize(); + + /* Search for all channels */ + db_ptr = sp_ptr->channels; + for (i = 0; i < sp_ptr->nchan; i++) + { + /* Do macro substitution */ + db_ptr->db_name = seqAlloc(MACRO_STR_LEN); + macEval(db_ptr->db_uname, db_ptr->db_name, MACRO_STR_LEN, + macro_tbl); + printf(" %d: %s\n", i, db_ptr->db_name); + status = ca_search(db_ptr->db_name, &(db_ptr->chid)); + if (status != ECA_NORMAL) + { + SEVCHK(status, "ca_search"); + ca_task_exit(); + return -1; + } + db_ptr++; + } + + /* Wait for returns from "ca_search" */ + status = ca_pend_io(10.0); + if (status != ECA_NORMAL) + { + SEVCHK(status, "ca_pend_io"); + return -1; + } +#ifdef DEBUG + db_ptr = sp_ptr->channels; + for (i = 0; i < sp_ptr->nchan; i++) + { + printf("\"%s\" ca_search() returned: chid=0x%x\n", + db_ptr->db_name, db_ptr->chid); + db_ptr++; + } +#endif + printf("All db channels connected\n"); + return 0; +} + /* Issue monitor requests */ +issue_monitor_requests(sp_ptr) +SPROG *sp_ptr; +{ + CHAN *db_ptr; + int status, i; + int seq_event_handler(); + + db_ptr = sp_ptr->channels; + for (i = 0; i < sp_ptr->nchan; i++) + { + if (db_ptr->mon_flag) + { + status = ca_add_general_event( + db_ptr->dbr_type, /* requested type */ + db_ptr->chid, /* chid */ + seq_event_handler, /* function to call */ + db_ptr, /* user arg is db entry */ + db_ptr->delta, /* pos. delta value */ + db_ptr->delta, /* neg. delta value */ + db_ptr->timeout, /* timeout */ + 0 /* no event id */); + if (status != ECA_NORMAL) + { + SEVCHK(status, "ca_search"); + ca_task_exit(); + return -1; + } + } + db_ptr++; + } + ca_flush_io(); + + return 0; +} + /* Channel access events (monitors) come here */ +seq_event_handler(args) +struct event_handler_args args; +{ + SPROG *sp_ptr; + SSCB *ss_ptr; + CHAN *db_ptr; + int i, nbytes, count; + int nss; + + /* User arg is ptr to db channel structure */ + db_ptr = (CHAN *)args.usr; + /* Copy value returned into user variable */ + count = db_ptr->count; + if (count == 0) + count = 1; + nbytes = db_ptr->size * count; + bcopy(args.dbr, db_ptr->var, nbytes); +#ifdef DEBUG + printf("seq_event_handler: "); + if (db_ptr->dbr_type == DBR_FLOAT) + printf("%s=%g\n", db_ptr->db_name, *(float *)db_ptr->var); + else if (db_ptr->dbr_type == DBR_INT) + { + i = *(short *)args.dbr; + printf("%s=%d\n", db_ptr->db_name, i); + } + else + printf("?\n"); +#endif DEBUG + + /* Process event handling in each state set */ + sp_ptr = db_ptr->sprog; /* State program that owns this db entry */ + + /* Set synchronization event flag (if it exists) for each state set */ + if (db_ptr->ev_flag != 0) + seq_efSet(sp_ptr, 0, db_ptr->ev_flag); + + /* Wake up each state set that is waiting for event processing */ + ss_ptr = sp_ptr->sscb; + for (nss = 0; nss < sp_ptr->nss; nss++, ss_ptr++) + { + if (ss_ptr->action_complete) + { + semGive(ss_ptr->sem_id); + } + } + + return 0; +} + diff --git a/src/sequencer/seq_mac.c b/src/sequencer/seq_mac.c new file mode 100644 index 000000000..daf4a84d0 --- /dev/null +++ b/src/sequencer/seq_mac.c @@ -0,0 +1,288 @@ +/************************************************************************** + GTA PROJECT AT division + Copyright, 1990, The Regents of the University of California. + Los Alamos National Laboratory + + @(#)seq_mac.c 1.1 11/9/90 + DESCRIPTION: Macro routines for Sequencer. + + ENVIRONMENT: VxWorks +***************************************************************************/ +#include +#include +#include "vxWorks.h" +#include "seq.h" + +LOCAL int macNameLth(); +LOCAL int macParseName(); +LOCAL int macParseValue(); +LOCAL char *skipBlanks(); + + + +/* #define DEBUG */ + +/* macTblInit - initialize macro table */ +macTblInit(mac_ptr) +MACRO *mac_ptr; +{ + int i; + + for (i = 0 ; i < MAX_MACROS; i++, mac_ptr++) + { + mac_ptr->name = NULL; + mac_ptr->value = NULL; + } +} + + /* macEval - substitute macro value into a string */ +macEval(pInStr, pOutStr, maxChar, macTbl) +char *pInStr; +char *pOutStr; +MACRO *macTbl; +{ + char *pMacVal, *pTmp; + int nameLth, valLth; + +#ifdef DEBUG + printf("macEval: InStr=%s\n", pInStr); +#endif + pTmp = pOutStr; + while (*pInStr != 0 && maxChar > 0) + { + if (*pInStr == '{') + { /* Macro substitution */ + pInStr++; /* points to macro name */ + nameLth = macNameLth(pInStr); +#ifdef DEBUG + printf("Name=%s[%d]\n", pInStr, nameLth); +#endif + /* Find macro value from macro name */ + pMacVal = macValGet(pInStr, nameLth, macTbl); + if (pMacVal != NULL) + { /* Substitute macro value */ + valLth = strlen(pMacVal); + if (valLth > maxChar) + valLth = maxChar; +#ifdef DEBUG + printf("Val=%s[%d]\n", pMacVal, valLth); +#endif + strncpy(pOutStr, pMacVal, valLth); + maxChar -= valLth; + pOutStr += valLth; + } + pInStr += nameLth; + if (*pInStr != 0) + pInStr++; /* skip '}' */ + + } + else + { /* Straight susbstitution */ + *pOutStr++ = *pInStr++; + maxChar--; + } + *pOutStr = 0; +#ifdef DEBUG + printf("OutStr=%s\n", pTmp); +#endif + } + *pOutStr == 0; +} + +/* macValGet - given macro name, return pointer to its value */ +char *macValGet(macName, macNameLth, macTbl) +char *macName; +int macNameLth; +MACRO *macTbl; +{ + int i; + + for (i = 0 ; i < MAX_MACROS; i++, macTbl++) + { + if ((macTbl->name != NULL) && + (strlen(macTbl->name) == macNameLth)) + { + if (strncmp(macName, macTbl->name, macNameLth) == 0) + { + return macTbl->value; + } + } + } + return NULL; +} + +/* Return number of characters in a macro name */ +LOCAL int macNameLth(pstr) +char *pstr; +{ + int nchar; + + nchar = 0; + while ( (*pstr != 0) && (*pstr != '}') ) + { + pstr++; + nchar++; + } + return nchar; +} + /* macParse - parse the macro definition string and build +the macro table (name/value pairs). Returns number of macros parsed. +Assumes the table may already contain entries (values may be changed). +String for name and value are allocated dynamically from pool. +*/ +int macParse(pMacStr, macTbl) +char *pMacStr; /* macro definition string */ +MACRO *macTbl; /* macro table */ +{ + int nMac, nChar; + char *skipBlanks(); + MACRO *pMacTbl; + char *name, *value; + + for ( ;; ) + { + /* Skip blanks */ + pMacStr = skipBlanks(pMacStr); + + /* Parse the macro name */ + + nChar = macParseName(pMacStr); + if (nChar == 0) + break; /* finished or error */ + name = seqAlloc(nChar+1); + if (name == NULL) + break; + bcopy(pMacStr, name, nChar); + name[nChar] = 0; +#ifdef DEBUG + printf("name=%s, nChar=%d\n", name, nChar); +#endif + pMacStr += nChar; + + /* Find a slot in the table */ + pMacTbl = macTblGet(name, macTbl); + if (pMacTbl == NULL) + break; /* table is full */ + if (pMacTbl->name == NULL) + { /* Empty slot, insert macro name */ + pMacTbl->name = name; + } + + /* Skip over blanks and equal sign or comma */ + pMacStr = skipBlanks(pMacStr); + if (*pMacStr == ',') + { /* no value after the macro name */ + pMacStr++; + continue; + } + if (*pMacStr++ != '=') + break; + pMacStr = skipBlanks(pMacStr); + + /* Parse the value */ + nChar = macParseValue(pMacStr); + if (nChar == 0) + break; + value = seqAlloc(nChar+1); + if (value == NULL) + break; + bcopy(pMacStr, value, nChar); + value[nChar] = 0; + pMacStr += nChar; +#ifdef DEBUG + printf("value=%s, nChar=%d\n", value, nChar); +#endif + + /* Insert or replace macro value */ + pMacTbl->value = value; + + /* Skip blanks and comma */ + pMacStr = skipBlanks(pMacStr); + if (*pMacStr++ != ',') + break; + } + if (*pMacStr == 0) + return 0; + else + return -1; +} + + +LOCAL int macParseName(pStr) +char *pStr; +{ + int nChar; + + /* First character must be [A-Z,a-z] */ + if (!isalpha(*pStr)) + return 0; + pStr++; + nChar = 1; + /* Character must be [A-Z,a-z,0-9,_] */ + while ( isalnum(*pStr) || *pStr == '_' ) + { + pStr++; + nChar++; + } + /* Loop terminates on any non-name character */ + return nChar; +} + +LOCAL int macParseValue(pStr) +char *pStr; +{ + int nChar; + + nChar = 0; + /* Character string terminates on blank, comma, or EOS */ + while ( (*pStr != ' ') && (*pStr != ',') && (*pStr != 0) ) + { + pStr++; + nChar++; + } + return nChar; +} + +LOCAL char *skipBlanks(pChar) +char *pChar; +{ + while (*pChar == ' ') + pChar++; + return pChar; +} + +/* macTblGet - find a match for the specified name, otherwise +return an empty slot in macro table */ +LOCAL MACRO *macTblGet(name, macTbl) +char *name; /* macro name */ +MACRO *macTbl; +{ + int i; + MACRO *pMacTbl; + +#ifdef DEBUG + printf("macTblGet: name=%s\n", name); +#endif + for (i = 0, pMacTbl = macTbl; i < MAX_MACROS; i++, pMacTbl++) + { + if (pMacTbl->name != NULL) + { + if (strcmp(name, pMacTbl->name) == 0) + { + return pMacTbl; + } + } + } + + /* Not found, find an empty slot */ + for (i = 0, pMacTbl = macTbl; i < MAX_MACROS; i++, pMacTbl++) + { + if (pMacTbl->name == NULL) + { + return pMacTbl; + } + } + + /* No empty slots available */ + return NULL; +} diff --git a/src/sequencer/seq_main.c b/src/sequencer/seq_main.c new file mode 100644 index 000000000..d0922affa --- /dev/null +++ b/src/sequencer/seq_main.c @@ -0,0 +1,420 @@ +/************************************************************************** + GTA PROJECT AT division + Copyright, 1990, The Regents of the University of California. + Los Alamos National Laboratory + + @(#)seq.c 1.8 2/1/91 + DESCRIPTION: Seq() initiates a sequence as a group of cooperating + tasks. An optional string parameter specifies the values for + macros. + + ENVIRONMENT: VxWorks +***************************************************************************/ + +/* #define DEBUG 1 */ + +#include "seq.h" +#include "vxWorks.h" +#include "taskLib.h" + +#define SCRATCH_SIZE (MAX_MACROS*(MAX_STRING_SIZE+1)*12) + +/* The following variable points to the area allocated for the + parent state program and its corresponding state sets. + It is declared a "task variable" and is shared by only these + tasks. + It is also used as a flag to indicate that the "taskDeleteHookAdd()" + routine has been called (we only want to do that once after VxWorks boots). +*/ + + +LOCAL TASK *alloc_task_area(); +LOCAL count_states(); +LOCAL copy_sprog(); +LOCAL init_sprog(); +LOCAL init_sscb(); + + + +TASK *task_area_ptr = NULL; + +/* User entry routine to initiate a state program */ +seq(sp_ptr, macro_def, stack_size) +SPROG *sp_ptr; /* ptr to state program table */ +char *macro_def; /* macro def'n string */ +int stack_size; /* stack size */ +{ + int status; + extern sequencer(), sprog_delete(); + extern char *seqVersion; + + /* If no parameters specified, print version info. */ + if (sp_ptr == 0) + { + printf("%s\n", seqVersion); + return 0; + } + + /* Check for correct state program format */ + if (sp_ptr->magic != MAGIC) + { /* Oops */ + printf("Illegal magic number in state program\n"); + return -1; + } + + /* Specify a routine to run at task delete */ + if (task_area_ptr == NULL) + { + taskDeleteHookAdd(sprog_delete); + task_area_ptr = (TASK *)ERROR; + } + + /* Specify stack size */ + if (stack_size < SPAWN_STACK_SIZE) + stack_size = SPAWN_STACK_SIZE; + + /* Spawn the sequencer main task */ + printf("Spawning state program \"%s\"\n", sp_ptr->name); + status = taskSpawn(sp_ptr->name, SPAWN_PRIORITY, + SPAWN_OPTIONS, stack_size, + sequencer, sp_ptr, macro_def, stack_size); + return status; +} + /* Sequencer main task entry point */ +sequencer(sp_ptr_orig, macro_def, stack_size) +SPROG *sp_ptr_orig; /* ptr to original (global) state program table */ +char *macro_def; /* macro def'n string */ +int stack_size; /* stack size */ +{ + int tid, nmac, nss, nstates, nchannels, user_size; + TASK *alloc_task_area(); + extern TASK *task_area_ptr; + SPROG *sp_ptr; + MACRO *mac_ptr; + char macroTmp[100]; /* for macro names & values */ + + tid = taskIdSelf(); /* my task id */ + + /* Allocate a contiguous space for all task structures */ + task_area_ptr = alloc_task_area(sp_ptr_orig); +#ifdef DEBUG + printf("task_area_ptr=%d, *task_area_ptr=%d\n", task_area_ptr, *task_area_ptr); +#endif DEBUG + + /* Make "task_area_ptr" a task variable */ + if (taskVarAdd(tid, &task_area_ptr) != OK) + { + printf("taskVarAdd failed\n"); + return -1; + } + + sp_ptr_orig->task_id = tid; + sp_ptr = task_area_ptr->sp_ptr; + mac_ptr = task_area_ptr->mac_ptr; + + /* Make a private copy of original structures (but change pointers!) */ + copy_sprog(sp_ptr_orig, task_area_ptr); + + /* Initialize state program block */ + init_sprog(sp_ptr); + + /* Initialize state set control blocks */ + init_sscb(sp_ptr); + + /* Initialize the macro definition table */ + macTblInit(mac_ptr); /* Init macro table */ + + /* Parse the macro definitions */ + macParse(macro_def, mac_ptr); + + /* Connect to DB channels */ + connect_db_channels(sp_ptr, mac_ptr); + + /* Issue monitor requests */ + issue_monitor_requests(sp_ptr); + + /* Create the state set tasks */ + create_ss_tasks(sp_ptr, stack_size); + + /* Note: No return from task */ +} + /* Allocate the task area. This area will hold all state program structures: + |***************| + | TASK |---| + |***************| | + | SPROG | | + |***************| V Ptrs to start of SPROG, SSCB[0], STATE[0], + | SSCB [0] | USER AREA, and SCRATCH AREA + |***************| + | SSCB [1] | + |***************| + | ..... [n] | + |***************| + | STATE [0] | + |***************| + | STATE [1] | + |***************| + | ..... [n] | + |***************| + | USER AREA | - user variables (a structure) + |***************| + | MACRO TBL | + |***************| + | SCRATCH AREA | - for parsing channel names + |***************| + + + The pointer to the allocated area is saved for task delete hook routine. +*/ +LOCAL TASK *alloc_task_area(sp_ptr_orig) +SPROG *sp_ptr_orig; /* original state program area */ +{ + int size, nss, nstates, nchannels, user_size, mac_size, scr_size; + TASK *ta_ptr; /* ptr to task area */ + + /* Calc. size of task area */ + nss = sp_ptr_orig->nss; + nstates = count_states(sp_ptr_orig); + nchannels = sp_ptr_orig->nchan; + user_size = sp_ptr_orig->user_size; + mac_size = MAX_MACROS*sizeof(MACRO); + scr_size = SCRATCH_SIZE; + size = sizeof(TASK) + sizeof(SPROG) + nss*sizeof(SSCB) + + nstates*sizeof(STATE) + nchannels*sizeof(CHAN) + user_size + + mac_size + scr_size; +#ifdef DEBUG + printf("nss=%d, nstates=%d, nchannels=%d, user_size=%d, scr_size=%d\n", + nss, nstates, nchannels, user_size, scr_size); + printf("sizes: SPROG=%d, SSCB=%d, STATE=%d, CHAN=%d\n", + sizeof(SPROG), sizeof(SSCB), sizeof(STATE), sizeof(CHAN)); +#endif DEBUG + /* Alloc the task area & set up pointers */ + ta_ptr = (TASK *)malloc(size); + ta_ptr->task_area_size = size; + ta_ptr->sp_ptr = (SPROG *)(ta_ptr + 1); + ta_ptr->ss_ptr = (SSCB *)(ta_ptr->sp_ptr+1); + ta_ptr->st_ptr = (STATE *)(ta_ptr->ss_ptr + nss); + ta_ptr->db_ptr = (CHAN *)(ta_ptr->st_ptr + nstates); + ta_ptr->user_ptr = (char *)(ta_ptr->db_ptr + nchannels); + ta_ptr->mac_ptr = (MACRO *)ta_ptr->user_ptr + user_size; + ta_ptr->scr_ptr = (char *)ta_ptr->mac_ptr + mac_size; + ta_ptr->scr_nleft = scr_size; +#ifdef DEBUG + printf("ta_ptr=%d, size=%d\n", ta_ptr, size); + printf("sp_ptr=%d, ss_ptr=%d, st_ptr=%d, db_ptr=%d, user_ptr=%d\n", + ta_ptr->sp_ptr, ta_ptr->ss_ptr, ta_ptr->st_ptr, ta_ptr->db_ptr, ta_ptr->user_ptr); + printf("scr_ptr=%d, scr_nleft=%d\n", ta_ptr->scr_ptr, ta_ptr->nleft); +#endif DEBUG + + return ta_ptr; +} + +/* Count the total number of states in ALL state sets */ +LOCAL count_states(sp_ptr) +SPROG *sp_ptr; +{ + SSCB *ss_ptr; + int nss, nstates; + + nstates = 0; + ss_ptr = sp_ptr->sscb; + for (nss = 0; nss < sp_ptr->nss; nss++, ss_ptr++) + { + nstates += ss_ptr->num_states; + } + return nstates; +} + /* Copy the SPROG, SSCB, STATE, and CHAN structures into this task. +Note: we have to change the pointers in the SPROG struct and all SSCB structs */ +LOCAL copy_sprog(sp_ptr_orig, ta_ptr) +TASK *ta_ptr; +SPROG *sp_ptr_orig; +{ + SPROG *sp_ptr; + SSCB *ss_ptr, *ss_ptr_orig; + STATE *st_ptr, *st_ptr_orig; + CHAN *db_ptr, *db_ptr_orig; + int nss, nstates, nchan; + + sp_ptr = ta_ptr->sp_ptr; + + /* Copy the entire SPROG struct */ + *sp_ptr = *sp_ptr_orig; + /* Ptr to 1-st SSCB in original SPROG */ + ss_ptr_orig = sp_ptr_orig->sscb; + /* Ptr to 1-st SSCB in new SPROG */ + ss_ptr = ta_ptr->ss_ptr; + sp_ptr->sscb = ss_ptr; /* Fix ptr to 1-st SSCB */ + st_ptr = ta_ptr->st_ptr; + + /* Copy structures for each state set */ + for (nss = 0; nss < sp_ptr->nss; nss++) + { + *ss_ptr = *ss_ptr_orig; /* copy SSCB */ + ss_ptr->states = st_ptr; /* new ptr to 1-st STATE */ + st_ptr_orig = ss_ptr_orig->states; + for (nstates = 0; nstates < ss_ptr->num_states; nstates++) + { + *st_ptr++ = *st_ptr_orig++; /* copy STATE struct */ + } + ss_ptr++; + ss_ptr_orig++; + } + + /* Copy database channel structures */ + db_ptr = ta_ptr->db_ptr; + sp_ptr->channels = db_ptr; + db_ptr_orig = sp_ptr_orig->channels; + for (nchan = 0; nchan < sp_ptr->nchan; nchan++) + { + *db_ptr = *db_ptr_orig; + db_ptr->sprog = sp_ptr; + db_ptr++; + db_ptr_orig++; + } + + return 0; +} + /* Initialize state program block */ +LOCAL init_sprog(sp_ptr) +SPROG *sp_ptr; +{ + sp_ptr->sem_id = semCreate(); + semInit(sp_ptr->sem_id); + sp_ptr->task_is_deleted = FALSE; + + return; +} + +/* Initialize state set control blocks */ +LOCAL init_sscb(sp_ptr) +SPROG *sp_ptr; +{ + SSCB *ss_ptr; + STATE *st_ptr; + int nss; + char task_name[20]; + + ss_ptr = sp_ptr->sscb; + for (nss = 0; nss < sp_ptr->nss; nss++, ss_ptr++) + { + st_ptr = ss_ptr->states; /* 1-st state */ + ss_ptr->task_id = 0; + ss_ptr->sem_id = semCreate(); + semInit(ss_ptr->sem_id); + semGive(ss_ptr->sem_id); + ss_ptr->ev_flag = 0; + ss_ptr->ev_flag_mask = st_ptr->event_flag_mask; + ss_ptr->current_state = st_ptr; /* initial state */ + ss_ptr->next_state = NULL; + ss_ptr->action_complete = TRUE; + } + return 0; +} + /* Get DB value (uses channel access) */ +seq_pvGet(sp_ptr, ss_ptr, db_ptr) +SPROG *sp_ptr; /* ptr to state program */ +SSCB *ss_ptr; /* ptr to current state set */ +CHAN *db_ptr; /* ptr to channel struct */ +{ + int status; + + ca_array_get(db_ptr->dbr_type, db_ptr->count, db_ptr->chid, db_ptr->var); + /********** In this version we wait for each db_get() **********/ + status = ca_pend_io(10.0); + if (status != ECA_NORMAL) + { + printf("time-out: db_get() on %s\n", db_ptr->db_name); + return -1; + } + /********** We should have an event handler for this call ************/ + /********** Then we could use event flags on "db_get" calls **********/ + return 0; +} + +/* Put DB value (uses channel access) */ +seq_pvPut(sp_ptr, ss_ptr, db_ptr) +SPROG *sp_ptr; /* ptr to state program */ +SSCB *ss_ptr; /* ptr to current state set */ +CHAN *db_ptr; /* ptr to channel struct */ +{ + int status; + + status = ca_array_put(db_ptr->dbr_type, db_ptr->count, + db_ptr->chid, db_ptr->var); + if (status != ECA_NORMAL) + { + SEVCHK(status, "ca_array_put"); + return -1; + } + ca_flush_io(); +} + /* Set event flag bits for each state set */ +seq_efSet(sp_ptr, ss_ptr, ev_flag) +SPROG *sp_ptr; /* state program where ev flags are to be set */ +SSCB *ss_ptr; /* not currently used */ +int ev_flag; /* bits to set */ +{ + int nss; + SSCB *ssp; + EVFLAG ev_flag_chk; + +#ifdef DEBUG + char *name; + name = "?"; + if (ss_ptr != NULL) + name = ss_ptr->name; + printf("seq_efSet: bits 0x%x from ss %s\n", ev_flag, name); +#endif + + ssp = sp_ptr->sscb; /* 1-st state set */ + for (nss = 0; nss < sp_ptr->nss; nss++, ssp++) + { /********** need some resource locking here ***************/ + /* Set event flag only if "action" is complete */ + if (ssp->action_complete) + { /* Only set ev flag if contained in mask & bit(s) get set */ + ev_flag_chk = (ev_flag & ssp->ev_flag_mask) | ssp->ev_flag; + if (ev_flag_chk != ssp->ev_flag) /* did bit get set? */ + { /* set the bit(s) & wake up the ss task */ + ssp->ev_flag = ev_flag_chk; + semGive(ssp->sem_id); + } + } + } + return; +} + +/* Test event flag for matching bits */ +seq_efTest(sp_ptr, ss_ptr, ev_flag) +SPROG *sp_ptr; +SSCB *ss_ptr; +int ev_flag; /* bit(s) to test */ +{ + int nss; + SSCB *ssp; + + if ( (ss_ptr->ev_flag & ev_flag) != 0 ) + return TRUE; + return FALSE; +} + +/* Allocate memory from scratch area (always round up to even no. bytes) */ +char *seqAlloc(nChar) +int nChar; +{ + char *pStr; + extern TASK *task_area_ptr; + + pStr = task_area_ptr->scr_ptr; + /* round to even no. bytes */ + if ((nChar & 1) != 0) + nChar++; + if (task_area_ptr->scr_nleft >= nChar) + { + task_area_ptr->scr_ptr += nChar; + task_area_ptr->scr_nleft -= nChar; + return pStr; + } + else + return NULL; +} diff --git a/src/sequencer/seq_qry.c b/src/sequencer/seq_qry.c new file mode 100644 index 000000000..b4a1c36ef --- /dev/null +++ b/src/sequencer/seq_qry.c @@ -0,0 +1,91 @@ +/************************************************************************** + GTA PROJECT AT division + Copyright, 1990, The Regents of the University of California. + Los Alamos National Laboratory + + @(#)seq_qry.c 1.3 11/9/90 + DESCRIPTION: Task querry & debug routines for run-time sequencer + + ENVIRONMENT: VxWorks +***************************************************************************/ + +/* #define DEBUG 1 */ + +#include "seq.h" +#include "vxWorks.h" +#include "taskLib.h" + +/* querry the sequencer */ +seqQry(tid) +int tid; +{ + extern TASK *task_area_ptr; + TASK *ta_ptr; + SPROG *sp_ptr; + SSCB *ss_ptr; + STATE *st_ptr; + CHAN *db_ptr; + int nss, nst, nch; + float time; + + ta_ptr = (TASK *)taskVarGet(tid, &task_area_ptr); /* task_area_ptr is task variable */ + sp_ptr = ta_ptr->sp_ptr; + if (sp_ptr->magic != MAGIC) + { + printf("tqry: wrong magic number\n"); + return -1; + } + /* Print info about state program */ + printf("State Program: \"%s\"\n", sp_ptr->name); + printf(" ta_ptr=%d=0x%x\n", ta_ptr, ta_ptr); + printf(" sp_ptr=%d=0x%x\n", sp_ptr, sp_ptr); + + ss_ptr = sp_ptr->sscb; + for (nss = 0; nss < sp_ptr->nss; nss++, ss_ptr++) + { + printf(" State Set: \"%s\"\n", ss_ptr->name); + printf("\tss_ptr=%d=0x%x\n", ss_ptr, ss_ptr); + st_ptr = ss_ptr->current_state; + if (st_ptr != NULL) { + printf("\tcurrent state: \"%s\"\n", st_ptr->name); + } + time = ss_ptr->time/60.0; + printf("\ttime state was entered=%d tics (%g seconds)\n", + ss_ptr->time, time); + st_ptr = ss_ptr->next_state; + printf("\tevent flag=%d\n", ss_ptr->ev_flag); + printf("\tevent flag mask=0x%x\n", ss_ptr->ev_flag_mask); + printf("\tnumer delays queued=%d\n", ss_ptr->ndelay); + if (st_ptr != NULL) + printf("\tnext state: \"%s\"\n", st_ptr->name); + } + wait_rtn(); + + /* Print info about db channels */ + db_ptr = sp_ptr->channels; + for (nch = 0; nch < sp_ptr->nchan; nch++, db_ptr++) + { + printf("\nChannel name: \"%s\"\n", db_ptr->db_name); + printf(" unexpanded name: \"%s\"\n", db_ptr->db_uname); + printf(" size=%d bytes\n", db_ptr->size); + printf(" length=%d elements\n", db_ptr->length); + printf(" DB request type=%d\n", db_ptr->dbr_type); + printf(" monitor flag=%d\n", db_ptr->mon_flag); + printf(" count=%d\n", db_ptr->count); + printf(" event flag=%d=0x%x\n", db_ptr->ev_flag, db_ptr->ev_flag); + printf(" delta=%g\n", db_ptr->delta); + printf(" timeout=%g\n", db_ptr->timeout); + wait_rtn(); + } + + return 0; +} + +wait_rtn() +{ + char bfr; + printf("Hit RETURN to continue\n"); + do { + read(STD_IN, &bfr, 1); + } while (bfr != '\n'); +} diff --git a/src/sequencer/seq_task.c b/src/sequencer/seq_task.c new file mode 100644 index 000000000..739568e0b --- /dev/null +++ b/src/sequencer/seq_task.c @@ -0,0 +1,245 @@ +/************************************************************************** + GTA PROJECT AT division + Copyright, 1990, The Regents of the University of California. + Los Alamos National Laboratory + + @(#)seq_task.c 1.4 2/1/91 + DESCRIPTION: Seq_tasks.c: Task creation and control for sequencer + state sets. + + ENVIRONMENT: VxWorks +***************************************************************************/ + +#include "seq.h" +#include "vxWorks.h" +#include "taskLib.h" + + +LOCAL ss_task_init(); +LOCAL ULONG get_timeout(); +LOCAL VOID semTake(); + + +extern TASK *task_area_ptr; + +/* Create state set tasks. Set task variable for each task */ +#define TASK_NAME_SIZE 25 +create_ss_tasks(sp_ptr, stack_size) +SPROG *sp_ptr; +int stack_size; +{ + SSCB *ss_ptr; + int nss; + char task_name[2*TASK_NAME_SIZE+2]; + extern TASK *task_area_ptr; + extern ss_entry(); + + ss_ptr = sp_ptr->sscb; + task_name[0] = 0; + strncat(task_name, sp_ptr->name, TASK_NAME_SIZE); + strcat(task_name, "_"); + + for (nss = 0; nss < sp_ptr->nss; nss++, ss_ptr++) + { + if (nss != 0) + { /* Spawn the ss task */ + /* Form task name from program name + state set name */ + strncat(task_name, ss_ptr->name, TASK_NAME_SIZE); + + ss_ptr->task_id = taskSpawn(task_name, + SPAWN_PRIORITY+ss_ptr->task_priority, + SPAWN_OPTIONS, stack_size, ss_entry, sp_ptr, ss_ptr); +#ifdef DEBUG + printf("task %d: %s\n", ss_ptr->task_id, task_name); +#endif DEBUG + } + } + /* Main task handles first state set */ + ss_ptr = sp_ptr->sscb; + ss_ptr->task_id = sp_ptr->task_id; + ss_entry(sp_ptr, ss_ptr); +} + /* Task entry point for state sets */ +/* Provides main loop for state set processing (common, re-entrant code) */ +ss_entry(sp_ptr, ss_ptr) +SPROG *sp_ptr; +SSCB *ss_ptr; +{ + BOOL ev_trig; + STATE *st_ptr; + ULONG delay, get_timeout(); + + /* Initialize all tasks except the main task */ + if (ss_ptr->task_id != sp_ptr->task_id) + ss_task_init(sp_ptr, ss_ptr); + + /* Start in first state */ + st_ptr = ss_ptr->current_state; + + /* Initialize for event flag processing */ + ss_ptr->ev_flag_mask = st_ptr->event_flag_mask; + ss_ptr->ev_flag = 0; + + /* Main loop */ + while (1) + { +#ifdef DEBUG + printf("State set %s, state %s\n", ss_ptr->name, st_ptr->name); +#endif DEBUG + ss_ptr->time = tickGet(); /* record time we entered this state */ + + /* Call delay function to set up delays */ + ss_ptr->ndelay = 0; + st_ptr->delay_func(sp_ptr, ss_ptr); + + /* On 1-st pass fall thru w/o wake up */ + semGive(ss_ptr->sem_id); + + /* Loop until an event is triggered */ + do { + /* Wake up on CA event, event flag, or expired time delay */ + semTake(ss_ptr->sem_id, get_timeout(ss_ptr, st_ptr)); +#ifdef DEBUG + printf("%s: semTake returned\n", ss_ptr->name); +#endif DEBUG + ss_ptr->time = tickGet(); + /* Call event function to check for event trigger */ + ev_trig = st_ptr->event_func(sp_ptr, ss_ptr); + } while (!ev_trig); + + /* Event triggered, execute the corresponding action */ + ss_ptr->action_complete = FALSE; + st_ptr->action_func(sp_ptr, ss_ptr); + + /* Change to next state */ + ss_ptr->current_state = ss_ptr->next_state; + ss_ptr->next_state = NULL; + st_ptr = ss_ptr->current_state; + ss_ptr->ev_flag_mask = st_ptr->event_flag_mask; + ss_ptr->ev_flag = 0; + ss_ptr->action_complete = TRUE; + } +} + /* Initialize state-set tasks */ +LOCAL ss_task_init(sp_ptr, ss_ptr) +SPROG *sp_ptr; +SSCB *ss_ptr; +{ + /* Import task variable context from main task */ + taskVarAdd(ss_ptr->task_id, &task_area_ptr); + taskVarGet(sp_ptr->task_id, &task_area_ptr); /* main task's id */ + + /* Import Channel Access context from main task */ + ca_import(sp_ptr->task_id); + + return; +} + /* Return time-out for semTake() */ +LOCAL ULONG get_timeout(ss_ptr) +SSCB *ss_ptr; +{ + int ndelay; + ULONG time, timeout, tmin; + + if (ss_ptr->ndelay == 0) + return 0; + + time = tickGet(); + tmin = 0; + /* find lowest timeout that's not expired */ + for (ndelay = 0; ndelay < ss_ptr->ndelay; ndelay++) + { + timeout = ss_ptr->timeout[ndelay]; + if (time < timeout) + { + if (tmin == 0 || timeout < tmin) + tmin = timeout; + } + } + if (tmin != 0) + tmin -= time; /* convert timeout to delay */ + return tmin; +} + /* Set-up for delay() on entering a state. This routine is called +by the state program for each delay in the "when" statement */ +VOID seq_start_delay(sp_ptr, ss_ptr, delay_id, delay) +SPROG *sp_ptr; +SSCB *ss_ptr; +int delay_id; /* delay id */ +float delay; +{ + ss_ptr->timeout[delay_id] = ss_ptr->time + delay*60.0; + delay_id += 1; + if (delay_id > ss_ptr->ndelay) + ss_ptr->ndelay = delay_id; + return; +} + +/* Test for time-out expired */ +BOOL seq_test_delay(sp_ptr, ss_ptr, delay_id) +SPROG *sp_ptr; +SSCB *ss_ptr; +int delay_id; +{ + return (ss_ptr->time >= ss_ptr->timeout[delay_id]); +} + /* This task is run whenever ANY task in the system is deleted */ +sprog_delete(pTcbX) +TCBX *pTcbX; /* ptr to TCB of task to be deleted */ +{ + int tid, nss, val, tid_ss; + SPROG *sp_ptr; + SSCB *ss_ptr; + extern TASK *task_area_ptr; + TASK *ta_ptr; + + tid = pTcbX->taskId; + /* Note: task_area_ptr is a task variable */ + val = taskVarGet(tid, &task_area_ptr); + if (val == ERROR) + return 0; /* not one of our tasks */ + ta_ptr = (TASK *)val; + printf(" ta_ptr=0x%x, tid=%d=0x%x\n", ta_ptr, tid, tid); + sp_ptr = ta_ptr->sp_ptr; + + /* Is this a real sequencer task? */ + if (sp_ptr->magic != MAGIC) + { + printf(" Not main state program task\n"); + return -1; + } + + /* Delete state set tasks */ + ss_ptr = sp_ptr->sscb; + for (nss = 0; nss < sp_ptr->nss; nss++, ss_ptr++) + { + tid_ss = ss_ptr->task_id; + if ( tid_ss > 0) + { + /* Don't delete self yet */ + if (tid != tid_ss) + { + printf(" delete ss task: tid=%d=0x%x\n", + tid_ss, tid_ss); + taskVarSet(tid_ss, &task_area_ptr, ERROR); + taskDelete(tid_ss); + } + } + } + + printf("free ta_ptr=0x%x\n", ta_ptr); + taskDelay(60); + free(ta_ptr); + + return 0; +} + /* semTake - take semaphore: + VxWorks semTake with timeout added. */ +LOCAL VOID semTake (semId, timeout) +SEM_ID semId; /* semaphore id to take */ +UINT timeout; /* timeout in tics */ +{ + int dummy; + + vrtxPend(&semId->count, timeout, &dummy); +} diff --git a/src/sequencer/snc.y b/src/sequencer/snc.y new file mode 100644 index 000000000..b86d5525a --- /dev/null +++ b/src/sequencer/snc.y @@ -0,0 +1,239 @@ +%{ +/************************************************************************** + GTA PROJECT AT division + Copyright, 1990, The Regents of the University of California. + Los Alamos National Laboratory + + @(#)snc.y 1.1 10/16/90 + ENVIRONMENT: UNIX +***************************************************************************/ +/* 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_lax.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 +#include +#include "parse.h" + +Expr *expression(); +Expr *parameter(); + +extern int line_num; /* input file line no. */ +%} + +%start state_program + +%union +{ + int ival; + char *pchar; + void *pval; + Expr *expr; +} +%token STATE STATE_SET +%token NUMBER NAME DBNAME +%token DEBUG_PRINT +%token PROGRAM DEFINE +%token R_SQ_BRACKET L_SQ_BRACKET +%token BAD_CHAR L_BRACKET R_BRACKET +%token COLON SEMI_COLON EQUAL +%token L_PAREN R_PAREN PERIOD COMMA OR AND +%token MONITOR ASSIGN TO WHEN INT FLOAT DOUBLE SHORT CHAR STRING_DECL +%token EVFLAG SYNC +%token ASTERISK AMPERSAND +%token PLUS MINUS SLASH GT GE EQ LE LT NE NOT +%token PLUS_EQUAL MINUS_EQUAL MULT_EQUAL DIV_EQUAL AND_EQUAL OR_EQUAL +%token STRING +%token C_STMT +%type type +%type subscript +%type parameter function expression +/* precidence rules for expression evaluation */ +%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 */ +: program_name definitions program_body { program(""); } +| program_name definitions program_body C_STMT { program($4); } +| error { snc_err("state program", line_num, 12); } +; + +program_name /* program name */ +: PROGRAM NAME { program_name($2, ""); } +| PROGRAM NAME L_PAREN STRING R_PAREN { program_name($2, $4); } +; + +definitions /* definitions block */ +: defn_stmt +| definitions defn_stmt +; + +defn_stmt /* individual definitions for SNL (preceeds state sets) */ +: assign_stmt +| monitor_stmt +| decl_stmt +| debug_stmt +| sync_stmt +| C_STMT { defn_c_stmt($1); } +| error { snc_err("definitions", line_num, 1); } +; + +assign_stmt /* 'assign [,] to ;' */ + /* subscript range is optional */ +: ASSIGN NAME TO STRING SEMI_COLON { assign_stmt($2, (char *)0, (char *)0, $4); } +| ASSIGN NAME L_SQ_BRACKET NUMBER R_SQ_BRACKET TO STRING SEMI_COLON + { assign_stmt($2, $4, (char *)0, $7); } +| ASSIGN NAME L_SQ_BRACKET NUMBER COMMA NUMBER R_SQ_BRACKET TO STRING SEMI_COLON + { assign_stmt($2, $4, $6, $9); } +; + +monitor_stmt /* variable to be monitored; subscript & delta are optional */ +: MONITOR NAME subscript SEMI_COLON { monitor_stmt($2, $3, "0"); } +| MONITOR NAME subscript COMMA NUMBER SEMI_COLON { monitor_stmt($2, $3, $5); } +; + +subscript /* e.g. [10] */ +: /* empty */ { $$ = 0; } +| L_SQ_BRACKET NUMBER R_SQ_BRACKET { $$ = $2; } +; + +debug_stmt +: DEBUG_PRINT NUMBER SEMI_COLON { set_debug_print($2); } +; + +decl_stmt /* variable declarations (e.g. float x[20];) */ +: type NAME subscript SEMI_COLON { decl_stmt($1, $2, $3, (char *)0); } +| type NAME subscript EQUAL NUMBER SEMI_COLON { decl_stmt($1, $2, $3, $5); } +| type NAME subscript EQUAL STRING SEMI_COLON { decl_stmt($1, $2, $3, $5); } +; + +type /* types for variables defined in SNL */ +: FLOAT { $$ = V_FLOAT; } +| DOUBLE { $$ = V_DOUBLE; } +| INT { $$ = V_INT; } +| SHORT { $$ = V_SHORT; } +| CHAR { $$ = V_CHAR; } +| STRING_DECL { $$ = V_STRING; } +| EVFLAG { $$ = V_EVFLAG; } +; + +sync_stmt /* sync */ +: SYNC NAME subscript NAME SEMI_COLON { sync_stmt($2, $3, $4); } +| SYNC NAME subscript TO NAME SEMI_COLON { sync_stmt($2, $3, $5); } +; + +program_body /* a program body is one or more state sets */ +: state_set +| program_body state_set +; + +state_set /* define a state set */ +: STATE_SET NAME L_BRACKET state_set_body R_BRACKET { state_set($2); } +| error { snc_err("state set", line_num, 3); } +; + +state_set_body /* define a state set body (one or more state blocks) */ +: state_block +| state_set_body state_block +| error { snc_err("state set body", line_num, 4); } +; + +state_block /* a block that defines a single state */ +: STATE NAME L_BRACKET trans_list R_BRACKET + { state_block($2); } +| error { snc_err("state block", line_num, 11); } +; + +trans_list /* all transitions for one state */ +: transition +| trans_list transition +| error { snc_err("transition", line_num, 5); } +; + +transition /* define a transition (e.g. "when (abc(x) | def(y, z)) state 2;" ) */ +: WHEN L_PAREN expression R_PAREN L_BRACKET action R_BRACKET STATE NAME + { transition($9, $3); } +; + +expression /* general expression: e.g. (-b+2*a/(c+d)) != 0 || (func1(x,y) < 5.0) */ + /* Expr *expression(int type, char *value, Expr *left, Expr *right) */ +: NUMBER { $$ = expression(E_CONST, $1, (Expr *)0, (Expr *)0); } +| STRING { $$ = expression(E_STRING, $1, (Expr *)0, (Expr *)0); } +| NAME { $$ = expression(E_VAR, $1, (Expr *)0, (Expr *)0); } +| function { $$ = $1; } +| expression PLUS expression { $$ = expression(E_BINOP, "+", $1, $3); } +| expression MINUS expression { $$ = expression(E_BINOP, "-", $1, $3); } +| expression ASTERISK expression { $$ = expression(E_BINOP, "*", $1, $3); } +| expression SLASH expression { $$ = expression(E_BINOP, "/", $1, $3); } +| expression GT expression { $$ = expression(E_BINOP, ">", $1, $3); } +| expression GE expression { $$ = expression(E_BINOP, ">=", $1, $3); } +| expression EQ expression { $$ = expression(E_BINOP, "==", $1, $3); } +| expression NE expression { $$ = expression(E_BINOP, "!=", $1, $3); } +| expression LE expression { $$ = expression(E_BINOP, "<=", $1, $3); } +| expression LT expression { $$ = expression(E_BINOP, "<", $1, $3); } +| expression OR expression { $$ = expression(E_BINOP, "||", $1, $3); } +| expression AND expression { $$ = expression(E_BINOP, "&&", $1, $3); } +| expression EQUAL expression { $$ = expression(E_BINOP, "=", $1, $3); } +| expression PLUS_EQUAL expression { $$ = expression(E_BINOP, "+=", $1, $3); } +| expression MINUS_EQUAL expression { $$ = expression(E_BINOP, "-=", $1, $3); } +| expression AND_EQUAL expression { $$ = expression(E_BINOP, "&=", $1, $3); } +| expression OR_EQUAL expression { $$ = expression(E_BINOP, "|=", $1, $3); } +| expression DIV_EQUAL expression { $$ = expression(E_BINOP, "/=", $1, $3); } +| expression MULT_EQUAL expression { $$ = expression(E_BINOP, "*=", $1, $3); } +| L_PAREN expression R_PAREN { $$ = expression(E_PAREN, "", (Expr *)0, $2); } +| PLUS expression %prec UOP { $$ = expression(E_UNOP, "+", (Expr *)0, $2); } +| MINUS expression %prec UOP { $$ = expression(E_UNOP, "-", (Expr *)0, $2); } +| NOT expression { $$ = expression(E_UNOP, "!", (Expr *)0, $2); } +| ASTERISK expression %prec UOP { $$ = expression(E_UNOP, "*", (Expr *)0, $2); } +| AMPERSAND expression %prec UOP { $$ = expression(E_UNOP, "&", (Expr *)0, $2); } +| expression L_SQ_BRACKET expression R_SQ_BRACKET %prec SUBSCRIPT + { $$ = expression(E_SUBSCR, "", $1, $3); } +| /* empty */ { $$ = expression(E_EMPTY, ""); } +; + +function /* function */ +: NAME L_PAREN parameter R_PAREN { $$ = expression(E_FUNC, $1, (Expr *)0, $3); } +; + +parameter /* expr, expr, .... */ +: expression { $$ = parameter($1, 0); } +| parameter COMMA expression { $$ = parameter($3, $1); } +| /* empty */ { $$ = 0; } +; + +action /* action block for a single state */ +: /* Empty */ +| action_item +| action action_item +| error { snc_err("action", line_num, 8); } +; + +action_item /* define an action */ +: expression SEMI_COLON { action_stmt($1); } +| C_STMT { action_c_stmt($1); } +| error { snc_err("action statement", line_num, 9); } +; + +%% diff --git a/src/sequencer/snc_lex.l b/src/sequencer/snc_lex.l new file mode 100644 index 000000000..80d9f0785 --- /dev/null +++ b/src/sequencer/snc_lex.l @@ -0,0 +1,164 @@ +%{ +/************************************************************************** + GTA PROJECT AT division + Copyright, 1990, The Regents of the University of California. + Los Alamos National Laboratory + + @(#)snc_lex.l 1.1 10/16/90 + ENVIRONMENT: UNIX +***************************************************************************/ +/* 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 "parse.h" +#include "y.tab.h" /* output from yacc */ +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif +/*#define DEBUG 1*/ + +#ifdef DEBUG +#define RETURN(param) { printf("return(param)\n"); return(param); } +#else +#define RETURN(param) return(param); +#endif +#define STR_BFR_SIZE 30000 + + extern int line_num; /* input line number */ + char str_bfr[STR_BFR_SIZE]; /* holding place for strings */ + char *str_next = str_bfr; /* current ptr to str_bfr */ + char *c_str; /* Start of current string in str_bfr */ + int nc; + double atof(); + int one_line_c_code; + +%} + +/* Start conditions (SNL, C code, comment, and string) */ +%Start SNL C_CODE COMMENT STR + +NAME [a-zA-Z][a-zA-Z0-9_]* +FPNUM (\-?(([0-9]+)(\.[0-9]*)?)|(\.[0-9]+)) + +%% /* Begin rules */ +. *str_next++ = yytext[0]; +\n { + *str_next++ = '\n'; + line_num++; + if (one_line_c_code) + { + *str_next++ = 0; + yylval.pchar = c_str; + BEGIN SNL; + RETURN(C_STMT); + } + } +"}%" { + *str_next++ = 0; + yylval.pchar = c_str; + BEGIN SNL; + RETURN(C_STMT); + } +\n line_num++; +"*/" BEGIN SNL; +. ; +"\\\"" { + *str_next++ = yytext[0]; + *str_next++ = yytext[1]; + } +\" { + *str_next++ = 0; + yylval.pchar = c_str; + BEGIN SNL; + RETURN(STRING); + } +. { *str_next++ = yytext[0]; } +\n { *str_next++ = '?'; line_num++; } +\n { line_num++; } +"%{" { + c_str = str_next; + one_line_c_code = FALSE; + BEGIN C_CODE; + } +"%%" { + c_str = str_next; + one_line_c_code = TRUE; + BEGIN C_CODE; + } +"/*" BEGIN COMMENT; +\" { c_str = str_next; BEGIN STR; } +"ss" RETURN(STATE_SET); +"state" RETURN(STATE); +"when" RETURN(WHEN); +"monitor" RETURN(MONITOR); +"assign" RETURN(ASSIGN); +"int" RETURN(INT); +"float" RETURN(FLOAT); +"double" RETURN(DOUBLE); +"short" RETURN(SHORT); +"char" RETURN(CHAR); +"string" RETURN(STRING_DECL); +"to" RETURN(TO); +"define" RETURN(DEFINE); +"program" RETURN(PROGRAM); +"debug" RETURN(DEBUG_PRINT); +"evflag" RETURN(EVFLAG); +"sync" RETURN(SYNC); +{NAME} { + nc = strlen(yytext); + bcopy(yytext, str_next, nc+1); + yylval.pchar = str_next; + str_next += nc+1; + RETURN(NAME); + } +\= RETURN(EQUAL); +\: RETURN(COLON); +\& RETURN(AMPERSAND); +\* RETURN(ASTERISK); +\{ RETURN(L_BRACKET); +\} RETURN(R_BRACKET); +\[ RETURN(L_SQ_BRACKET); +\] RETURN(R_SQ_BRACKET); +\; RETURN(SEMI_COLON); +\. RETURN(PERIOD); +\( RETURN(L_PAREN); +\) RETURN(R_PAREN); +\, RETURN(COMMA); +"|" RETURN(OR); +"&" RETURN(AND); +"||" RETURN(OR); +"&&" RETURN(AND); +"+" RETURN(PLUS); +"-" RETURN(MINUS); +"/" RETURN(SLASH); +">" RETURN(GT); +">=" RETURN(GE); +"==" RETURN(EQ); +"+=" RETURN(PLUS_EQUAL); +"-=" RETURN(MINUS_EQUAL); +"*=" RETURN(MULT_EQUAL); +"/=" RETURN(DIV_EQUAL); +"&=" RETURN(AND_EQUAL); +"|=" RETURN(OR_EQUAL); +"!=" RETURN(NE); +"<=" RETURN(LE); +"<" RETURN(LT); +"!" RETURN(NOT); +{FPNUM} { + nc = strlen(yytext); + bcopy(yytext, str_next, nc+1); + yylval.pchar = str_next; + str_next += nc+1; + RETURN(NUMBER); + } +[\t\ ]* ; +. RETURN(BAD_CHAR); +.|\n { line_num = 1; BEGIN SNL; yyless(0); } + diff --git a/src/sequencer/snc_main.c b/src/sequencer/snc_main.c new file mode 100644 index 000000000..e69173128 --- /dev/null +++ b/src/sequencer/snc_main.c @@ -0,0 +1,194 @@ +/************************************************************************** + GTA PROJECT AT division + Copyright, 1990, The Regents of the University of California. + Los Alamos National Laboratory + + @(#)snc_main.c 1.1 10/16/90 + DESCRIPTION: Main program and miscellaneous routines for + State Notation Compiler. + + ENVIRONMENT: UNIX +***************************************************************************/ +extern char *sncVersion; + +#include + +/* SNC Globals: */ +int line_no = 1; /* input line number */ +char in_file[200]; /* input file name */ +char out_file[200]; /* output file name */ + +/*+************************************************************************ +* NAME: main +* +* CALLING SEQUENCE +* type argument I/O description +* ------------------------------------------------------------- +* int argc I arg count +* char *argv[] I array of ptrs to args +* +* RETURNS: n/a +* +* FUNCTION: Program entry. +* +* NOTES: 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. Stderr is not redirected. +* +* This routine calls yyparse(), which never returns. +*-*************************************************************************/ +main(argc, argv) +int argc; +char *argv[]; +{ + FILE *infp, *outfp, *freopen(); + extern char in_file[], out_file[]; + + /* Use line buffered output */ + setlinebuf(stdout); + + /* Get command arguments */ + get_args(argc, argv); + /* Redirect input stream from specified file */ + infp = freopen(in_file, "r", stdin); + if (infp == NULL) + { + perror(in_file); + exit(1); + } + +#define REDIRECT +#ifdef REDIRECT + /* Redirect output stream to specified file */ + outfp = freopen(out_file, "w", stdout); + if (outfp == NULL) + { + perror(out_file); + exit(1); + } +#endif REDIRECT + printf( + "/* %s: %s */\n\n", sncVersion, in_file); + + /* Initialize parser */ + init_snc(); + + /* Call the SNC parser */ + yyparse(); +} + /*+************************************************************************ +* NAME: get_args +* +* CALLING SEQUENCE +* type argument I/O description +* ----------------------------------------------------------- +* int argc I number of arguments +* char *argv[] I shell command arguments +* RETURNS: n/a +* +* FUNCTION: Get the shell command arguments. +* +* NOTES: 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 gloabals in_file[] and out_file[]. +*-*************************************************************************/ +get_args(argc, argv) +int argc; +char *argv[]; +{ + extern char in_file[], out_file[]; + int ls; + char *s; + + if (argc < 2) + { + fprintf(stderr, "%s\n", sncVersion); + fprintf(stderr, "Usage: snc infile\n"); + exit(1); + } + s = argv[1]; + + ls = strlen(s); + bcopy(s, in_file, ls); + in_file[ls] = 0; + bcopy(s, out_file, ls); + if ( strcmp(&in_file[ls-3], ".st") == 0 ) + { + out_file[ls-2] = 'c'; + out_file[ls-1] = '\0'; + } + else + { + out_file[ls] = '.'; + out_file[ls+1] = 'c'; + ls += 2; + } + out_file[ls] = 0; + return; +} + /*+************************************************************************ +* NAME: snc_err +* +* CALLING SEQUENCE +* type argument I/O description +* ------------------------------------------------------------------- +* char *err_txt I Text of error msg. +* int line I Line no. where error ocurred +* int code I Error code (see snc.y) +* +* RETURNS: no return +* +* FUNCTION: Print the SNC error message and then exit. +* +* NOTES: +*-*************************************************************************/ +snc_err(err_txt, line, code) +char *err_txt; +int line, code; +{ + fprintf(stderr, "Syntax error %d (%s) at line %d\n", + code, err_txt, line); + exit(code); +} + /*+************************************************************************ +* NAME: yyerror +* +* CALLING SEQUENCE +* type argument I/O description +* --------------------------------------------------- +* char *err I yacc error +* +* RETURNS: n/a +* +* FUNCTION: Print yacc error msg +* +* NOTES: +*-*************************************************************************/ +yyerror(err) +char *err; +{ + fprintf(stderr, "%s: line no. %d\n", err, line_no); + return; +} + +/*+************************************************************************ +* NAME: print_line_num +* +* CALLING SEQUENCE +* type argument I/O description +* --------------------------------------------------- +* int line_num I current line number +* +* RETURNS: n/a +* +* FUNCTION: Prints the line number and input file name for use by the +* C preprocessor. e.g.: # line 24 "something.st" +* +* NOTES: +*-*************************************************************************/ +print_line_num(line_num) +int line_num; +{ + printf("# line %d \"%s\"\n", line_num, in_file); + return; +}