An Embeddable Scripting Engine |
Tweet |
Follow @jx9_engine |
Jx9 in 5 minutes or less
Here
is what you do to start experimenting with the Jx9 scripting engine without
having to do a lot of tedious reading and configuration:
download The Code
Get a copy of the last public release of Jx9 (A single 1.3 MB C file). Visit the download page for additional information.
Write Programs That Use Jx9
Below is a simple C program that demonstrates how to use the C/C++ interface to Jx9. This program compile and execute the following Jx9 scripts.
$my_data = {
// Greeting message
greeting : "Hello world!\n",
// Dummy field
__id : 1,
// Host Operating System
os_name: uname(), //Built-in OS function
// Current date
date : __DATE__,
// Return the current time using an anonymous function
time : function(){ return __TIME__; }
};
// invoke JSON object members
print $my_data.greeting; //Hello world!
print "Host Operating System: ", $my_data.os_name, JX9_EOL;
print "Current date: ", $my_data.date, JX9_EOL;
print "Current time: ", $my_data.time(); // Anonymous function
That is, this simple Jx9 script when running should display a greeting message, the current system time and the host operating system. A typical output of this program would look like this:
Host Operating System: Microsoft Windows 7 localhost 6.1 build 7600 x86
Current date: 2012-12-27
Current time: 10:36:02
Another Jx9 script that demonstrate how to use the built-in IO facility.
$num = [];
print "Enter a number (Decimal, Hex, Octal or Binary notation)\n";
//Populate the JSON array with the first entry
$num[] = (int)fgets(STDIN);
print "Another number\n";
$num[] = (int)fgets(STDIN);
print "Finally, one last number\n";
$num[] = (int)fgets(STDIN);
//show content
print "Before sorting\n";
print $num;
//Sort the array now
sort($num);
print "\nAfter sorting\n";
print $num;
This simple Jx9 script ask for three numbers (64 bit integers) from the standard input (STDIN), store the given numbers in a JSON array, perform a merge-sort using the built-in sort function and output the sorted array. A typical output of this program would look like this:
50232
Another number
80
Finally, one last number
0xff
Before sorting
[50232,80,255]
After sorting
[80,255,50232]
An implementation of the famous factorial function in Jx9.
print "Enter a number\n";
$num = (int)fgets(STDIN);
function factorial(int $num)
{
if( $num == 0 || $num == 1 )
return 1;
else
return
$num
* factorial($num – 1);
}
print "Facorial of $num = "..factorial($num);
One final Jx9 script that demonstrate how Jx9 can be used for processing external configuration file based on JSON using the built-in json_encode() and json_decode() functions.
// Create a dummy configuration using a JSON object
$my_config = {
bind_ip : "127.0.0.1",
config : "/etc/symisc/jx9.conf",
dbpath : "/usr/local/unqlite",
fork : true,
logappend : true,
logpath : "/var/log/jx9.log",
quiet : true,
port : 8080
};
// Dump the JSON object
print $my_config;
// Write to disk
$file = "config.json.txt";
print "\n\n------------------\nWriting JSON object to disk file: '$file'\n";
// Create the file
$fp = fopen($file,'w+');
if( !$fp )
exit("Cannot create $file");
// Write the JSON object
fwrite($fp,$my_config);
// Close the file
fclose($fp);
// All done
print "$file successfully created on: "..__DATE__..' '..__TIME__;
// ---------------------- config_reader.jx9 ----------------------------
// Read the configuration file defined above
$iSz = filesize($zFile); // Size of the whole file
$fp = fopen($zFile,'r'); // Read-only mode
if( !$fp ){
exit("Cannot open '$zFile'");
}
// Read the raw content
$zBuf = fread($fp,$iSz);
// decode the JSON object now
$my_config = json_decode($zBuf);
if( !$my_config ){
print "JSON decoding error\n";
}else{
// Dump the JSON object
foreach( $my_config as $key,$value ){
print "$key ===> $value\n";
}
}
// Close the file
fclose($fp);
The first script generate a JSON object holding some dummy configuration fields, create a disk file named config.json.txt using the built-in fopen() function and finally serialize the JSON object to disk using the fwrite() function. While the second script perform the reverse operation using the fread() and json_decode() functions.
As you can see, Jx9 is a powerful programming language with a friendly and familiar syntax with a rich standard library built with over 303 functions and 139 constants suitable for most purposes. Refer to the Jx9 Language Reference Manual for additional information.
Embedding Jx9 using the C/C++ API
Embedding Jx9 in a C/C++ host application is relatively easy. The three Jx9 scripts defined above can be embedded in an application with the same C/C++ interfaces. That is, this simple C program could be used to compile and execute all the Jx9 scripts defined above.
/*
* Compile this file together with the jx9 scripting engine source code to generate
* the executable. For example:
* gcc -W -Wall -O6 -o test jx9_intro.c jx9.c
*/
/* Make sure you have the latest release of the JX9 engine
* from:
* http://jx9.symisc.net/downloads.html
*/
#include <stdio.h>
#include <stdlib.h>
-
/* Make sure this header file is available.*/
#include "jx9.h"
-
/*
* Display an error message and exit.
*/
static void Fatal(const char *zMsg)
{
puts(zMsg);
/* Shutdown the library */
jx9_lib_shutdown();
/* Exit immediately */
exit(0);
}
/*
* VM output consumer callback.
* Each time the virtual machine generates some outputs, the following
* function gets called by the underlying virtual machine to consume
* the generated output.
* All this function does is redirecting the VM output to STDOUT.
* This function is registered later via a call to jx9_vm_config()
* with a configuration verb set to: JX9_VM_CONFIG_OUTPUT.
*/
static int Output_Consumer(const void *pOutput, unsigned int nOutputLen, void *pUserData /* Unused */)
{
/*
* Note that it's preferable to use the write() system call to display the output
* rather than using the libc printf() which everybody now is extremely slow.
*/
printf("%.*s",
nOutputLen,
(const char *)pOutput /* Not null terminated */
);
/* All done, VM output was redirected to STDOUT */
return JX9_OK;
}
/*
* Main program: Compile and execute the JX9 program defined above.
*/
int main(void)
{
jx9 *pEngine; /* JX9 engine handle*/
jx9_vm *pVm; /* Compiled JX9 program */
int rc;
-
/* Allocate a new jx9 engine instance */
rc = jx9_init(&pEngine);
if( rc != JX9_OK ){
/*
* If the supplied memory subsystem is so sick that we are unable
* to allocate a tiny chunk of memory, there is no much we can do here.
*/
Fatal("Error while allocating a new JX9 engine instance");
}
/* Compile the test program defined above */
rc = jx9_compile(pEngine,JX9_PROG,-1,&pVm);
if( rc != JX9_OK ){
if( rc == JX9_COMPILE_ERR ){
const char *zErrLog;
int nLen;
/* Extract error log */
jx9_config(pEngine,
JX9_CONFIG_ERR_LOG,
&zErrLog,
&nLen
);
if( nLen > 0 ){
/* zErrLog is null terminated */
puts(zErrLog);
}
}
/* Exit */
Fatal("Compile error");
}
/*
* Now we have our script compiled, it's time to configure our VM.
* We will install the VM output consumer callback defined above
* so that we can consume the VM output and redirect it to STDOUT.
*/
rc = jx9_vm_config(pVm,
JX9_VM_CONFIG_OUTPUT,
Output_Consumer, /* Output Consumer callback */
0 /* Callback private data */
);
if( rc != JX9_OK ){
Fatal("Error while installing the VM output consumer callback");
}
/*
* And finally, execute our program. Note that your output (STDOUT in our case)
* should display the result.
*/
jx9_vm_exec(pVm, 0);
-
/* All done, cleanup the mess left behind. */
jx9_vm_release(pVm);
jx9_release(pEngine);
-
return 0;
}
We create a new Jx9 engine instance using a call to jx9_init() on line 62. This is often the first Jx9 API call that an application makes and is a prerequisite in order to compile Jx9 code using one of the compile interfaces.
We compile our Jx9 test program on line 73 using the jx9_compile interface.
We configure our Virtual Machine on line 99 by setting a VM output consumer callback named Output_Consumer(). All this callback does is redirecting the VM output to STDOUT using the libc printf() routine or the write() system call.
And
finally we execute our Jx9 program on
line 113 using
a call to jx9_vm_exec().
Your standard output (STDOUT) should display the result.
Clean-up is done on line 117 and 118 respectively via calls to jx9_vm_release() and jx9_release().
Compile the program
Compile the target C file together with the jx9 engine source code to generate the executable. For example:
gcc -W -Wall -O6 -o jx9_test jx9_intro.c jx9.c
Working Examples
jx9_intro.c: Hello world from C using Jx9 (First script).
jx9_terminal_io.c: Jx9 built-in IO facility from C (second script).
jx9_json_config_write.c: JSON configuration writer (third script).
jx9_json_config_read.c: JSON configuration reader (third script).
Visit the download page for additional working examples.
Sharing Data between the C Code and Jx9 Scripts.
Sharing data between the host application and the target Jx9 script such as passing environments information, command line arguments or registering predefined variables such as your application name, copyright notice and so forth is relatively easy and is done via the foreign variable mechanism.
This simple Jx9 script output the content of some foreign variable decalred below.
//Scalar foreign variable named $my_app
print "\$my_app =" , $my_app..JX9_EOL;
//foreign JSON object named $my_data
print "\$my_data = " , $my_data;
//Dump command line arguments
if( count($argv) > 0 ){
print "\nCommand line arguments:\n";
print $argv;
}else{
print "\nEmpty command line";
}
//Return a simple JSON object to the host application
$my_config = {
"jx9_version" : __JX9__, //JX9 Engine version
"time" : __TIME__, //Current time
"date" : __DATE__ //Current date
};
//terminate the script
die;
The following C program demonstrate how data is shared between the host application and the running Jx9 script. The main() function defined below creates and install two foreign variables named respectively $my_app and $my_data. The first is a simple scalar value while the last is a complex JSON object. these foreign variables are made available to the running script using the jx9_vm_config() interface with a configuration verb set to JX9_VM_CONFIG_CREATE_VAR.
/*
* Compile this file together with the jx9 scripting engine source code to generate
* the executable. For example:
* gcc -W -Wall -O6 -o test jx9_hostapp_info.c jx9.c
*/
/* Make sure you have the latest release of the JX9 engine
* from:
* http://jx9.symisc.net/downloads.html
*/
#include <stdio.h>
#include <stdlib.h>
-
/* Make sure this header file is available.*/
#include "jx9.h"
-
/*
* Display an error message and exit.
*/
static void Fatal(const char *zMsg)
{
puts(zMsg);
/* Shutdown the library */
jx9_lib_shutdown();
/* Exit immediately */
exit(0);
}
/*
* VM output consumer callback.
* Each time the virtual machine generates some outputs, the following
* function gets called by the underlying virtual machine to consume
* the generated output.
* All this function does is redirecting the VM output to STDOUT.
* This function is registered later via a call to jx9_vm_config()
* with a configuration verb set to: JX9_VM_CONFIG_OUTPUT.
*/
static int Output_Consumer(const void *pOutput, unsigned int nOutputLen, void *pUserData /* Unused */)
{
/*
* Note that it's preferable to use the write() system call to display the output
* rather than using the libc printf() which everybody now is extremely slow.
*/
printf("%.*s",
nOutputLen,
(const char *)pOutput /* Not null terminated */
);
/* All done, VM output was redirected to STDOUT */
return JX9_OK;
}
- /*
-
* The following walker callback is made available to the [jx9_array_walk()] interface
-
* which is used to iterate over the JSON object extracted from the running script.
-
* (See below for more information).
-
*/
-
static int JsonObjectWalker(jx9_value *pKey,jx9_value *pData,void *pUserData /* Unused */)
-
{
-
const char *zKey,*zData;
-
/* Extract the key and the data field */
-
zKey = jx9_value_to_string(pKey,0);
-
zData = jx9_value_to_string(pData,0);
-
/* Dump */
-
printf(
-
"%s ===> %s\n",
-
zKey,
-
zData
-
);
-
return JX9_OK;
-
}
-
/*
-
* Main program: Compile and execute the JX9 program defined above.
-
*/
-
int main(int argc,char **argv)
-
{
-
jx9_value *pScalar,*pObject; /* Foreign JX9 variable to be installed later */
-
jx9 *pEngine; /* JX9 engine handle*/
-
jx9_vm *pVm; /* Compiled JX9 program */
-
int rc;
-
int n;
-
-
/* Allocate a new jx9 engine instance */
-
rc = jx9_init(&pEngine);
-
if( rc != JX9_OK ){
-
Fatal("Error while allocating a new JX9 engine instance");
-
}
-
-
/* Compile the test program defined above */
-
rc = jx9_compile(pEngine,JX9_PROG,-1,&pVm);
-
if( rc != JX9_OK ){
-
if( rc == JX9_COMPILE_ERR ){
-
const char *zErrLog;
-
int nLen;
-
/* Extract error log */
-
jx9_config(pEngine,
-
JX9_CONFIG_ERR_LOG,
-
&zErrLog,
-
&nLen
-
);
-
if( nLen > 0 ){
-
/* zErrLog is null terminated */
-
puts(zErrLog);
-
}
-
}
-
/* Exit */
-
Fatal("Compile error");
-
}
-
/* Register script agruments so we can access them later using the $argv[]
-
* array from the compiled JX9 program.
-
*/
-
for( n = 1; n < argc ; ++n ){
-
jx9_vm_config(pVm, JX9_VM_CONFIG_ARGV_ENTRY, argv[n]/* Argument value */);
-
}
-
-
/*
-
* Now we have our script compiled, it's time to configure our VM.
-
* We will install the VM output consumer callback defined above
-
* so that we can consume the VM output and redirect it to STDOUT.
-
*/
-
rc = jx9_vm_config(pVm,
-
JX9_VM_CONFIG_OUTPUT,
-
Output_Consumer, /* Output Consumer callback */
-
0 /* Callback private data */
-
);
-
if( rc != JX9_OK ){
-
Fatal("Error while installing the VM output consumer callback");
-
}
-
/*
-
* Create a simple scalar variable.
-
*/
-
pScalar = jx9_new_scalar(pVm);
-
if( pScalar == 0 ){
-
Fatal("Cannot create foreign variable $my_app");
-
}
-
/* Populate the variable with the desired information */
-
jx9_value_string(pScalar,"My Host Application/1.2.5",-1/*Compule length automatically*/); /* Dummy signature*/
-
-
/*
-
* Install the variable ($my_app).
-
*/
-
rc = jx9_vm_config(
-
pVm,
-
JX9_VM_CONFIG_CREATE_VAR, /* Create variable command */
-
"my_app", /* Variable name (without the dollar sign) */
-
pScalar /* Value */
-
);
-
if( rc != JX9_OK ){
-
Fatal("Error while installing $my_app");
-
}
-
/* To access this foreign variable from the running script, simply invoke it
-
* as follows:
-
* print $my_app;
-
* or
-
* dump($my_app);
-
*/
-
-
/*
-
* Now, it's time to create and install a more complex variable which is a JSON
-
* object named $my_data.
-
* The JSON Object looks like this:
-
* {
-
* "path" : "/usr/local/etc",
-
* "port" : 8082,
-
* "fork" : true
-
* };
-
*/
-
-
pObject = jx9_new_array(pVm); /* Unified interface for JSON Objects and Arrays */
-
/* Populate the object with the fields defined above. */
-
jx9_value_reset_string_cursor(pScalar);
-
/* Add the "path" : "/usr/local/etc" entry */
-
jx9_value_string(pScalar,"/usr/local/etc",-1);
-
jx9_array_add_strkey_elem(pObject,"path",pScalar); /* Will make it's own copy of pScalar */
-
/* Add the "port" : 8080 entry */
-
jx9_value_int(pScalar,8080);
-
jx9_array_add_strkey_elem(pObject,"port",pScalar); /* Will make it's own copy of pScalar */
-
/* Add the "fork": true entry */
-
jx9_value_bool(pScalar,1 /* TRUE */);
-
jx9_array_add_strkey_elem(pObject,"fork",pScalar); /* Will make it's own copy of pScalar */
-
-
/* Now, install the variable and associate the JSON object with it */
-
rc = jx9_vm_config(
-
pVm,
-
JX9_VM_CONFIG_CREATE_VAR, /* Create variable command */
-
"my_data", /* Variable name (without the dollar sign) */
-
pObject /*value */
-
);
-
if( rc != JX9_OK ){
-
Fatal("Error while installing $my_data");
-
}
-
/* Release the two values */
-
jx9_release_value(pVm,pScalar);
-
jx9_release_value(pVm,pObject);
-
-
/*
-
* And finally, execute our program. Note that your output (STDOUT in our case)
-
* should display the result.
-
*/
-
jx9_vm_exec(pVm, 0);
-
/* Extract the content of the variable named $my_config defined in the
-
* running script which hold a simple JSON object.
-
*/
-
pObject = jx9_vm_extract_variable(pVm,"my_config");
-
if( pObject && jx9_value_is_json_object(pObject) ){
-
/* Iterate over object entries */
-
printf("\n\nTotal entries in $my_config = %u\n",jx9_array_count(pObject));
-
jx9_array_walk(pObject,JsonObjectWalker,0);
-
}
-
/* All done, cleanup the mess left behind.
-
*/
-
jx9_vm_release(pVm);
-
jx9_release(pEngine);
-
-
return 0;
-
}
We create a new Jx9 engine instance on line 82 using a call to jx9_init().
We compile our Jx9 test program on line 88 using a call to jx9_compile().
We pass command line arguments to the target Jx9 script ($argv predefined variable) on line 112 using a call to jx9_vm_config() with a configuration verb set to: JX9_VM_CONFIG_ARGV_ENTRY.
- We install a VM output consumer callback on line 120 using a call to jx9_vm_config() with a configuration verb set to: JX9_VM_CONFIG_OUTPUT.
We create a simple scalar foreign variable on line 131 using a call to jx9_new_scalar().
We populate the scalar variable with the desired value, here the application name on line 136 using a call to jx9_value_string().
We install the foreign variable as $my_app on line 141 using a call to jx9_vm_config() with a configuration verb set to: JX9_VM_CONFIG_CREATE_VAR.
We create an empty JSON object on line 168 using a call to jx9_new_array().
We populate our JSON object on line 170 til line 179 with the desired fields using the jx9_value_*() and jx9_array_add_*() interfaces.
We install our JSON object as a foreign variable named $my_data on line 182 using a call to jx9_vm_config() with a configuration verb set to: JX9_VM_CONFIG_CREATE_VAR.
We execute our JX9 program on line 200 using a call to jx9_vm_exec().
We extract the content of the variable named $my_config (A JSON object) declared inside the executed Jx9 script on line 204 using a call to jx9_vm_extract_variable().
We iterate over the elements of the extracted JSON object on line 208 using a call to jx9_array_walk().
finally, cleanup is done on line 212 and 213 using a call to jx9_vm_release() and jx9_release().
Standalone Interpreter For Jx9
The Jx9 download page includes a simple standalone Jx9 interpreter named jx9 (or jx9.exe on windows) that allows the user to enter and execute Jx9 files against a Jx9 engine. This utility is available in prebuilt binaries forms or can be compiled from source. You can get a copy of the Jx9 interpreter from the download page.
To start the jx9 program, just type "jx9" followed by the name of the Jx9 file to xecute. That is, the first argument is to the interpreter, the rest are scripts arguments, press "Enter" and the Jx9 code will be executed.
If something goes wrong while processing the Jx9 script due to a compile-time error, your error output (STDOUT) should display the compile-time error messages.
Usage example of the jx9 interpreter:
Running the interpreter
jx9 scripts/hello_world.jx9.txt
Running the interpreter with script arguments
jx9 scripts/mp3_tag.jx9.txt /usr/local/path/to/my_mp3s
The Jx9 interpreter package includes over 40 Jx9 scripts to test from simple hello world programs to ZIP archive extracting, MP3 tag extracting, JSON encoding/decoding, INI processing, UTF-8 encoding/decoding and many more. These scripts are available in the scripts directory of the zip archive.
Next
Check out the Introduction To The Jx9 C/C++ Interface for an introductory overview and roadmap to the dozens of Jx9 interface functions.
A separate document, The Jx9 C/C++ Interface, provides detailed specifications for all of the various C/C++ APIs for Jx9. Once the reader understands the basic principles of operation for Jx9, that document should be used as a reference guide.
Any questions, check the Frequently Asked Questions page or visit the Support Page for online community support.