Programming Gri
1: Introduction
2: Simple example
3: Fancy example
4: Running Gri
5: Programming Gri
6: General Issues
7: X-Y Plots
8: Contour Plots
9: Image Plots
10: Examples
11: Handling Data
12: Gri Commands
13: Gri Extras
14: Evolution of Gri
15: Installing Gri
16: Gri Bugs
17: System Tools
18: Acknowledgments
19: License
20: Newsgroup
21: Concept Index
|
5.10: Adding new commands to Gri
Gri can be extended easily. Primitive commands (e.g. `set x name ')
can be supplemented with so-called "new commands." New commands are a
little like subroutines other programming languages. For example, you
might find that you often draw filled curves with a particular graylevel
(say 0.5), and then return the graylevel to the previous value. This
requires you to do the following each time:
new .old_graylevel.
.old_graylevel. = ..graylevel..
set graylevel 0.5
draw curve filled to 0 y
set graylevel .old_graylevel.
delete .old_graylevel.
|
This gets a bit tedious, and it would obviously be nicer to just say
something like
To make this shortcut, you'd tell Gri about the existence of a new
command called `Draw my kinda curve ', and tell it that the new
command can be accomplished by the longer code fragment written above.
Once you've learned how to make new commands, you are likely to use them
a lot. The following explains how you add new commands. For advice on
programming style, etc, see Resource File..
5.10.1: How Gri parses commands
Whenever Gri reads a command line, it compares it with its list of
commands. This list is searched in this order: (1) the universal
`gri.cmd' file see Options On Command Line, (2) your resource
file see Resource File., if it exists, and then (3) your command
file itself. Gri stops searching when it finds a Gri command that
matches the command line. "Matching" means that the command line is
identical in all words in a Gri command, scanning from the left, until
it encounters a word containing
-
A quote (e.g. `
"string" ')
-
A synonym name (e.g. `
\file ')
-
A variable name (e.g. `
.number. ')
-
An opening square bracket (e.g. `
[option] ')
-
An opening brace (e.g. `
{a|b} ')
-
An choice between two items (e.g. `
first|second ')
When Gri finds a command that matches your command line, it assumes that
this is the intended command, and searches no further. This means that
you must be careful not to have your command hidden by other commands.
For example, if your resource file contained these lines, Gri would
never execute the second new command, because calls to it match
the first command. To avoid this, you may either reverse the order of
the definitions, so that Gri will find the proper routine, or rename one
of the routines.
`Draw foo'
Draw a foo.
{
show "drawing a foo"
}
`Draw foo bar'
Draw a foo bar.
{
show "drawing a foo bar"
}
|
Gri searches the `gri.cmd' file first, so any new command that you
create that clash with built-in commands will be ignored by Gri
see Options On Command Line. Gri will warn you of this, and proceed,
ignoring your newer definition. To get around this, use capital letters
to begin the words of your new command. By convention, Gri never uses
capital letters in this way, so a clash is impossible (except with any
similar command you might have defined previously, such as in your
`~/.grirc' file).
5.10.2: Simple example of creating new command
To make a new command called `Show The Time ' insert the following
into your `~/.grirc' resource file or into your command-file
somewhere near the top, or at least before you use the command.
`Show The Time'
New command to show the time of day.
{
show "\.time."
}
|
EXPLANATION:
-
The name of the new command is enclosed in angled single-quote marks.
The words of the new command should begin with upper-case letters to
prevent a name clash with a present or future built-in Gri command.
Formatting convention: Make sure that the entire definition
string, from the opening angled quote to the ending angled quote,
appears on one line. Otherwise Gri will give an error like
ERROR: Can't extract syntax for new command
|
-
Following the name line, you may optionally insert any number of lines
which will become the `
help ' information for the new command. See
the file `gri.cmd' for the recommended stylistic conventions in
writing help information see Options On Command Line.
-
Following the help lines, if they exist, the body of the new command is
given, sandwiched between a starting line containing an opening brace
(`
{ ') as the only nonwhite character, and an ending line
containing a closing brace (`} ') as the only nonwhite character.
Any valid Gri commands may be used in the body of the new command. It
is acceptable to use other new commands in the body. Recursion is also
allowed -- a new command is allowed to call itself (although there is a
limit on nesting, of perhaps a thousand or so; this varies with the
version of Gri). Formatting convention: It is usual, but not
necessary, to use an indentation level of 2 spaces in the body of the
new command.
The new command is invoked by `Show The Time '. Help for the
command is found by `help Show The Time ' or `help Show '.
5.10.3: Complicated example of creating new command
The following example from the global `gri.cmd' file illustrates
how to parse/check the commandline (see Local Synonyms.), which is a
good practice in any code you expect to re-use. The first `if '
statement checks that the word `at ' is in the right place (this
would not have been checked by the syntax matcher, the word having
followed a string). The presence of the keyword `cm ' is checked
for, and user units or cm units are used accordingly. Local variables
are created (`new ') and then destroyed (`delete ') so that
this new command cannot affect outside code.
`draw label whiteunder "\string" at .ll_x. .ll_y. [cm]'
Draw label for plot, located with lower-left corner
at indicated (x,y) position (specified in user
units or in cm on the page). Whiteout is used
to clean up the area under the label. BUGS:
Cannot handle angled text; doesn't check for
super/subscripts.
{
if {rpn "\.word4." "at" !=}
show "ERROR 5th word must be `at', not `\.word4.'"
show traceback
quit
end if
new .x. .y. .oldgray. .space.
if {rpn \.words. 7 ==}
.x. = {rpn \.word5. xusertocm}
.y. = {rpn \.word6. yusertocm}
else if {rpn \.words. 8 ==}
if {rpn "\.word7." "cm" !=}
show "ERROR: Require 7th word to be `cm'"
show traceback
quit
end if
.x. = \.word5.
.y. = \.word6.
else
show "ERROR: Require 7 or 8 words, not \.words."
show traceback
quit
end if
# Coordinates now in cm. Next, white out a box
# under the text (and .space. centimetres
# beyond text), then draw label.
.space. = 0.1 # Space of 1mm
.oldgray. = ..graylevel..
set graylevel white
draw box filled \
{rpn .x. .space. -} \
{rpn .y. .space. -} \
{rpn .x. "\.word3." width + .space. +} \
{rpn .y. "M" ascent + .space. + } cm
set graylevel .oldgray.
draw label "\.word3." at .x. .y. cm
delete .x. .y. .oldgray. .space.
}
|
|