home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ARM Club 1
/
ARM_CLUB_CD.iso
/
contents
/
education
/
n
/
spice
/
docs
/
FTE
/
ME
/
FRONTEND
Wrap
Text File
|
1988-01-27
|
21KB
|
585 lines
.\" RCS Info: $Revision: 1.2 $ on $Date: 85/09/16 17:33:49 $
.\" $Source: /cad4/faustus/spice/doc/RCS/frontend.me,v $
.\" Copyright (c) 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
.th
.ds S \s-2SPICE\s+2\&3
.+c "Front End"
.pp
\fBNote: there is a lot in this section that is out of date, but
the code is in such a condition that it will have to be cleaned
up a great deal before I can update the documentation...\fR
.pp
The \*S front end (FTE) is designed to be easily adaptable
to different programs. There are several important parts: the
"C-shell parser", which handles aliases, history, and the other csh-type
functions, which is completely modular and may easily be used with
other programs; the routines for the various commands; the parser for
algebraic expressions; the expression
evaluation routines; the complex math routines; and the plotting
routines.
.pp
The global front-end routines and variables
are all prefixed with these characters (there are some exceptions in
"std.c"):
.(b
\fBcom_\fR Front-end command routines
\fBcp_\fR C-shell parser routines and variables
\fBcx_\fR Complex math routines
\fBdg_\fR Diagnostic stuff like stack backtrace routines
\fBft_\fR General front-end routines and variables
\fBgr_\fR Graphics routines
\fBif_\fR \*S interface routines
\fBinp_\fR Input routines
\fBsp_\fR \*S variables
\fBwl_\fR Routines to do wordlist manipulation
\fBwl_\fR Wordlist manipulation routines
\fBwrd_\fR Routines in the \fBwritedata\fR package
.)b
.sh 2 "Csh Parser"
.pp
The C-shell parser (\fBcshpar\fR) does aliasing, history, quoting,
backquote evaluation, globbing (expansion of *, ?, ~, {}, and []),
filename, command, and keyword completion, and
IO redirection. It is supposed to function the same way that the
C-shell does, so unless otherwise noted the C Shell User's Manual
should be consulted for the details of how these operate.
.pp
To use \fBcshpar\fR, the file "FTEcshpar.h" should be included.
The host program then must call
.(b
cp_parse(string);
.)b
If \fIstring\fR is non-NULL then the string will be used for input
instead of the current input file.
This will return a doubly-linked list of words in the following
format:
.(b
\fBtypedef struct\fR wordlist {
\fBchar\fR *wl_word; /* The word. */
\fBstruct\fR wordlist *wl_next; /* Forward link. */
\fBstruct\fR wordlist *wl_prev; /* Backward link. */
} wordlist;
.)b
The list will be what the user typed, after alias substitutions, etc.
The user must supply two routines:
.(b
cp_userset(var, isset)
\fBstruct\fR variable *var;
\fBbool\fR isset;
.)b
which \fBcshpar\fR calls if a variable that it doesn't know about
gets set (it knows about such variables as \fIprompt, noglob,
history,\fR and \fIverbose\fR).
The \fIisset\fR argument is \fBtrue\fR (\fBbool\fR is typedef'd as
\fBchar\fR, with \fBtrue\fR = (\fBchar\fR) 1 and \fBfalse\fR =
(\fBchar\fR) 0) if the variable has been set, and \fBfalse\fR if the
variable has been unset.
If the host program doesn't care about any variables, the function can
just be a dummy routine. Also required is
.(b
\fBstruct\fR variable
cp_enqvar(word)
\fBchar\fR *word;
.)b
which gets called when \fBcshpar\fR doesn't know about a variable mentioned \-
if the host program doesn't know about the variable either it should return
NULL.
.pp
The definition for the variable
structure is
.(b
\fBstruct\fR variable {
\fBchar\fR va_type; /* The type (see below). */
\fBchar\fR *va_name; /* The variable name. */
\fBunion\fR { /* The value of the variable. */
\fBbool\fR vV_bool;
\fBlong\fR vV_num;
\fBdouble\fR vV_real;
\fBchar\fR *vV_string;
\fBstruct\fR variable *vV_list;
} va_V;
\fBstruct\fR variable *va_next; /* Forward link. */
\fBstruct\fR variable *va_prev; /* Backward link. */
} ;
#\fBdefine\fR va_bool va_V.vV_bool
#\fBdefine\fR va_num va_V.vV_num
#\fBdefine\fR va_real va_V.vV_real
#\fBdefine\fR va_string va_V.vV_string
#\fBdefine\fR va_list va_V.vV_list
#\fBdefine\fR VT_BOOL 1
#\fBdefine\fR VT_NUM 2
#\fBdefine\fR VT_REAL 3
#\fBdefine\fR VT_STRING 4
#\fBdefine\fR VT_LIST 5
.)b
.pp
In addition to these entry points, the behavior of \fBcshpar\fR can be
changed with the routine
.(b
cp_modify(c, what)
\fBchar\fR c;
.)b
where \fIwhat\fR is one of:
.(b
#\fBdefine\fR CPM_REGC 1 /* Character made non-special to the parser. */
#\fBdefine\fR CPM_DEF 2 /* Character restored to default meaning. */
#\fBdefine\fR CPM_BRR 3 /* Break to right of character. */
#\fBdefine\fR CPM_BRL 4 /* Break to left of character. */
#\fBdefine\fR CPM_ALONE 5 /* Make character a single word. */
#\fBdefine\fR CPM_NOBRK 6 /* Don't break at character. */
#\fBdefine\fR CPM_NOAL 7 /* No aliasing. */
#\fBdefine\fR CPM_AL 8 /* Aliasing. */
#\fBdefine\fR CPM_INTER 9 /* Interactive mode. */
#\fBdefine\fR CPM_NOINTER 10 /* Noninteractive mode (sources, etc). */
.)b
and \fIc\fR is a character, if one is required. (Otherwise it is
ignored.) Making a character non-special usually prevents some action
from being carried out -- for instance, making the character *
non-special prevents it from being expanded into filenames. This is
done with \*S, as it is used for multiplication. Setting
non-interactive mode prevents a prompt from being displayed and
command and keyword completion from being done.
To do a source, one would set non-interactive mode with
.(b
cp_modify((\fBchar\fR) 0, CPM_NOINTER);
.)b
and the change the FILE pointer \fIcp_curinput\fR to the desired input
stream. When \fIcp_parse\fR returns \fBNULL\fR, then the end of file
has been reached and \fIcp_curinput\fR should be reset to whatever it
was before.
.pp
The characters that are used for the various functions generally
may be changed: the variables (all \fBchar\fR's) containing them
are as follows:
.(b
Function Variable Default
history cp_bang !
substitute cp_hat ^ (this is , in the front end)
variables cp_dol $
wildcard cp_star *
wildcard cp_huh ?
wildcard cp_obrac [
wildcard cp_cbrac ]
home directory cp_til ~
expansion cp_ocurl {
expansion cp_ccurl }
expansion cp_comma ,
input redirect cp_lt <
output redirect cp_gt >
error redirect cp_amp &
comment cp_hash # (this is * in the front end)
.)b
If the variable \fInoglob\fR is set, this inhibits expansion of the
wildcard characters *, ?, [, and ].
.pp
If the host program wants to take advantage of the IO redirection
features of the front-end, it should use the FILE pointers
\fBcp_in, cp_out,\fR and \fBcp_err\fR instead of \fBstdin, stdout,
\fRand\fB stderr\fR. These are reset every time \fBcp_parse\fR is
called.
Whenever the user uses '>' or '<', the appropriate file is opened and the
\fBcp_\fR FILE pointers are set to that file.
.pp
A few routines are available for setting and unsetting aliases,
setting and unsetting variables, and printing history, aliases, and
variables:
.pp
.(b
cp_setalias(word, substitute)
\fBchar\fR *word;
wordlist *substitute;
.)b
The substitute list may contain history substitution characters, which
operate on the current argument list.
.(b
cp_unalias(word)
\fBchar\fR *word;
.)b
If \fIword\fR has an alias then it is removed.
.(b
cp_vset(varname, type, value)
\fBchar\fR *varname;
\fBchar\fR *value;
.)b
The variable called \fIvarname\fR with the type \fItype\fR (see the
VT_ defines above) is set to the value pointed to by \fIvalue\fR (of
whatever type is specified by the \fItype\fR argument.)
.(b
cp_getvar(name, type, value)
\fBchar\fR *name;
\fBchar\fR *value;
.)b
The value of the variable with the given name and type is stored in
the object pointed to by \fIvalue\fR. \fIValue\fR should be an array
of \fBchar\fR's is \fItype\fR is \fIVT_STRING\fR, an \fBint\fR * if
it is \fIVT_NUM\fR, and so forth. If the variable is defined with a
different type, it is converted to the desired type if possible.
.(b
cp_remvar(varname)
\fBchar\fR *varname;
.)b
If there is a variable called \fIvarname\fR then it is deleted.
.(b
cp_vprint()
.)b
Print the values of all the variables currently defined.
.(b
cp_paliases(name)
\fBchar\fR *name;
.)b
Print the alias associated with \fIname\fR, or all aliases if the name
is NULL.
.(b
cp_hprint(eventhi, eventlo)
.)b
Print the history from event number \fIeventhi\fR to event number
\fIeventlo\fR.
.(b
cp_addcomm(word, keywords, filec)
\fBchar\fR *word;
\fBwordlist\fR *keywords;
\fBbool\fR filec;
.)b
Add the command \fIword\fR to the list used for command completion.
If \fIkeywords\fR is non-NULL then these keywords are used for
keyword completion for this command, in addition to the global
keyword list, which is \fIcp_keywords\fR (also a wordlist, which
the host program may alter at any time). If the \fIfilec\fR argument
is \fItrue\fR, then instead of keyword completion, filename and user
name completion is done for this command. There is no way to
specifiy certain arguments as being filenames and certain ones
as keywords, etc. The keyword lists and file completion flags
will also work when a command is aliased, but not through
history substitutions (yet).
.pp
When EOF (control-D) is typed, then \fIcshpar\fR prints out the
alternatives that the user may type at this point, and when
escape is typed then \fIcshpar\fR attempts to complete as much of
the command, keyword, or filename already typed as it can.
.(b
cp_remcomm(word)
\fBchar\fR *word;
.)b
Remove \fIword\fR from the list of commands that may be completed,
if it is there.
.(b
cp_addkword(word)
\fBchar\fR *word;
.)b
Add a keyword to the default list of keywords for keyword completion.
These are in addition to keywords specific to particular commands.
.(b
cp_addkword(word)
\fBchar\fR *word;
.)b
Remove the keyword from the default list, if it is there.
.pp
There are several commands that the host program should recognise and
call the proper routines for -- they all take wordlists as arguments (the
\fIcdr\fR of the wordlist returned by \fBcp_parse\fR) and are
as follows:
.(b
Name Function
set cp_cset
unset cp_cunset
alias cp_calias
unalias cp_cualias
history cp_chistory
echo cp_cecho
.)b
.pp
One note about using \fIcshpar\fR -- if you type a word as "word",
it will be returned by \fIcp_parse\fR with the quotes on, so
you should always use \fIcp_unquote()\fR with it. (This doesn't
happen with single-quoted arguments -- the reason it is useful
with double quotes is to be able to distinguish between strings
and numbers if they are written the same.) The way that \fIcshpar\fR
quotes characters with single quotes and backslashes is by turning
on the eighth bit, which is unfortunately slightly non-portable
but is pretty easy to deal with...
.sh 2 "The Basic Command Interpreter"
.pp
The front end maintains a list of the commands available to it -- there
is a array called \fIComs\fR in the file "front.c" of the
following structures:
.(b
\fBstruct\fR comm {
\fBchar\fR *co_comname; /* The name of the command. */
\fBint\fR (*co_func) (); /* The function that handles the command. */
\fBbool\fR co_stringargs; /* Collapse the arguments into a string. */
\fBbool\fR co_spiceonly; /* These can't be used from nutmeg. */
\fBbool\fR co_filec; /* Do filename completion. */
\fBint\fR co_minargs; /* Minimum number of args. */
\fBint\fR co_maxargs; /* Maximum number of args. */
\fBchar\fR *co_help; /* A short help string. */
} ;
.)b
If the \fIco_stringargs\fR field is \fBtrue\fR, then the function will
be passed its arguments in a string, otherwise it will be passed a
wordlist. If \fIco_spiceonly\fR is true and the program that is
being run is \fInutmeg\fR, then the command will not be executed, as
it is \*S-specific.
The help function prints the help string with
.(b
printf(helpstring, ft_program);
.)b
where \fIft_program\fR is a global string containing the name of the
current program (argv[0]), so the help string may contain a "%s" in
the place of the program name.
.pp
Any routines that are added to the front end may be made usable simply
by adding an entry to the ft_coms array. (Also, if there are any special
keywords for this command, see the stuff in the function \fIcpinit\fR
in "front.c". This isn't well done, because it is there just to show
off keyword completion.)
.pp
If any options are
added to \*S (which go on the .options card), its name, type, and
code number (as in PARMdefs.h) should be
added to the \fIopts\fR array in spiceonly.c.
.pp
\*S data is stored in the front end in two ways. First, there is the
\fIspicedata\fR format, which is more like the way the data is saved in
files (the data arrays are by points instead of vectors, as this is the
way \*S outputs them), and is used only in the file "format.c" and routines
like \fIwrite\fR and \fIload\fR.
.pp
The more usual format is defined in "FTEdata.h":
.(b
\fBstruct\fR dvec {
\fBchar\fR *v_name; /* The name of the vector. */
\fBint\fR v_type; /* The vector type (see FTEspicedata.h) */
\fBshort\fR v_flags; /* Flags: */
#\fBdefine\fR VF_REAL 000001 /* The data is complex. */
#\fBdefine\fR VF_COMPLEX 000002 /* The data is real. */
#\fBdefine\fR VF_UPLIM 000004 /* An upper limit is in effect (see below). */
#\fBdefine\fR VF_LOWLIM 000010 /* A lower limit is in effect. */
#\fBdefine\fR VF_ACCUM 000020 /* writedata() should accumulate this vector. */
#\fBdefine\fR VF_PLOT 000040 /* writedata() should incrementally plot it. */
#\fBdefine\fR VF_PRINT 000100 /* writedata() should print this vector. */
\fBunion\fR {
\fBdouble\fR *vU_realdata;
\fBcomplex\fR *vU_compdata;
} v_U; /* The actual data. */
#\fBdefine\fR v_realdata v_U.vU_realdata
#\fBdefine\fR v_compdata v_U.vU_compdata
#\fBdefine\fR isreal(v) ((v)->v_flags & VF_REAL)
#\fBdefine\fR iscomplex(v) ((v)->v_flags & VF_COMPLEX)
\fBint\fR v_length; /* Length of the vector. */
\fBint\fR v_rlength; /* How much space we really have. */
\fBdouble\fR v_yhi; /* The upper and lower y limits, if this */
\fBdouble\fR v_ylo; /* is a dvec to be plotted. */
\fBint\fR v_outindex; /* Index if writedata is building the vector. */
\fBint\fR v_linestyle; /* What line style we are using. */
\fBint\fR v_color; /* What color we are using. */
\fBbool\fR v_permanent; /* Don't garbage collect this dvec. */
\fBstruct\fR plot *v_plot; /* The plot structure (if it has one). */
\fBstruct\fR dvec *v_next; /* Forward link. */
\fBstruct\fR dvec *v_link2; /* Extra link for use with some commands. */
} ;
.)b
All the dvecs that are available are linked together under \fIft_plots\fR,
which correspond to seperate \*S runs. The current plot is where
vectors are searched for first by name, and is pointed to by the
variable \fBft_curplot\fR. The plot structure is as follows:
.(b
\fBstruct\fR plot {
\fBchar\fR *pl_title; /* The title card. */
\fBchar\fR *pl_date; /* Date. */
\fBchar\fR *pl_name; /* The plot name. */
\fBstruct\fR dvec *pl_dvecs; /* The data vectors in this plot. */
\fBstruct\fR dvec *pl_scale; /* The "scale" for the rest of the vectors. */
\fBstruct\fR plot *pl_next; /* List of plots. */
\fBwordlist\fR *pl_commands; /* Commands to execute when this plot is set. */
} ;
.)b
In order to get a \fIdvec\fR, given a name, the function
\fBft_vecbyname(name)\fR, where \fIname\fR is the name of the desired
vector, is used. This tries to find the named vector, and if it can't
it then tried "\fBV(name)\fR" and "\fBI(name)\fR". It limits the search
to the current plot.
.sh 2 "Functions"
.pp
There is a table of data on the available functions in the file
psubr.c, of the form:
.(b
\fBstruct\fR func {
\fBchar\fR *fu_name; /* The print name of the function. */
\fBcomplex\fR *(*fu_func)(); /* The function. */
} ;
.)b
When an expression like \fIsin (foo)\fR is parsed, the routines in
psubr.c try to find a function in the \fIfuncs\fR table called
\fIsin\fR. If there is one, then a function node is added to the parse
tree (see FTEparse.h), but if there is none, then a vector named
\fIsin(foo)\fR is checked for. Also if a name of the form \fBtype(name)\fR
is given, where \fBtype\fR can be \fBV\fR or \fBI\fR, a vector with
name \fBname\fR will match.
When a parse tree is evaluated with the
function \fIevaluate(parsenode)\fR, and a function node is
encountered, then the routine \fIapply_func\fR applies the appropriate
complex math routine to each point of the data vector to obtain the
new vector.
.pp
To add a new function, it is necessary to add a \fIfunc\fR structure to
the above array, and add the function referenced by \fIfu_func\fR
to "cmath.c".
.pp
Complex math functions are called in the following manner:
.(b
\fBchar\fR *
cx_function (data, type, length, newlength, newtype)
\fBchar\fR *data;
\fBshort\fR type;
\fBint\fR length;
\fBint\fR *newlength;
\fBshort\fR *newtype;
.)b
The function should cast \fIdata\fR to either \fBdouble\fR * or
\fBcomplex\fR *, depending on whether \fItype\fR is \fIVF_REAL\fR or
\fIVF_COMPLEX\fR. It should set *\fInewtype\fR likewise, depending on
what the result of its application will be, and also it should set
*\fInewlength\fR to the length of the result. There are three types
of functions defined so far - the sort that operate pointwise, where
*\fInewlength\fR = \fIlength\fR, the sort that take a scalar and return
a vector, like \fIcx_vector\fR, where *\fInewlength\fR = something
independent of \fIlength\fR, and the sort that take a vector and
return a scalar, like \fIcx_mean\fR, where *\fInewlength\fR = 1.
.sh 2 "Operations"
.pp
Operations are done in much the same way as complex functions
are done. The routine \fIdoop(func_name, function, arg1, arg2)\fR,
where \fIfunction\fR is a pointer to a function returning a
\fBchar\fR * and \fIarg1\fR and \fIarg2\fR are \fIdvec\fRs, is
used. Complex functions are called as follows:
.(b
\fBchar\fR *
cx_operation (data1, data2, type1, type2, length)
\fBchar\fR *data1, data2;
\fBshort\fR type1, type2;
.)b
Vectors that are operated on are made the same length. The result
is assumed to be of the same length as the operands and its
type is \fIcomplex\fR if either of the operands is complex.
(The exception to this is the comma operator.)
Adding
new operations requires changing the \fIops\fR table in
"psubr.c", adding the relevant
information to the parser (the files "parse.c" and "getpname.c),
adding a routine like the
ones in "evaluate.c", and perhaps adding a complex function to "cmath.c".
The format of the \fIops\fR table is:
.(b
\fBstruct\fR op {
\fBint\fR op_num; /* From parser #defines. */
\fBchar\fR *op_name; /* Printing name. */
\fBchar\fR op_arity; /* One or two. */
\fBstruct\fR dvec *(*op_func)(); /* The function to do the work. */
}
.)b
These functions are actually dummy functions that call \fIdoop()\fR
directly.
.pp
The parser is a simple operator-precedence parser.
.sh 2 "Plotting Routines"
.pp
The plotting routines use \fIMFB\fR, the Model Frame Buffer graphics
package. The main stuff is in the file "graf.c".
.sh 2 "Using The Front End With Other Programs"
.pp
The front end may be adapted to use with other circuit-simulation programs
besides \*S without much difficulty. See the manual page for \fBwritedata\fR
for details on how to use this set of routines seperately from the rest of
the front-end.
.pp
All \*S-specific code is in the file "spiceif.c". The following routines
are defined, and should be re-written for another simulator. In general,
pointers to circuits are kept as \fBchar\fR *'s, and are only cast to
the appropriate thing (\fBCKTcircuit\fR *'s for \*S) in the interface
routines.
.(b
if_run(ckt, what)
char *ckt;
char *what;
.)b
.pp
This runs a simulation of the circuit. The type of simulation is determined
by the string \fIwhat\fR \- in \*S the possibilities are "tran", "ac",
"dc", "op", "run", and "continue" (continue the run that is already in
progress). XXXXXXXXXXXX
.(b
if_dump(ckt, fp)
\fBchar\fR *ckt;
\fBFILE\fR *fp;
.)b
.pp
Do a "dump" of the current circuit \- with \*S now this is just a listing
of what \*S thinks the circuit looks like.
.(b
if_inpline(ckt, line)
\fBchar\fR *ckt;
\fBchar\fR *line;
.)b
.pp
Parse the given line and add it to the circuit. Since the \fBINP\fR parser
is incremental this it is possible with \*S to add lines to the circuit
at any point.
.(b
\fBchar\fR *
if_inpdeck(deck)
\fBstruct\fR card *deck;
.)b
.pp
The \fBcard\fR structure, as defined in "FTEinput.h" is as follows:
.(b
\fBstruct\fR card {
\fBint\fR ca_linenum;
\fBchar\fR *ca_line;
\fBchar\fR *ca_error;
\fBstruct\fR card *ca_next;
\fBstruct\fR card *ca_actual;
} ;
.)b
The complete deck is passed to this routine, which has it parsed and returns
a pointer to the circuit structure. See the chapter in the \fBINP\fR parser
for the details of how the card structure works.
.(b
if_option(ckt, name, type, value)
\fBchar\fR *ckt;
\fBchar\fR *name;
\fBint\fR type;
\fBchar\fR *value;
.)b
.pp
Add an option to the circuit. The \fIname, type,\fR and \fIvalue\fR arguments
are the same as the corresponding fields in the \fIvariable\fR structure.
If the routine can't use the option it should just return.
.(b
if_cktfree(ckt)
\fBchar\fR *ckt;
.)b
.pp
Free the data occupied by the circuit. This may be a no-op, of course.
.(b
\fBchar\fR *
if_errstring(code)
.)b
.pp
If \fIcode\fR is a number that denotes a particular \*S error, this routine
should return a string describing the error.
.pp
Additionally, there is some code in "subckt.c" and "fourier.c" that refers
to \*S routines, but subcircuit expansion can be easily disabled and the
file "CKTfour.c" taken from \*S for use with the front-end.