Yacas currently comes with a compiler that can convert scripts to C++ code. This facility will be used in the future to move as many functions defined in the kernel to scripts as possible.
The advantages of this approach are:
The disadvantages are:
The Yacas system comes with a compiler that can compile scripts to C++ files. To invoke, one can call
CompileCpp(scriptfile,pluginname); |
while in Yacas. scriptfile needs to be a full path to a script file, and pluginname is the base name for the plugin. This function creates a file $(pluginname).cpp, a C++ file that can be compiled into a plugin.
For the developer, however, it is a nuissance to have to compile the scripts each time something is changed.
When working on the scripts that need to be compiled it is better if the scripts get loaded in favor of the plugins. To achieve this a programmer can create his own initialization script, in which he can store:
Set(LoadPlugIns,False); Use("yacasinit.ys"); |
and pass this file as argument to the --init command line flag.
The calling sequence for Defun is:
Defun(FunctionName,Arguments)Body; |
Or when used from LISP
(Defun FunctionName Arguments Body) |
For example, Defun can be used in infix grammar script as:
Defun("add",{x,y}) MathAdd(x,y); |
The LISP equivalent would be:
(Defun "add" (List x y) (MathAdd x y)) |
Defun is defined entirely in terms of functions supported by the kernel, so it can be the very first function defined in the initialization script. As such it can be defined even before plugins get loaded.
There is one additional limitation: Compiled code can currently only call functions that have already been defined. This includes the functions in the kernel, and the scripts and plugins loaded before this script or plugin was loaded.
Why LISP expressions, instead of the usual infix grammar notation? Somewhere in the future the infix grammar parser will also be defined in script. And since the compiler only allows use of functions that have already been defined, the functions used by the infix grammar parser have to be defined in LISP syntax. If you think this is too strict, there is the added advantage of using functions that have already been compiled, in that the resulting code will be faster (the compiled code calls other compiled code directly).
Other than that, all functions with fixed number of arguments in the kernel are supported, and some macros and functions or macros with variable number of arguments.
This will be extended over time.
TrapError(DllLoad("libmath"),Use("base.rep/math.ys")); |
What this does is it tries to load the plugin with name libmath, and if this fails it tries to load the script base.rep/math.ys instead. So until the plugin exists Yacas uses the script file that is used to build the plugin instead.
The first time the Yacas executable is built the plugins are not available. To compile the plugins Yacas itself is needed. Being able to use the scripts in stead of the plugins solves this chicken-and-egg problem. At first there are the scripts, and Yacas will be a little bit slower, but it will work, and can be used to compile the scripts to plugins, after which it will be faster.
The scripts that get compiled in are grouped in the base.rep/ directory in the scripts/ directory.