kleltut man page on DragonFly

Man page or keyword search:  
man Server   44335 pages
apropos Keyword Search (all sections)
Output format
DragonFly logo
[printable version]

KLELTUT(1)			    libklel			    KLELTUT(1)

INTRODUCTION
       This manual page provides a tutorial for the creation of a simple
       application that embeds the KL-EL compiler and interpreter.

BASIC EXAMPLE
       Here is a simple application that uses KL-EL, in its entirety.  Note
       that the line numbers are for explanatory purposes.

	   1 #include <klel.h>
	   2 #include <stdio.h>
	   3 #include <stdlib.h>
	   4
	   5 int
	   6 main(int iArgumentCount, char **ppcArgumentVector)
	   7 {
	   8   KLEL_CONTEXT *psContext = NULL;
	   9   KLEL_VALUE *psResult = NULL;
	  10   char *pcExpression = (iArgumentCount >= 2) ? ppcArgumentVector[1] : "";
	  11   char *pcMessage = NULL;
	  12   size_t szLength = 0;
	  13   psContext = KlelCompile(pcExpression, 0, NULL, NULL, NULL);
	  14   if (KlelIsValid(psContext))
	  15   {
	  16	 psResult = KlelExecute(psContext);
	  17	 if (psResult != NULL)
	  18	 {
	  19	   pcMessage = KlelValueToString(psResult, &szLength);
	  20	   fprintf(stdout, "result: %s\n", pcMessage);
	  21	   KlelFreeResult(psResult);
	  22	   free(pcMessage);
	  23	 }
	  24	 else
	  25	 {
	  26	   fprintf(stderr, "error: %s\n", KlelGetError(psContext));
	  27	 }
	  28   }
	  29   else
	  30   {
	  31	 fprintf(stderr, "error: %s\n", KlelGetError(psContext));
	  32   }
	  33   KlelFreeContext(psContext);
	  34
	  35   return 0;
	  36 }

       This example includes basic error handling and shows how simple
       embedding KL-EL can be.	When compiled and linked with the KL-EL
       library, this program will take the first argument (which represents a
       KL-EL expression) and compile/execute it.  Then, the result of that
       execution is converted to a string value and printed to stdout.

       Let's analyze what's going on here.  The first really interesting call
       is this:

	  13   psContext = KlelCompile(pcExpression, 0, NULL, NULL, NULL);

       This compiles the expression (or an empty string if the user didn't
       provide an argument) and returns a KLEL_CONTEXT structure.  The 0 means
       that we aren't passing any special flags to the compiler.  The next two
       NULLs mean that we're not exporting any variables into the KL-EL
       envrionment, and the final NULL means that we have no user-defined data
       to pass around.

       Next we check to make sure the compile was successful:

	  14   if (KlelIsValid(psContext))

       If KlelIsValid returns zero (false), it means that an error occurred
       during compilation and the resulting context, if any, is useless for
       anything except getting error messages.	Assuming compilation
       succeeded, we then proceed to execute the expression:

	  16	 psResult = KlelExecute(psContext);

       KlelExecute will return NULL if execution fails with any generated
       error messages being stored in the provided context.  If execution
       doesn't fail, we proceed to print out the result of the execution and
       free the result since we're done using it:

	  19	   pcMessage = KlelValueToString(psResult, &szLength);
	  20	   fprintf(stdout, "result: %s\n", pcMessage);
	  21	   KlelFreeResult(psResult);
	  22	   free(pcMessage);

       Most of the rest of the example is simply error handling that is called
       if either compilation or execution fails.

       The final thing we do is free the context for the expression:

	  33   KlelFreeContext(psContext);

       And that's it!

       Note that the context could have been executed again or as many times
       as you wish.  There's no global state in KL-EL, so different threads
       can compile expressions and run them simultaneously (though a single
       context shouldn't be shared across threads without proper handling and
       serialization).

       Assuming the source file from above is named "klel-basic.c" and you
       have an appropriate build environment (including gcc, libklel, and
       libpcre), you should be able to compile the code as follows:

	   $ gcc -o klel-basic klel-basic.c -lklel -lpcre

       Try out a few simple expressions:

	   $ klel-basic '2 + 2'
	   result: 4

	   $ klel-basic 'pi / e'
	   result: 1.15573

	   $ klel-basic '"0x" . hex_of_int(65536)'
	   result: 0x10000

       This tutorial includes a few more complicated examples below, but this
       example shows the basic workflow followed by any application that
       embeds KL-EL.

EXPORTING FUNCTIONS AND VARIABLES EXAMPLE
       Here is some source code that we can add to the example program above
       that demonstrates how to export variables and functions into the KL-EL
       environment where they can be used in KL-EL expressions.	 We export an
       integer variable, "arg_count", that holds the number of command line
       arguments passed to the application.  We also export a function,
       "get_arg", that returns a string representation of the numbered command
       line argument.

       The code below should be inserted into the example above starting at
       line 4.

	   1 #include <string.h>
	   2
	   3 int giArgumentCount = 0;
	   4 char **gppcArgumentVector = NULL;
	   5
	   6 KLEL_VALUE *
	   7 GetArg(KLEL_VALUE **ppsArgs, void *pvContext)
	   8 {
	   9   int64_t i64Arg = ppsArgs[0]->llInteger;
	  10
	  11   if (i64Arg < 0 || i64Arg >= giArgumentCount)
	  12   {
	  13	 KlelReportError((KLEL_CONTEXT *)pvContext, "get_arg: invalid argument", NULL);
	  14	 return NULL;
	  15   }
	  16
	  17   return KlelCreateString(strlen(gppcArgumentVector[i64Arg]), gppcArgumentVector[i64Arg]);
	  18 }
	  19
	  20 KLEL_EXPR_TYPE
	  21 GetType(const char *pcName, void *pvContext)
	  22 {
	  23   if (strcmp(pcName, "arg_count") == 0)
	  24   {
	  25	 return KLEL_TYPE_INT64;
	  26   }
	  27   else if (strcmp(pcName, "get_arg") == 0)
	  28   {
	  29	 return KLEL_TYPE_STRING_FUNCTION1(KLEL_TYPE_INT64);
	  30   }
	  31
	  32   return KLEL_TYPE_UNKNOWN;
	  33 }
	  34
	  35 KLEL_VALUE *
	  36 GetValue(const char *pcName, void *pvContext)
	  37 {
	  38   if (strcmp(pcName, "arg_count") == 0)
	  39   {
	  40	 return KlelCreateInteger(giArgumentCount);
	  41   }
	  42   else if (strcmp(pcName, "get_arg") == 0)
	  43   {
	  44	 return KlelCreateFunction(KLEL_TYPE_STRING_FUNCTION1(KLEL_TYPE_INT64), "get_arg", GetArg);
	  45   }
	  46
	  47   return KlelCreateUnknown();
	  48 }

       After inserting this code into the basic example above, change the
       basic example's compile expression from this

	  13   psContext = KlelCompile(pcExpression, 0, NULL, NULL, NULL);

       to this

	  13   psContext = KlelCompile(pcExpression, 0, GetType, GetValue, NULL);
	  14   giArgumentCount = iArgumentCount;
	  15   gppcArgumentVector = ppcArgumentVector;

       By doing this, KL-EL expressions now have access to a new variable,
       "arg_count" and a new function "get_arg".  Let's examine the new code
       in depth.

       KL-EL allows you to export variables and functions by defining two
       callback functions.  One function is called with a variable name and
       returns the type of that variable.  The other function is called with a
       variable name and returns the value of that variable.  The type of a
       variable can never change, but a variable's value can change at any
       time.  We export the GetArg function as "get_arg" and the
       giArgumentCount variable as "arg_count".

       Let's start by looking at the type callback, GetType:

	  20 KLEL_EXPR_TYPE
	  21 GetType(const char *pcName, void *pvContext)
	  22 {
	  23   if (strcmp(pcName, "arg_count") == 0)
	  24   {
	  25	 return KLEL_TYPE_INT64;
	  26   }
	  27   else if (strcmp(pcName, "get_arg") == 0)
	  28   {
	  29	 return KLEL_TYPE_STRING_FUNCTION1(KLEL_TYPE_INT64);
	  30   }
	  31
	  32   return KLEL_TYPE_UNKNOWN;
	  33 }

       This function simply checks the name of the variable it's supposed to
       look up and returns the appropriate type: KLEL_TYPE_INT64 for
       "arg_count" and a slightly more complicated type descriptor for
       "get_arg" that says that it is a function that returns a string and
       takes one argument, an integer.	If it's passed a variable name it
       doesn't know, it returns KLEL_TYPE_UNKNOWN, which causes KL-EL to
       search the standard library to see if it can be found there.

       In this simple example we just use a cascading if-then-else to figure
       out which variable name was passed in.  In larger applications, a hash
       function might be used to hash the variable name and turn it into a
       table lookup.

       Now let's look at the function that returns those variables' values,
       GetValue:

	  35 KLEL_VALUE *
	  36 GetValue(const char *pcName, void *pvContext)
	  37 {
	  38   if (strcmp(pcName, "arg_count") == 0)
	  39   {
	  40	 return KlelCreateInteger(giArgumentCount);
	  41   }
	  42   else if (strcmp(pcName, "get_arg") == 0)
	  43   {
	  44	 return KlelCreateFunction(KLEL_TYPE_STRING_FUNCTION1(KLEL_TYPE_INT64), "get_arg", GetArg);
	  45   }
	  46
	  47   return KlelCreateUnknown();
	  48 }

       The basic structure of this function is similar to GetType: it
       determines which variable is being requested, and returns the
       appropriate value.  It uses the KlelCreateInteger function to create
       the integer value for "arg_count", and KlelCreateFunction to create the
       function value for "get_arg".  By returning the result of
       KlelCreateUnknown if it doesn't know the value of the variable, it
       causes KL-EL to search the standard library.

       If the values of the exported variables were calculated dynamically
       (which they certainly can be), returning NULL instead of the result of
       KlelCreateUnknown would signal to KL-EL that the variable is known but
       an error occurred.  In that case, KL-EL won't search the standard
       library.

       Both GetType and GetValue take a second argument, a void pointer to the
       context.	 This is the same value (cast as a void pointer) that was
       returned by KlelCompile.

       The value returned for "arg_count" isn't that interesting -- it's just
       an integer.  The value returned for "get_arg" is much more interesting
       -- it's a function that will get invoked by the library.	 Let's look at
       the exported function, GetArg:

	   6 KLEL_VALUE *
	   7 GetArg(KLEL_VALUE **ppsArgs, void *pvContext)
	   8 {
	   9   int64_t i64Arg = ppsArgs[0]->llInteger;
	  10
	  11   if (i64Arg < 0 || i64Arg >= giArgumentCount)
	  12   {
	  13	 KlelReportError((KLEL_CONTEXT *)pvContext, "get_arg: invalid argument", NULL);
	  14	 return NULL;
	  15   }
	  16
	  17   return KlelCreateString(strlen(gppcArgumentVector[i64Arg]), gppcArgumentVector[i64Arg]);
	  18 }

       Just like GetValue, exported functions must return a pointer to a
       KLEL_VALUE.  Exported functions take two arguments, an array of
       pointers to KLEL_VALUE representing the the function's arguments, and a
       void pointer for the current context.  There are always exactly
       thirteen entries in ppsArgs, though they aren't all necessarily filled
       in.  The zeroeth entry is the function's first argument, and arguments
       are specified in ascending order.

       GetArg is pretty simple -- it just takes the value of its first
       argument (an integer) and either returns the corresponding command line
       argument as a string, or it reports an error and returns NULL.  The
       library's internal type checker guaranteed that this function would be
       called with one integer argument, so it's technically okay that this
       example doesn't explicitly check -- but there's no harm in double
       checking if you want.

       Finally, the last change needed to export our variable and function was
       to pass the two callback functions to KlelCompile.  Once that is done,
       your new variable and function are ready for use in KL-EL expressions.

GUARDED COMMANDS
   What Are Guarded Commands?
       Guarded commands are a kind of two-part expression.  The first part of
       the expression is called the "guard", and the second part is the
       "command".  The guard must be a boolean expression, and the command
       must be a call to the special function "eval".

       Guarded commands allow for extra information to be passed to an
       application from the expression.	 The extra information consists of two
       strings, known as the "interpreter" and the "program", a collection of
       256 integers called "exit codes", and up to twelve additional strings.

       Conventionally, guarded commands are used to pass operating system
       commands to the application to be executed, but KL-EL assigns no
       semantics to them other than that they are guarded commands with a
       boolean expression for a guard.	KL-EL has been used as a "control
       language" for some applications that embed multiple programming
       language interpreters (Python, Perl, Lua, etc) to determine which
       interpreter should be run on a given set of input by using guarded
       commands.

       Guarded commands look like this:

	   if (filename == "/etc/passwd") then
	     eval("exec", "/bin/rm", "-f", filename) pass [0, 255]

       The part in parentheses after the "if" is the guard.  The rest of the
       expression after the "then" is the command.  In this example, "exec" is
       the interpreter and "/bin/rm" is the program.

       One might read this example as saying "if the value of the 'filename'
       variable is '/etc/passwd', then execute the '/bin/rm' command with the
       following arguments and assume the operation was successful if the exit
       code is 0 or 255.

       While you could read it that way, KL-EL doesn't enforce any of that --
       it's up to your application to decide what to do with the success
       criteria provided in this expression.  KL-EL provides functions to
       extract each of the various parts of the guarded command.

       There are some type checking and syntactic limits enforced by KL-EL on
       guarded commands:

       The guard expression must be boolean
       The first two arguments to the eval function must be literal strings
       with no interpolations and shorter than 255 bytes.
       Exit codes must be literal integers.

   Compiling and Executing Guarded Commands
       If you just use KlelCompile and KlelExecute and don't run the guarded
       command in the specified interpreter, then KL-EL will simply treat a
       guarded command as a boolean expression.	 More specifically, it will
       act as though the guard is the whole expression.

       The function KlelIsGuardedCommand will test to see if a compiled
       expression is a guarded command.	 If you want to force the user to only
       provide guarded commands, the KLEL_MUST_BE_GUARDED_COMMAND flag should
       be passed to KlelCompile.  If this flag is set, KlelCompile will return
       a compilation error for any requests to compile a non-guarded command.

       If a guarded command is supplied, then you can use the following
       functions on the compiled expression:

       KlelGetInterpreter
	   returns the interpreter argument to the eval function

       KlelGetProgram
	   returns the program argument to the eval function

       KlelIsSuccessReturnCode
	   returns true or false if the code passed in is a successful code
	   according to the expression.

       None of the functions above will cause evaluation of the remaining
       arguments to the eval function, so they can be called even before your
       callbacks are ready to be executed.  This allows you to make sure these
       arguments are valid and set up any external interpreters you may need.

       Once you're ready to evaluate the remaining arguments to the eval
       function, you can call the KlelGetCommand function.  Presumably you'd
       do this if the result of KlelExecute was true, but it's up to you.  The
       KlelGetCommand function returns a pointer to a KLEL_COMMAND structure.
       This structure contains all of the information about the guarded
       command and is defined as follows:

	   typedef struct _KLEL_COMMAND
	   {
	     char pcInterpreter[KLEL_MAX_NAME + 1];
	     char pcProgram[KLEL_MAX_NAME + 1];
	     size_t szArgumentCount;
	     char *ppcArgumentVector[KLEL_MAX_FUNC_ARGS + 1];
	     int aiCodes[256];
	   } KLEL_COMMAND;

       The pcInterpreter and pcProgram arguments simply contain the associated
       string.	The aiCodes array contains a nonzero value in every position
       that corresponds to a successful exit code.  Note that if the
       expression does not contain any exit codes (they are optional), then 0
       is considered the only successful exit code.

       Most interesting, however, is the ppcArgumentVector array.  This
       contains the values of the remaining arguments to the eval function
       converted to strings.  As a convenience, the first entry in this array
       is identical to the contents of the pcProgram member; this makes it
       easy to interface with the execv(3) family of functions.

       Once you're done with a KLEL_COMMAND structure, it needs to be freed
       using KlelFreeCommand.

       The klel-expr program included in the KL-EL source distribution accepts
       normal expressions and guarded commands.	 It evaluates normal
       expressions and prints their results, but for guarded commands, it
       defines two interpreters: "echo" and "system".  For the "echo"
       interpreter, it simply echos the contents of ppcArgumentVector.	The
       "system" interpreter takes the contents of pcProgram and passes it to
       the standard system(3) function.

SEE ALSO
       klel-expr(1), klelapi(3), klellang(3), klelstdlib(3)

1.1.0				  2015-09-16			    KLELTUT(1)
[top]

List of man pages available for DragonFly

Copyright (c) for man pages and the logo by the respective OS vendor.

For those who want to learn more, the polarhome community provides shell access and support.

[legal] [privacy] [GNU] [policy] [cookies] [netiquette] [sponsors] [FAQ]
Tweet
Polarhome, production since 1999.
Member of Polarhome portal.
Based on Fawad Halim's script.
....................................................................
Vote for polarhome
Free Shell Accounts :: the biggest list on the net