JX9 Scripting Engine

An Embeddable Scripting 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.

// Declare a JSON object and assign it to the variable $my_data
$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:


Hello world!
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.


//Declare an empty JSON array
$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:


Enter a number
 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.


// ---------------------- config_writer.jx9 ----------------------------

// 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.



  1. /*

  2. * Compile this file together with the jx9 scripting engine source code to generate

  3. * the executable. For example:

  4. * gcc -W -Wall -O6 -o test jx9_intro.c jx9.c

  5. */


  6. /* Make sure you have the latest release of the JX9 engine

  7. * from:

  8. * http://jx9.symisc.net/downloads.html

  9. */

  10. #include <stdio.h>

  11. #include <stdlib.h>


  12. /* Make sure this header file is available.*/

  13. #include "jx9.h"


  14. /*

  15. * Display an error message and exit.

  16. */

  17. static void Fatal(const char *zMsg)

  18. {

  19.    puts(zMsg);

  20.    /* Shutdown the library */

  21.    jx9_lib_shutdown();

  22.    /* Exit immediately */

  23.    exit(0);

  24. }


  25. /*

  26. * VM output consumer callback.

  27. * Each time the virtual machine generates some outputs, the following

  28. * function gets called by the underlying virtual machine to consume

  29. * the generated output.

  30. * All this function does is redirecting the VM output to STDOUT.

  31. * This function is registered later via a call to jx9_vm_config()

  32. * with a configuration verb set to: JX9_VM_CONFIG_OUTPUT.

  33. */

  34. static int Output_Consumer(const void *pOutput, unsigned int nOutputLen, void *pUserData /* Unused */)

  35. {

  36.   /*

  37.    * Note that it's preferable to use the write() system call to display the output

  38.    * rather than using the libc printf() which everybody now is extremely slow.

  39.    */

  40.    printf("%.*s",

  41.        nOutputLen,

  42.       (const char *)pOutput /* Not null terminated */

  43.    );

  44.      /* All done, VM output was redirected to STDOUT */

  45.      return JX9_OK;

  46. }


  47. /*

  48. * Main program: Compile and execute the JX9 program defined above.

  49. */

  50. int main(void)

  51. {

  52.   jx9 *pEngine; /* JX9 engine handle*/

  53.   jx9_vm *pVm; /* Compiled JX9 program */

  54.   int rc;


  55.   /* Allocate a new jx9 engine instance */

  56.   rc = jx9_init(&pEngine);

  57.   if( rc != JX9_OK ){

  58.    /*

  59.     * If the supplied memory subsystem is so sick that we are unable

  60.     * to allocate a tiny chunk of memory, there is no much we can do here.

  61.     */

  62.     Fatal("Error while allocating a new JX9 engine instance");

  63.   }



  64.   /* Compile the test program defined above */

  65.   rc = jx9_compile(pEngine,JX9_PROG,-1,&pVm);

  66.   if( rc != JX9_OK ){

  67.     if( rc == JX9_COMPILE_ERR ){

  68.      const char *zErrLog;

  69.      int nLen;

  70.     /* Extract error log */

  71.     jx9_config(pEngine,

  72.         JX9_CONFIG_ERR_LOG,

  73.        &zErrLog,

  74.        &nLen

  75.    );

  76.    if( nLen > 0 ){

  77.       /* zErrLog is null terminated */

  78.       puts(zErrLog);

  79.     }

  80.   }

  81.   /* Exit */

  82.   Fatal("Compile error");

  83. }



  84. /*

  85. * Now we have our script compiled, it's time to configure our VM.

  86. * We will install the VM output consumer callback defined above

  87. * so that we can consume the VM output and redirect it to STDOUT.

  88. */

  89.   rc = jx9_vm_config(pVm,

  90.       JX9_VM_CONFIG_OUTPUT,

  91.       Output_Consumer, /* Output Consumer callback */

  92.       0 /* Callback private data */

  93.     );

  94.   if( rc != JX9_OK ){

  95.       Fatal("Error while installing the VM output consumer callback");

  96.    }



  97.   /*

  98.   * And finally, execute our program. Note that your output (STDOUT in our case)

  99.   * should display the result.

  100.   */

  101.   jx9_vm_exec(pVm, 0);



  102. /* All done, cleanup the mess left behind. */

  103.  jx9_vm_release(pVm);

  104.  jx9_release(pEngine);


  105.   return 0;

  106. }


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

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.


print "Showing foreign variable contents\n";
//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.


  1. /*

  2. * Compile this file together with the jx9 scripting engine source code to generate

  3. * the executable. For example:

  4. * gcc -W -Wall -O6 -o test jx9_hostapp_info.c jx9.c

  5. */


  6. /* Make sure you have the latest release of the JX9 engine

  7. * from:

  8. * http://jx9.symisc.net/downloads.html

  9. */

  10. #include <stdio.h>

  11. #include <stdlib.h>


  12. /* Make sure this header file is available.*/

  13. #include "jx9.h"


  14. /*

  15. * Display an error message and exit.

  16. */

  17. static void Fatal(const char *zMsg)

  18. {

  19.    puts(zMsg);

  20.    /* Shutdown the library */

  21.    jx9_lib_shutdown();

  22.    /* Exit immediately */

  23.    exit(0);

  24. }


  25. /*

  26. * VM output consumer callback.

  27. * Each time the virtual machine generates some outputs, the following

  28. * function gets called by the underlying virtual machine to consume

  29. * the generated output.

  30. * All this function does is redirecting the VM output to STDOUT.

  31. * This function is registered later via a call to jx9_vm_config()

  32. * with a configuration verb set to: JX9_VM_CONFIG_OUTPUT.

  33. */

  34. static int Output_Consumer(const void *pOutput, unsigned int nOutputLen, void *pUserData /* Unused */)

  35. {

  36.   /*

  37.    * Note that it's preferable to use the write() system call to display the output

  38.    * rather than using the libc printf() which everybody now is extremely slow.

  39.    */

  40.    printf("%.*s",

  41.        nOutputLen,

  42.       (const char *)pOutput /* Not null terminated */

  43.    );

  44.      /* All done, VM output was redirected to STDOUT */

  45.      return JX9_OK;

  46. }

  47. /*
  48. * The following walker callback is made available to the [jx9_array_walk()] interface

  49. * which is used to iterate over the JSON object extracted from the running script.

  50. * (See below for more information).

  51. */

  52. static int JsonObjectWalker(jx9_value *pKey,jx9_value *pData,void *pUserData /* Unused */)

  53. {

  54.   const char *zKey,*zData;

  55.   /* Extract the key and the data field */

  56.    zKey = jx9_value_to_string(pKey,0);

  57.    zData = jx9_value_to_string(pData,0);

  58.    /* Dump */

  59.    printf(

  60.      "%s ===> %s\n",

  61.      zKey,

  62.     zData

  63.   );

  64.   return JX9_OK;

  65. }

  66. /*

  67. * Main program: Compile and execute the JX9 program defined above.

  68. */

  69. int main(int argc,char **argv)

  70. {

  71.   jx9_value *pScalar,*pObject; /* Foreign JX9 variable to be installed later */

  72.   jx9 *pEngine; /* JX9 engine handle*/

  73.   jx9_vm *pVm; /* Compiled JX9 program */

  74.   int rc;

  75.   int n;


  76.   /* Allocate a new jx9 engine instance */

  77.   rc = jx9_init(&pEngine);

  78.   if( rc != JX9_OK ){

  79.    Fatal("Error while allocating a new JX9 engine instance");

  80.   }

  81.  

  82.   /* Compile the test program defined above */

  83.   rc = jx9_compile(pEngine,JX9_PROG,-1,&pVm);

  84.   if( rc != JX9_OK ){

  85.    if( rc == JX9_COMPILE_ERR ){

  86.      const char *zErrLog;

  87.      int nLen;

  88.      /* Extract error log */

  89.      jx9_config(pEngine,

  90.         JX9_CONFIG_ERR_LOG,

  91.         &zErrLog,

  92.         &nLen

  93.       );

  94.    if( nLen > 0 ){

  95.       /* zErrLog is null terminated */

  96.       puts(zErrLog);

  97.     }

  98.   }

  99.   /* Exit */

  100.    Fatal("Compile error");

  101.   }


  102. /* Register script agruments so we can access them later using the $argv[]

  103. * array from the compiled JX9 program.

  104. */

  105.  for( n = 1; n < argc ; ++n ){

  106.    jx9_vm_config(pVm, JX9_VM_CONFIG_ARGV_ENTRY, argv[n]/* Argument value */);

  107. }


  108. /*

  109. * Now we have our script compiled, it's time to configure our VM.

  110. * We will install the VM output consumer callback defined above

  111. * so that we can consume the VM output and redirect it to STDOUT.

  112. */

  113. rc = jx9_vm_config(pVm,

  114.       JX9_VM_CONFIG_OUTPUT,

  115.        Output_Consumer, /* Output Consumer callback */

  116.        0 /* Callback private data */

  117.     );

  118.    if( rc != JX9_OK ){

  119.        Fatal("Error while installing the VM output consumer callback");

  120.    }

  121.  /*

  122.   * Create a simple scalar variable.

  123.   */

  124.   pScalar = jx9_new_scalar(pVm);

  125.   if( pScalar == 0 ){

  126.      Fatal("Cannot create foreign variable $my_app");

  127.    }

  128.    /* Populate the variable with the desired information */

  129.    jx9_value_string(pScalar,"My Host Application/1.2.5",-1/*Compule length automatically*/); /* Dummy signature*/


  130.   /*

  131.    * Install the variable ($my_app).

  132.    */

  133.   rc = jx9_vm_config(

  134.          pVm,

  135.          JX9_VM_CONFIG_CREATE_VAR, /* Create variable command */

  136.          "my_app", /* Variable name (without the dollar sign) */

  137.           pScalar /* Value */

  138.        );

  139.     if( rc != JX9_OK ){

  140.        Fatal("Error while installing $my_app");

  141.     }

  142.   /* To access this foreign variable from the running script, simply invoke it

  143.    * as follows:

  144.    * print $my_app;

  145.    * or

  146.    * dump($my_app);

  147.    */


  148.  /*

  149.   * Now, it's time to create and install a more complex variable which is a JSON

  150.   * object named $my_data.

  151.   * The JSON Object looks like this:

  152.   * {

  153.   * "path" : "/usr/local/etc",

  154.   * "port" : 8082,

  155.   * "fork" : true

  156.   * };

  157.   */

  158.  

  159.   pObject = jx9_new_array(pVm); /* Unified interface for JSON Objects and Arrays */

  160.  /* Populate the object with the fields defined above. */

  161.   jx9_value_reset_string_cursor(pScalar);

  162.   /* Add the "path" : "/usr/local/etc" entry */

  163.   jx9_value_string(pScalar,"/usr/local/etc",-1);

  164.   jx9_array_add_strkey_elem(pObject,"path",pScalar); /* Will make it's own copy of pScalar */

  165.   /* Add the "port" : 8080 entry */

  166.   jx9_value_int(pScalar,8080);

  167.   jx9_array_add_strkey_elem(pObject,"port",pScalar); /* Will make it's own copy of pScalar */

  168.   /* Add the "fork": true entry */

  169.   jx9_value_bool(pScalar,1 /* TRUE */);

  170.   jx9_array_add_strkey_elem(pObject,"fork",pScalar); /* Will make it's own copy of pScalar */


  171.   /* Now, install the variable and associate the JSON object with it */

  172.   rc = jx9_vm_config(

  173.         pVm,

  174.         JX9_VM_CONFIG_CREATE_VAR, /* Create variable command */

  175.         "my_data", /* Variable name (without the dollar sign) */

  176.         pObject /*value */

  177.       );

  178.  if( rc != JX9_OK ){

  179.    Fatal("Error while installing $my_data");

  180.   }


  181.   /* Release the two values */

  182.   jx9_release_value(pVm,pScalar);

  183.   jx9_release_value(pVm,pObject);


  184.  /*

  185.   * And finally, execute our program. Note that your output (STDOUT in our case)

  186.   * should display the result.

  187.   */

  188.   jx9_vm_exec(pVm, 0);

  189.  /* Extract the content of the variable named $my_config defined in the

  190.   * running script which hold a simple JSON object.

  191.   */

  192.   pObject = jx9_vm_extract_variable(pVm,"my_config");

  193.  if( pObject && jx9_value_is_json_object(pObject) ){

  194.    /* Iterate over object entries */

  195.    printf("\n\nTotal entries in $my_config = %u\n",jx9_array_count(pObject));

  196.    jx9_array_walk(pObject,JsonObjectWalker,0);

  197. }

  198.  /* All done, cleanup the mess left behind.

  199.   */

  200.   jx9_vm_release(pVm);

  201.   jx9_release(pEngine);


  202. return 0;

  203. }

Get a copy of the C file.

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.



Symisc Systems
Copyright © Symisc Systems