navigation map

Chapters:
  1: Introduction
  2: Simple example
  3: Invocation
  4: Finer Control
  5: X-Y Plots
  6: Contour Plots
  7: Image Plots
  8: Examples
  9: Gri Commands
  10: Programming
  11: Environment
  12: Emacs Mode
  13: History
  14: Installation
  15: Gri Bugs
  16: Test Suite
  17: Gri in Press
  18: Acknowledgments
  19: License

Indices:
  Concepts
  Commands
  Variables
index.html#Top NewCommands.html#AddingNewCommands Gri: creating a complicated new command Gri: Hints for Gri programming index.html#Top Gri: Hints for Gri programming

10.11.5: Altering command arguments -- the `&' syntax

The Gri language permits a newcommand to change variables and synonyms passed as arguments, using a syntax that is quite similar to that employed by the C++ language.

10.11.5.1: Overview of the `&' syntax

Normally the arguments to a newcommand are parsed into either numerical values or strings, before execution is passed into the newcommand. This is a akin to the scheme called "call by value" in some programming languages. Gri also provides a syntax, borrowed from C++, that permits a newcommand to alter the contents of variable or synonym arguments.

The technique is simple. To permit a newcommand to modify an argument that is a variable or a synonym, just put a `&' to the left of the item on the calling line. Then, within the newcommand, the corresponding local synonym (i.e. `\.word1.', etc.) will behave as though it were the instance of the original variable or synonym.

The `&' is placed to the left of the variable-name or synonym-name without intervening space. For example `foo &.var. &\syn' tells the parser that the newcommand named `foo' may possibly alter the values of the variable `.var.' and the synonym `\syn', as they exist in the calling context.

It is important to note that Gri pays very little attention to the `&' in a syntax-declaration line. All it does is to note that the item to the right of the `&' is not a fixed word in the newcommand being defined; this follows the usual rules for parsing newcommand syntax (see Parsing).

10.11.5.2: Example: doubling a variable

Consider the task of adding a fixed amount to a variable. If the variable we wish to double is `.x.', we might write


`double_a_particular_variable'
{ 
    .x. = {rpn .x. 2 *}
}
.x. = 10
double_a_particular_variable

Code such as that presented above occurs in many applications. (Turn the multiplication into an addition, and change `.x.' to `..ymargin..', and you'll start to see the core of an application that draws multiple graph panels, one above another.) However, the code is too specific to be of much general use!

What if we want to double some other variable instead? The code below shows how to do that.


`double &.value.'
{
    \.word1. = {rpn \.word1. 2 *}      # line 3
}
.x. = 10                               # line 5
double &.x.
.y. = 3.14
double &.y.

At line 3 Gri interprets the `\.word1.' to the left of the equals sign as a reference to the variable that is set to the value 10 in line 5. Similarly, the `\.word1.' to the right of the equals sign evaluates to 10, the value in the calling program.

Gri automatically determines whether an item is a variable or a synonym, and does the correct thing. Thus, for example, if line 3 above were written as


\.word1. = "hello"                 # ERROR

an error would be reported, since `double' was called with a variable as an argument, and variables cannot hold strings.

10.11.5.3: Example: manipulating a synonym

Synonyms are treated in the same way, as is illustrated in the following example.

Q: what does the following print?


`add_a_dat &\filename'
{
    \.word1. = {rpn "\.word1." ".dat" strcat}
}
\filename = "test"
add_a_dat &\filename
show "\filename"

A: it prints `test.dat'.

10.11.5.4: Nesting

One newcommand may call another, letting a deeply-nested newcommand alter values of synonyms and variables that may otherwise be hidden behind `new' items of the same name. This is done by using the `&' notation at each step. The following provides an example of passing a variable through two levels of newcommands.

Q: what does the following print?


`food critic &food'                 
{                                  
    \.word2. = "\.word2.s"          
    yummy &\.word2.                 
}                                  
`yummy &foods'                      
{                                  
    \.word1. = "\.word1. are tasty" 
}                                   
\a = "apple"                         
food critic &\a                      
show "\a"                            

A: it prints `apples are tasty'.

10.11.5.5: About `new' and `delete'

If `new' and `delete' are executed on local synonyms inside newcommands (e.g. `new \.word1.') they create and destroy variables and synonyms in the context of the calling program.

For example, consider the following.

Q: what does the following print?


`poetry &\s'
{
    new \s                             # line 3
    \s = "rose"
    \.word1. = "\.word1. is a \s"      # line 5
    delete \s                          # line 6
}
\s = "A rose "                         # line 8
poetry &\s
show "\s"

A: it prints `A rose is a rose'.

The key point here is that the instance of the synonym named `\s' in the calling program, set in line 8, is modified by the `poetry' newcommand, in line 6. This modification involves the use of a synonym, also named `\s', that "lives" wholly within the newcommand, being created in line 3 and destroyed in line 6.

10.11.5.6: Determining calling information

Newcommands may determine the name and the nesting level of changeable calling arguments. To get the name, put a single ampersand after the backslash of the local synonym of interest. To get the nesting level (0 for main program, etc.) put two ampersands after the backslash.

`NC &.var.'
{
    show "\&.word1. (expect '.a.')"
    show "\&&.word1. (expect 0)"
}
.a. = 1
NC &.a.

Note: neither of these items may be used an lvalue. That is, they may not be used to the left of an equals sign. But you can always get around that by clever use of alias synonyms (see Alias Synonyms).

10.11.5.7: How Gri implements the `&' syntax

When the parser encounters an unquoted `&' followed immediately by the name of a variable or a synonym, it converts the whole token (`&' plus name) into a specially-encoded string that can be recognized inside newcommands. (This is only done if the `&' and the variable name are not enclosed in double quotes.)

This specially-encoded string contains not just the name of the variable or synonym, but also the current level of nesting of newcommands. In this way a newcommand can have its own private versions of variables, created by `new', that won't be misinterpreted for the identically-named variables in the calling program.

The format of these specially-encoded strings is `#\bn\ba\bm\be\b:\bN \b_ \bl\be\bv\be\bl\b:\bL#\b', where `N' stands for the name of the variable/synonym, `L' stands for the current level, and `\b' is the backspace character (hexadecimal 08 in the ascii table). This string is designed to be strange enough that users are unlikely to use it themselves. The coding scheme is not entirely arbitrary, however; note that if the backspace characters are ignored the result has the form `name:N_level:L'. It's also worth noting that if this string were printed on a terminal that erased characters when typing backspaces the result would be of the form `N_L'.

Examples: `@.a.' in the main program (i.e. at level 0) encodes to `#\bn\ba\bm\be\b:\b.a. \b_ \bl\be\bv\be\bl\b:\b0#\b' and `&\my_syn' inside a newcommand called by the main program (i.e. at level 1) encodes to `#\bn\ba\bm\be\b:\b\my_syn \b_ \bl\be\bv\be\bl\b:\b1#\b'.

Inside a newcommand, Gri checks to see if builtin synonyms (e.g. `\.word1.') hold such specially-encoded strings. If so, then the appropriate versions of the variables are used in preference to any variables that may have been newly created by `new' inside the newcommand.

navigation map