11
$\begingroup$

I'd like to return Greek symbols through MathLink from a C function. However, returning the usual escape sequence (such as \[Alpha]) does not seem to work. Here's a minimal example .tm file (myalpha.tm) which creates a function that should simply return \[Alpha] :

void myAlpha P(( ));

:Begin:         
:Function:          myAlpha
:Pattern:           myAlpha[ ]
:Arguments:         { }
:ArgumentTypes:     { }
:ReturnType:        Manual
:End:

#include "mathlink.h"
void myAlpha() { MLPutSymbol( stdlink, "\\[Alpha]" ); }
int main(int argc, char *argv[]) { return MLMain(argc, argv); }

To compile it (on OSX) I use :

/Applications/Mathematica.app/SystemFiles/Links/MathLink/DeveloperKit/MacOSX-x86-64/CompilerAdditions/mprep myalpha.tm -o myalphatm.c
/usr/bin/clang -c -I/Applications/Mathematica.app/SystemFiles/Links/MathLink/DeveloperKit/MacOSX-x86-64/CompilerAdditions myalphatm.c
/usr/bin/clang++ myalphatm.o -L/Applications/Mathematica.app/SystemFiles/Links/MathLink/DeveloperKit/MacOSX-x86-64/CompilerAdditions -lMLi3 -lstdc++ -framework Foundation -o myalpha

And to run it I execute this little script :

link = Install["<fullpath>/myalpha"];
myAlpha[];
Print[%]
Uninstall[link]

Inside a Mathematica notebook this produces some binary symbol, and if I run it with MathKernel from the commandline then I get :

$IterationLimit::itlim: Iteration limit of 4096 exceeded.
    Hold[Out[$Line - 1]]

My guess is that I haven't escaped everything correctly in the C string, but I'm not sure what the right escape sequence is. Since \ is the escape character in C I have escaped that, so the C-string reads "\\[Alpha]" and I've tried a variety of other options but to no avail.

$\endgroup$
9
$\begingroup$

halirutan's answer is correct, but more could be said on the matter, so I'll expand.

First, MathLink/WSTP has no knowledge about the long-name form of various characters. The only Wolfram Language components that have the ability to parse and understand things like \[Alpha], \[LongEqual], etc., are the front end and the kernel.

To explain more from here, I'll need to dive into a bit about Unicode and character encodings. A bit of background here. Every long-name maps to a single Unicode code point. Unicode code points have the conventional notation of U+xxxxxx, where the x's are hex digits and there might be 4, 5, or 6 of them (I'll consistently use 6 in this answer).

When the FE or kernel write or read files in ASCII (which they do by default, typically), there are a few different ways to write characters which aren't a part of ASCII so they'll be read. Where long-names are available, the kernel and FE use long-names to try to make the files more human-readable when you're looking at them in a text editor.

But neither the FE nor the kernel uses long-names for internal representation of strings. The internal representation uses some Unicode-friendly encoding variant. There are four that get used, and each of them has an equivalent set of MathLink/WSTP functions corresponding to them.

  • UTF-8, a Unicode consortium standard using a variable number of 1-byte code units to represent a code point.
  • UTF-16, a Unicode consortium standard using a variable number of 2-byte code units to represent a code point.
  • UTF-32, a Unicode consortium standard using a single 4-byte code unit to represent a code point.
  • What we internally call "MathLink encoding", an encoding that uses the plain-text subset of ASCII characters to represent code points.

MathLink understands all four of those encodings, and automatically converts between them. MathLink also supports a couple of encodings which cannot represent arbitrary code points (the ByteString and UCS2String variants, which I won't further belabor here).

halirutan's answer shows a correct example of using UTF-8. I might add that, if you're using C++11 or later, there are some string literal prefixes that can be quite helpful in speccing out string literals which are UTF-8/16/32. Annoyingly, MathLink rigorously requires prepending every UTF-16 and UTF-32 form with a Byte Order Mark in order to function properly. I'm not a big fan of this design decision, and it tends to make UTF-16/32 code clunky IMO, but that's the way it is.

MathLink encoding is what's used in the String variants (e.g., MLPutString or WSPutString). MathLink encoding is basically ASCII with the following exceptions:

  • \\: A literal backslash must be doubled. As with other forms here, this is in addition to the doubling of literal backslashes in typical C strings, so in C, this actually looks like
const char* literalmathlinkbackslash = "\\\\"
  • \ooo: A backslash followed by three octal digits is interpreted as the code point U+0000xx where xx is the hex equivalent of the octal number.
  • \.xx: A backslash followed by a period and two hex digits is interpreted as the code point U+0000xx.
  • \:xxxx: A backslash followed by a colon and four hex digits is interpreted as the code point U+00xxxx or, if between D800 and D8FF inclusive, may be interpreted as a member of a correctly matched surrogate pair.
  • \|xxxxxx: A backslash followed by a pipe and six hex digits is interpreted as the code point U+xxxxxx, if and only if the resulting hex number represents a valid Unicode code point. This means the numbers between 00D800 and 00DFFF inclusive, or greater than 10FFFF are not allowed.
  • A backslash followed by anything else is undefined behavior. A given bit of text following a backslash may or may not produce an error, but any behavior you observe should not be relied upon.

So, the UTF-8/16/32 and MathLink forms may all be used to communicate Unicode code points over MathLink. But long-names may absolutely not be used. The attempt in the original question to use a single backslash is in MathLink's "undefined behavior" zone. While the double backslash form now is sending a literal backslash, followed by a literal square bracket, etc.

$\endgroup$
7
$\begingroup$

I'm not an expert here, but one way to achieve what you want is to transfer UTF8 codes. I guess the assumption that you can simply transfer a string "\[Alpha]" as Symbol over MathLink and Mathematica interprets this for you, cannot be made. Therefore, the following is a different solution which works as expected (at least on my Linux here)

void myAlpha() { 
  MLPutUTF8Symbol( stdlink, "\u03B1", 2); 
}

Mathematica graphics

$\endgroup$
  • 1
    $\begingroup$ This works on OSX as well but MLPutUTF8Symbol needs a pointer to an unsigned char, so an explicit cast before the string is necessary. I.e. MLPutUTF8Symbol( stdlink, (const unsigned char *) "\u03B1", 2);. $\endgroup$ – Rasmus Apr 15 '14 at 14:28
2
$\begingroup$

Another route to go would be to translate the symbol to the internal character codes used by Mathematica, retrieved via ToCharacterCode:

In[5]:= ToCharacterCode["\[Alpha]"]

Out[5]= {945}

So in the C code you would use

MLPutFunction(link, "Symbol", 1);
MLPutFunction(link, "FromCharacterCode", 1);
MLPutInteger(link, 945);
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.