Initial revision

This commit is contained in:
Mark Anderson
1991-04-04 15:56:19 +00:00
parent c40050c44e
commit f06fb83f9c
16 changed files with 3435 additions and 0 deletions

4
src/sequencer/README Normal file
View File

@@ -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...
###

1
src/sequencer/Version Executable file
View File

@@ -0,0 +1 @@
1.6.4

400
src/sequencer/gen_ss_code.c Normal file
View File

@@ -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 <stdio.h>
#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;
}
}

10
src/sequencer/makeSeqVersion Executable file
View File

@@ -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}'";'

10
src/sequencer/makeVersion Executable file
View File

@@ -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}'";'

594
src/sequencer/parse.c Normal file
View File

@@ -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 <ctype.h>
#include <stdio.h>
#include "parse.h" /* defines linked list structures */
#include <math.h>
#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

148
src/sequencer/parse.h Normal file
View File

@@ -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();*/

475
src/sequencer/phase2.c Normal file
View File

@@ -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 <stdio.h>
#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;
}

152
src/sequencer/seq_ca.c Normal file
View File

@@ -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;
}

288
src/sequencer/seq_mac.c Normal file
View File

@@ -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 <stdio.h>
#include <ctype.h>
#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;
}

420
src/sequencer/seq_main.c Normal file
View File

@@ -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;
}

91
src/sequencer/seq_qry.c Normal file
View File

@@ -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');
}

245
src/sequencer/seq_task.c Normal file
View File

@@ -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);
}

239
src/sequencer/snc.y Normal file
View File

@@ -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 <stdio.h>
#include <ctype.h>
#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 <pchar> STATE STATE_SET
%token <pchar> NUMBER NAME DBNAME
%token <pchar> 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 <pchar> STRING
%token <pchar> C_STMT
%type <ival> type
%type <pchar> subscript
%type <expr> 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 <var name>[<lower lim>,<upper lim>] to <db name>;' */
/* 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 <variable> <event flag> */
: 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); }
;
%%

164
src/sequencer/snc_lex.l Normal file
View File

@@ -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 */
<C_CODE>. *str_next++ = yytext[0];
<C_CODE>\n {
*str_next++ = '\n';
line_num++;
if (one_line_c_code)
{
*str_next++ = 0;
yylval.pchar = c_str;
BEGIN SNL;
RETURN(C_STMT);
}
}
<C_CODE>"}%" {
*str_next++ = 0;
yylval.pchar = c_str;
BEGIN SNL;
RETURN(C_STMT);
}
<COMMENT>\n line_num++;
<COMMENT>"*/" BEGIN SNL;
<COMMENT>. ;
<STR>"\\\"" {
*str_next++ = yytext[0];
*str_next++ = yytext[1];
}
<STR>\" {
*str_next++ = 0;
yylval.pchar = c_str;
BEGIN SNL;
RETURN(STRING);
}
<STR>. { *str_next++ = yytext[0]; }
<STR>\n { *str_next++ = '?'; line_num++; }
<SNL>\n { line_num++; }
<SNL>"%{" {
c_str = str_next;
one_line_c_code = FALSE;
BEGIN C_CODE;
}
<SNL>"%%" {
c_str = str_next;
one_line_c_code = TRUE;
BEGIN C_CODE;
}
<SNL>"/*" BEGIN COMMENT;
<SNL>\" { c_str = str_next; BEGIN STR; }
<SNL>"ss" RETURN(STATE_SET);
<SNL>"state" RETURN(STATE);
<SNL>"when" RETURN(WHEN);
<SNL>"monitor" RETURN(MONITOR);
<SNL>"assign" RETURN(ASSIGN);
<SNL>"int" RETURN(INT);
<SNL>"float" RETURN(FLOAT);
<SNL>"double" RETURN(DOUBLE);
<SNL>"short" RETURN(SHORT);
<SNL>"char" RETURN(CHAR);
<SNL>"string" RETURN(STRING_DECL);
<SNL>"to" RETURN(TO);
<SNL>"define" RETURN(DEFINE);
<SNL>"program" RETURN(PROGRAM);
<SNL>"debug" RETURN(DEBUG_PRINT);
<SNL>"evflag" RETURN(EVFLAG);
<SNL>"sync" RETURN(SYNC);
<SNL>{NAME} {
nc = strlen(yytext);
bcopy(yytext, str_next, nc+1);
yylval.pchar = str_next;
str_next += nc+1;
RETURN(NAME);
}
<SNL>\= RETURN(EQUAL);
<SNL>\: RETURN(COLON);
<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(SEMI_COLON);
<SNL>\. RETURN(PERIOD);
<SNL>\( RETURN(L_PAREN);
<SNL>\) RETURN(R_PAREN);
<SNL>\, RETURN(COMMA);
<SNL>"|" RETURN(OR);
<SNL>"&" RETURN(AND);
<SNL>"||" RETURN(OR);
<SNL>"&&" RETURN(AND);
<SNL>"+" RETURN(PLUS);
<SNL>"-" RETURN(MINUS);
<SNL>"/" RETURN(SLASH);
<SNL>">" RETURN(GT);
<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(LE);
<SNL>"<" RETURN(LT);
<SNL>"!" RETURN(NOT);
<SNL>{FPNUM} {
nc = strlen(yytext);
bcopy(yytext, str_next, nc+1);
yylval.pchar = str_next;
str_next += nc+1;
RETURN(NUMBER);
}
<SNL>[\t\ ]* ;
<SNL>. RETURN(BAD_CHAR);
.|\n { line_num = 1; BEGIN SNL; yyless(0); }

194
src/sequencer/snc_main.c Normal file
View File

@@ -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 <stdio.h>
/* 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;
}