Manipulating Expressions in External Programs
Mathematica expressions provide a very general way to handle all kinds of data, and you may sometimes want to use such expressions inside your external programs. A language like C, however, offers no direct way to store general Mathematica expressions. It is nevertheless possible to do this by using the loopback links provided by the MathLink library. A loopback link is a local MathLink connection inside your external program, to which you can write expressions that can later be read back.
| MLINKMLLoopbackOpen(stdenv,int*errno) | |
| open a loopback link | |
| voidMLClose(MLINK link) | close a link |
| intMLTransferExpression(MLINK dest,MLINK src) | get an expression from src and put it onto dest |
Functions for manipulating loopback links.
...
ml = MLLoopbackOpen(stdenv, &errno);
MLPutFunction(ml, "Power", 2);
MLPutSymbol(ml, "x");
MLPutInteger32(ml, 3);
...
MLGetFunction(ml, &head, &n);
MLGetSymbol(ml, &sname);
MLGetInteger32(ml, &k);
...
MLClose(ml);
You can use MLTransferExpression() to take an expression that you get via stdlink from Mathematica, and save it in a local loopback link for later processing.
You can also use MLTransferExpression() to take an expression that you have built up on a local loopback link, and transfer it back to Mathematica via stdlink.
...
MLPutFunction(ml, "Factorial", 1);
MLPutInteger32(ml, 21);
MLPutFunction(stdlink, "FactorInteger", 1);
MLTransferExpression(stdlink, ml);
You can put any sequence of expressions onto a loopback link. Usually you get the expressions off the link in the same order as you put them on.
And once you have got an expression off the link it is usually no longer saved. But by using MLCreateMark() you can mark a particular position in a sequence of expressions on a link, forcing MathLink to save every expression after the mark so that you can go back to it later.
| MLMARKMLCreateMark(MLINK link) | create a mark at the current position in a sequence of expressions on a link |
| MLSeekMark(MLINK link,MLMARK mark,int n) | |
| go back to a position n expressions after the specified mark on a link | |
| MLDestroyMark(MLINK link,MLMARK mark) | destroy a mark in a link |
Setting up marks in MathLink links.
...
MLPutInteger32(ml, 45);
MLPutInteger32(ml, 33);
MLPutInteger32(ml, 76);
MLGetInteger32(ml, &i);
mark = MLCreateMark(ml);
MLGetInteger32(ml, &i);
MLGetInteger32(ml, &i);
MLSeekMark(ml, mark, 0);
MLGetInteger32(ml, &i);
MLDestroyMark(ml, mark);
The way the MathLink library is implemented, it is very efficient to open and close loopback links, and to create and destroy marks in them. The only point to remember is that as soon as you create a mark on a particular link, MathLink will save subsequent expressions that are put on that link, and will go on doing this until the mark is destroyed.
| intMLGetNext(MLINK link) | find the type of the next object on a link |
| intMLGetArgCount(MLINK link,int*n) | store in n the number of arguments for a function on a link |
| intMLGetSymbol(MLINK link,char**name) | get the name of a symbol |
| intMLGetInteger32(MLINK link,int*i) | get a machine integer |
| intMLGetReal64(MLINK link,double*x) | get a machine floating-point number |
| intMLGetString(MLINK link,char**string) | get a character string |
Functions for getting pieces of expressions from a link.
| MLTKFUNC | composite function—head and arguments |
| MLTKSYM | Mathematica symbol |
| MLTKINT | integer |
| MLTKREAL | floating-point number |
| MLTKSTR | character string |
Constants returned by MLGetNext().
switch(MLGetNext(ml)) {
case MLTKFUNC:
MLGetArgCount(ml, &n);
recurse for head
for (i = 0; i < n; i++)
recurse for each argument
...
case MLTKSYM:
MLGetSymbol(ml, &name);
...
case MLTKINT:
MLGetInteger32(ml, &i);
...
}
By using
it is straightforward to write programs that can read any expression. The way MathLink works, the head and arguments of a function appear as successive expressions on the link, which you read one after another.
Note that if you know that the head of a function will be a symbol, then you can use
instead of
. In this case, however, you still need to call
to disown the memory used to store the symbol name.
| intMLPutNext(MLINK link,int type) | prepare to put an object of the specified type on a link |
| intMLPutArgCount(MLINK link,int n) | give the number of arguments for a composite function |
| intMLPutSymbol(MLINK link,char*name) | |
| put a symbol on the link | |
| intMLPutInteger32(MLINK link,int i) | put a machine integer |
| intMLPutReal64(MLINK link,double x) | put a machine floating-point number |
| intMLPutString(MLINK link,char*string) | |
| put a character string | |
Functions for putting pieces of expressions onto a link.
MLPutNext() specifies types of expressions using constants such as
from the
header file—just like MLGetNext().
