1 - Introduction

I suck at writing documentation, so this will be short and bitter. For working samples, check out scripts/tests/*.ns

Nesla's earliest lines of code were derived from all the configuration file parsers I kept writing over and over, and was never happy with. With the hassle of writing new functions to deal with different files, and adding callback functions to deal with subsections, and _then_ taking the parsed data and making that data accessible to other loaded functions and modules, not to mention the whole memory management part, and the need to keep track of not only the name and type of variable, but also the size... Well, I guess I'm just lucky I have a sense of humour.

So here was a goal: A flexible config parser, a simple and universal data storage model, a short and simple command set, a zero effort memory management system that didn't suck, and a C api that wouldn't be painful or difficult to use in other projects. Whether or not it became a fully functional scripting language of its own was entirely incidental. What I ended up with is the Nesla core library; the scripting language for C programmers.

Syntactically, Nesla probably looks more like javascript than it does any other language. Use of the word 'object' may be less than 100% accurate, there are no properties, methods, events, or classes in the javascript sense, but the C syntax rules are nearly identical. Nesla is not an emulation of javascript, but both language designs do agree that C syntax is good and dollar signs are ugly.

Keywords

break continue return function global local var if else for do while exit

Working code looks a little like the following sample.

function demo(arg1) { global x=1; // you don't actually need local or var, but it makes the code clearer local y=2; var z=3; for (i=0;i<10;i++) { if (i<5) { print("less than half ", i, "\n"); } else if (i==5) { print("half\n"); } else { print("more than half ", i, "\n"); } if (i==arg1) break; } return; } demo(8);

break (accepts an optional unbracketed number arg to define the number of levels to break)
still need to add switch and goto..

Operators

= + ++ += - -- -= * *= / /= == != <= >= < > % & | ^ && || !

Strings can also be handled using the slightly shorter list of ops: = + += == != <= >= < >

The statement var x="a"+"b"; will set x to "ab".

Tables have considerably less ops: = {}

function subf() { return 69; } var pi = math.asin(1)*2; var table = { { a1="x", b = pi, [12]=41, [1]=42, 43, 'blah', subf() }, { "x", 'y', x = 41, 42, 43, 'blah', [5]=12, heh=";-)" } };

setting a var's value to null will completely free the value and effectively make the var non-existant

Objects And Classes

OOPS So here's the deal on 'Object Oriented Programming'. I don't get it. I'm not saying it's bad or that people who do it are deviants. I'm just not sure what the working definition of OO is these days. Nesla's storage system is entirely object-based, but that doesn't make the language object oriented. I added a 'this' variable so functions could infer the context in which they were called. Does this make Nesla an OO language? Consider the following code:

class str { function str(val) { this.value=tostring(val); }; function size() { return sizeof(this.value); }; function lower() { return string.tolower(this.value); }; function upper() { return string.toupper(this.value); }; function get() { return this.value; }; function set(val) { this.value=tostring(val); }; value=''; } x=new str("AbC"); print("["+x.size()+"]\n"); // will print 3 x.set("aBcDeF"); print("["+x.size()+"]\n"); // will print 6 print("["+x.lower()+"]\n"); // will print abcdef print("["+x.upper()+"]\n"); // will print ABCDEF

Is that technically an example of OO? True, most OO code has nicer looking constructors and classes and stuff I don't get, but this is working Nesla code.


The Basics

At the most basic level, objects are tables. The only thing that makes an object an object, and not _just_ a table, is 'this'. An object can be created as simply as doing this:

x = {}; x.this = &x;

'this' is a variable that links to the parent table and exists to provide a context for methods in the object. You should never create an object in the fashion above because it makes code harder to read. Otherwise, it's a perfectly valid way to create objects. If you want to extend this object with properties and methods, you can do so like this:

x.c = 42; x.pc = function () { printf("x.c=%d\r\n", this.c); };

And of course, you can call the method in the object like this:

x.pc();

Again, while valid, you should never create objects as shown above.


Constructors

An example of one preferred method would look like this.

function alpha() { pc = function () { printf("x.c=%d\r\n", this.c); }; c = 42; } x=new alpha(); x.pc();

The function alpha is what is known as a constructor. A constructor is a function that is used to help create an instance of a particular object type. Notice the keyword 'new'. This is what tells the interpreter to create and use an object as the context for the function call, and to return that object as the function's result. This method of creating an object is very similar to how Javascript instantiates objects. Notably, both have no class.


Classes

The use of classes in building objects is optional, but it can be useful.

class alpha { pc = function () { printf("x.c=%d\r\n", this.c); }; c = 42; } x=new alpha(); x.pc();

Do you see the difference? Me neither. Actually there is one major difference here, but it is not obvious. A class is not a function. In fact, it is a table, and this difference is _very_ important for one reason; tables can be linked. This means that an object (a table) can now be linked to a class (a table) without having to recreate it. This can be much faster when creating new objects, and can use significantly less memory when creating a lot of them. Now in this case, the function pc and the variable c have a single instance shared by both objects x and y.

class alpha { function alpha(a) { this.a = a; }; function pc() { printf("x.a=%s, x.c=%d\r\n", this.a, this.c); }; c = 42; } x=new alpha('x'); x.pc(); y=new alpha('y'); y.pc();

Note the addition of the alpha function to the class. This is a constructor. Any function with the same name as the class (or the name '_constructor') will be called when an object is created. This provides the same level of control over new objects as that of using a function instead of a class.


Inheritance

Using table linking with classes and objects has one other benefit; inheritance. In this example, a new object is created using the beta class, and it also 'inherits' the alpha class, including all functions and variables. It also 'overrides' the value of c without changing the original value in the alpha class.

class alpha { function pc() { printf("x.c=%d\r\n", this.c); }; c = 0; } class beta { function beta() { this.inherit(alpha); }; c = 42; } x=new beta(); x.pc();

The inherit function is not limited to use in classes, and can be used on any tables.


2 - The Language

copy


Description

Returns a copy of the first parameter.

eval


Description

Evaluates a supplied expression.

exec


Description

Executes a supplied statement.

serialize


Description

Print the provided var in a format appropriate for use in a nesla script. This will recursively print entire tables.

Syntax

serialize(object var)
ParameterDescription
var Object to be exported. Can be any object type, including table.

Return Value

Returns zero.

Remarks

Any argument that is not a string will be formatted automatically. Boolean values will be 'true' or 'false' and numbers will have up to 6 digits past the decimal. Most string functions may be binary safe, but this function _will_ terminate its output at the first \0 character.
The example "var x={}; x.y=x; serialize(x);" is valid code. It also recurses infinitely. Be careful, or you may be cursing infinitely yourself.

Examples

The following examples demonstrate the difference between print and serialize.

var x="this \"is a\" test\n";
print(x);

will display

this "is a" test
var x="this \"is a\" test\n";
print(serialize(x));

will display

"this \"is a\" test\n"
var x = {
        [0] = {
                key = "a"
        },
        [1] = {
                key = "b"
        }
};

print(serialize(x));

will display

{
        [0] = {
                key = "a"
        },
        [1] = {
                key = "b"
        }
}

iname


Description

Returns the name of a table entry at a given index.

include


Description

Include (and interpret) the code in the specified file.

Syntax

boolean = include(filename)
ParameterDescription
filename String containing the name of the file to be included.

Return Value

Returns true if the file has been successfully included. Any false return code indicates an error.

Remarks

Return codes indicating failure are almost always caused by a nonexistent or unreadable script file, not errors in the script itself.

Example

The following example demonstrates how to load a script and verify its success.

rval=include("./somefile.ns");
if (rval!=true) print("error loading ./somefile.ns\n");

ival


Description

Returns a pointer to the value of a table entry at a given index.

print


Description

Print the complete list of arguments to the standard output.

Syntax

number = print(...)
ParameterDescription
... List of objects to be printed.

Return Value

Returns the number of characters printed.

Remarks

Any argument that is not a string will be formatted automatically. Boolean values will be 'true' or 'false' and numbers will have up to 6 digits past the decimal. Most string functions may be binary safe, but this function _will_ terminate its output at the first \0 character.

Examples

The following example demonstrates how to print multiple objects.

print("Hello", "world.\n");
The following example gives the same output as above, but note that using + to concatenate the strings means that print only receives one argument.

print("Hello"+"world.\n");

See Also

io.print()

runtime


Description

Returns the elapsed time the parser has been running.

Syntax

number = runtime()

Return Value

Returns the time in seconds (with microsecond precision) the parser has been running.

sizeof


Description

Returns the size of the object.

Syntax

number = sizeof(object)
ParameterDescription
object Object to be sized. The return value's meaning will vary depending on this object's type.

Return Value

Returns the size of the object. For strings, this is the string length; for tables, the number of non-null objects in the table. Null values are zero size.

sleep


Description

Sleep for a specified number of seconds.

Syntax

sleep(number seconds)
ParameterDescription
seconds Number of seconds the script should pause execution.

Return Value

Returns zero.

system


Description

Performs an operating system call and returns the resulting errorcode.

Syntax

number = system(string command)

ParameterDescription
command Operating system command to be executed.

Return Value

Returns the errorcode after execution of command.

Remarks

This function does not include or easily allow any sophisticated methods such as piping, signal handling, or interactivity.

Examples

The following example demonstrates a way to list a directory and then read the results.

system("ls"+" -l"+" > x.txt");
print(file.readall("x.txt"));
file.unlink("x.txt");

tonumber


Description

Returns a number value equivalent of the source.

Syntax

number = tonumber(object)
ParameterDescription
object Object to be converted to a numeric value.

Return Value

Returns a numeric approximation of the object parameter. Objects such as tables and null will return zero since no other numeric value can be meaningfully representative.

tostring


Description

Returns a string value equivalent of the source.

Syntax

string = tostring(object[, number])
ParameterDescription
object Object to be converted to a numeric value.
number Precision to use for a numeric object.

Return Value

Returns a string value equivalent of the source. If both arguments are numbers, the second allows the setting of a decimal precision.

typeof


Description

Returns the name of the type of object.

Syntax

string = typeof(object)
ParameterDescription
object Object to be identified by type.

Return Value

Returns the name of the object type. Possible types include boolean, number, string, table, function and null.

write


Description

Writes the entire object as a string and returns the result code. This function is binary safe.

Syntax

number = write(object)
ParameterDescription
object Object to be written to standard output.

Return Value

Returns the number of bytes written.

See Also

io.write()

3 - file.*()


(string) file.append(string filename[, object]);

Writes the entire object to the end of an existing file as a string and returns the result code. This function is binary safe.

(string) file.mkdir(string dirname[, number mode]);


(string) file.read(string filename);

Reads the entire file into a string and returns that string. This function is binary safe, but use of some string functions to manipulate this string may mangle the data.

(string) file.rename(string filename, string newfilename);

Renames a file.

(table) file.stat(string filename);

Stats filename and returns a table with stats.

(number) file.write(string filename[, object]);

Writes the entire object as a string and returns the result code. This function is binary safe.

4 - io.*()

io.flush


Description

Flushes the output buffer.

Syntax

number = io.flush()

Return Value

Returns zero.

io.print


Description

Print the complete list of arguments to the standard output.

Syntax

number = io.print(...)
ParameterDescription
... List of objects to be printed.

Return Value

Returns the number of characters printed.

Remarks

Any argument that is not a string will be formatted automatically. Boolean values will be 'true' or 'false' and numbers will have up to 6 digits past the decimal. Most string functions may be binary safe, but this function _will_ terminate its output at the first \0 character.

Examples

The following example demonstrates how to print multiple objects.

io.print("Hello", "world.\n");
The following example gives the same output as above, but note that using + to concatenate the strings means that print only receives one argument.

io.print("Hello"+"world.\n");

See Also

print()

io.write


Description

Writes the entire object as a string and returns the result code. This function is binary safe.

Syntax

number = io.write(object)
ParameterDescription
object Object to be written to standard output.

Return Value

Returns the number of bytes written.

See Also

write()

5 - math.*()


(number) math.abs(number n);


(number) math.acos(number n);


(number) math.asin(number n);


(number) math.atan(number n);


(number) math.atan(number n);


(number) math.ceil(number n);


(number) math.cos(number n);

This page is not here.
This page is not here.

(number) math.floor(number n);

This page is not here.
This page is not here.

(number) math.rand([number range]);


(number) math.sin(number n);

This page is not here.

(number) math.sqrt(number n);


(number) math.tan(number n);

This page is not here.

6 - string.*()

A series of functions exist in the string namespace for working with strings. Most of these functions can also be accessed as methods of the base type itself. For example, 's.sub(0, 2)' is the equivalent of 'string.sub(s, 0, 2)' (assuming 's' is a string). A list of these methods is shown here.

Methods

Method Name Description
gettype() Returns a string describing the base type of a string, which is always "string".
istr(string x) Returns a substring starting at the point of the first case-insensitive match of x in the string, or null if no match is found.
length()
aka len()
Returns the length of the string.
replace(string x) Returns a new string with occurences of x in this string replaced.
split(string x, string y) Returns a table containing substrings of x, separated by y.
str(string x) Returns a substring starting at the point of the first match of x in the string, or null if no match is found.
substring(number x, [number y])
aka sub(number x, [number y])
Return a substring starting at index x, and continuing for y characters. If x is negative, the substring starting point is the end of the string minux x.
tolower() Returns a lower-case copy of the string.
tostring()
aka tostr()
Returns a string representation of the object. If the object is already a string, an unmodified copy of the original is returned.
toupper() Returns an upper-case copy of the string.
pages = {
	{ name="string.atoi",    tag="atoi"    };
	{ name="string.cat",     tag="cat"     };
	{ name="string.cmp",     tag="cmp"     };
	{ name="string.icmp",    tag="icmp"    };
//	{ name="string.istr",    tag="istr"    };
	{ name="string.itoa",    tag="itoa"    };
	{ name="string.join",    tag="join"    };
//	{ name="string.len",     tag="len"     };
	{ name="string.ncmp",    tag="ncmp"    };
	{ name="string.nicmp",   tag="nicmp"   };
//	{ name="string.replace", tag="replace" };
//	{ name="string.split",   tag="split"   };
//	{ name="string.str",     tag="str"     };
//	{ name="string.sub",     tag="sub"     };
//	{ name="string.tolower", tag="tolower" };
//	{ name="string.toupper", tag="toupper" };
};

(string) string.cat(string str1, string str2);


string.cat(x, y) will not change x or y. to set x to the result, use "x=string.cat(x, y)"
actually, all string functions should work like this (by not modifying the original arguments.


(number) string.cmp(string str1, string str2);

Case sensitive string comparison.

(number) string.icmp(string str1, string str2);

Case insensitive string comparison.

(string) string.istr(string stack, string needle);

Case insensitive substring search.

(table) string.join(table str, string sep);

This will merge the table str into a single string separated by sep.

(number) string.len(string str);

Length of the string (binary safe).

(number) string.ncmp(string str1, string str2, number len);

Case sensitive substring comparison up to len characters.

(number) string.nicmp(string str1, string str2, number len);

Case insensitive substring comparison up to len characters.
string.replace(string x, string y);

(table) string.split(string str, string sep);

This will separate the string into substrings and put those substrings in the returned table.

(string) string.str(string stack, string needle);

Case sensitive substring search.

(string) string.sub(string stack, number offset[, number maxlen]);

Returns a substring ranging from offset to maxlen.

string.tolower


Description

Returns a lower case version of the supplied string.

string.toupper


Description

Returns an upper case version of the supplied string.

7 - time.*()

time.gmtime


Description

Returns a table representation of timestamp. If timestamp is not defined, the function will use the current local system date.

time.localtime


Description

Returns a table representation of timestamp. If timestamp is not defined, the function will use the current local system date.

time.now


Description

Returns the elapsed time in seconds since January 1, 1970.

Syntax

number = time()

Return Value

Returns the time in seconds since the creation of the UNIXverse.

time.sqldate


Description

Returns a string representation of timestamp in the format 'YYYY-MM-DD'. If timestamp is not defined, the function will use the current local system date.

Syntax

string = sqldate([number timestamp])
ParameterDescription
timestamp The number of seconds since January 1, 1970 UTC (commonly called a UNIX timestamp).

Return Value

Returns a formatted date string in the format 'YYYY-MM-DD'.

Remarks

No remarks.

Examples

print(sqldate());

The above example will output something similar to: "2015-01-01"
print(sqldate(0)+" "+sqltime(0));

The above example will output something similar to (note the adjustment for local time): "1969-12-31 19:00:00"

See Also

time.sqltime()

time.sqltime


Description

Returns a string representation of timestamp in the format 'HH:MM:SS'. If timestamp is not defined, the function will use the current local system time.

Syntax

string = sqltime([number timestamp])
ParameterDescription
timestamp The number of seconds since January 1, 1970 UTC (commonly called a UNIX timestamp).

Return Value

Returns a formatted time string in the format 'HH:MM:SS'.

Remarks

No remarks.

Examples

print(sqltime());

The above example will output something similar to: "16:30:45"
print(sqldate(0)+" "+sqltime(0));

The above example will output something similar to (note the adjustment for local time): "1969-12-31 19:00:00"

See Also

time.sqldate()

8 - data.*()

This page is not here.
This page is not here.
This page is not here.
This page is not here.
This page is not here.
This page is not here.
This page is not here.
This page is not here.
This page is not here.
This page is not here.

(table) xml.read(string str);

Read the supplied XML text and return a digested table. This is _not_ a pretty function.

9 - The Extension Libraries

neslaext functions


(string) base64.decode(string encoded);

Return a decoded value from a base64-encoded string.

(string) base64.encode(string decoded);

Return an encoded value from a raw string.

(table) dirlist(string dirname);

Returns a table containing files and attributes in the supplied dirname.

(string) rot13(string str);

Returns a rot13 *cough* encoded string from str.
Double-rot13 encryption is so stealthy, you won't even know it's been encrypted.

(number) sort.bykey(table t, string subkey);


(number) sort.byname(table t[, number recursive]);

10 - net.*()

This page is not here.
This page is not here.
This page is not here.

(table) http.get(number ssl, string host, number port, string uri);

Connect to an HTTP server and retrieve the requested uri. Returns a table with { head, body } elements.


This page is not here.
This page is not here.
This page is not here.
This page is not here.
This page is not here.
This page is not here.

ssh.open


Description

Cloae an SSH connection.

Syntax

number = ssh.close(conn)
ParameterDescription
conn Server connection object to be closed.

Return Value

Always returns zero.

Remarks

None

Example

The following example demonstrates how to close a host connection.

ssh.close(conn);

ssh.open


Description

Open an SSH connection to a given host/port.

Syntax

ssh-conn = ssh.open(hostname[, port])
ParameterDescription
hostname String containing the name of the server to connect to.
port Number containing the server port to connect to (default is 22).

Return Value

Returns an ssh-conn connection object if successful. Any number returned likely indicates an error.

Remarks

None

Example

The following example demonstrates how to connect to a host and verify success.

if (typeof(conn=ssh.open("192.168.0.1", 22))!='ssh-conn') {
    print("failed connection");
    exit;
}
/* checking the host's RSA key fingerprint is optional, but a good idea. */
key="ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff";
if ((k=ssh.hostkey(conn))!=key) {
    print("expected = "+key+"\nrecieved = "+k+"\n");
    print("Host key verification failed.\n");
    exit;
}
print("RSA key fingerprint is "+k+".\n");
if (ssh.auth(conn, "username", "password")!=true) {
    print("failed auth");
    exit;
}
/*
 * do something useful here
 */

ssh.close(conn);
This page is not here.

net.tcp.socket


Description

Returns an object that can be used as either a client or a listening socket.

Methods

NameDescription
bindBinds a socket to the specified local host and port.
connectConnects a socket to the specified remote host and port.
acceptCreates a new socket for incoming requests to a bound socket.
closeCloses a socket and destroys the socket object.
getsReads a line of text from an open socket.
readReads incoming data from an open socket.
writeWrites data to an open socket.
infoReturns information about an open socket.

Remarks

None.

Examples

#!/usr/bin/nsp
function test_http() {
        print("trying http://localhost:80/   - ");
        sock=new net.tcp.socket();
        sock.connect("localhost", 80, false);
        if (typeof(sock.socket)!='sock4') {
                print("can't connect to http server\n");
                return;
        }
        o=sock.write("GET / HTTP/1.0\r\n\r\n");
        i=sock.gets();
        printf("[%s]\n", i);
        do {
                i=sock.gets();
        } while (i!="");
        do {
                i=sock.read();
        } while (i!="");
        sock.close();
}
test_http();

(sock4) tcp.accept(sock4 bindsock);


(sock4) tcp.bind(string host, number port, number ssl);


(number) tcp.close(sock4 socket);


(string) tcp.gets(sock4 socket);


(sock4) tcp.info(sock4 socket);

Returns a table containing information about the socket.

(sock4) tcp.open(string host, number port, number ssl);


(string) tcp.read(sock4 socket);


(number) tcp.write(sock4 socket, string str);

11 - The C API

I'm lazy, so here's the long ugly version. This is everything your C program will ever need to know about Nesla. Actually, it needs to know a lot less, but hey.

/* NESLA NullLogic Embedded Scripting Language Copyright (C) 2007-2015 Dan Cahill This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _NSP_H #define _NSP_H 1 #ifdef __cplusplus extern "C" { #endif #define NSP_NAME "nesla" #define NSP_VERSION "0.9.4" #if defined(TINYCC)||defined(__TURBOC__) struct timeval { long tv_sec; long tv_usec; }; struct timezone { int tz_minuteswest; int tz_dsttime; }; #endif #if defined(_MSC_VER) struct timezone { int tz_minuteswest; int tz_dsttime; }; #pragma warning(disable:4996) #define WIN32_LEAN_AND_MEAN #define _USE_32BIT_TIME_T /* always include winsock2 before windows */ #include <winsock2.h> #include <windows.h> #include <time.h> #if defined(WIN32) && defined(_DEBUG) #include <crtdbg.h> #endif #elif !defined(__TURBOC__) #include <sys/time.h> #include <stddef.h> #endif #include <setjmp.h> /* need to add size sanity here */ #if defined(__TURBOC__) typedef signed long int int32; typedef unsigned long int uint32; #elif defined(_LP64) typedef signed int int32; typedef unsigned int uint32; #else typedef signed int int32; typedef unsigned int uint32; #endif typedef signed char int8; typedef unsigned char uint8; #define MAX_OBJNAMELEN 64 #define MAX_OUTBUFSIZE 4096 #define OUTBUFLOWAT 2048 /* object types */ #define NT_NULL 0 #define NT_BOOLEAN 1 #define NT_NUMBER 2 #define NT_STRING 3 #define NT_NFUNC 4 #define NT_CFUNC 5 #define NT_TABLE 6 #define NT_CDATA 7 /* object status flags */ #define NST_HIDDEN 0x01 #define NST_READONLY 0x02 #define NST_SYSTEM 0x04 #define NST_AUTOSORT 0x08 #define NST_LINK 0x10 #define NST_STACKVAL 0x20 #define num_t double #define uchar unsigned char #define obj_t struct nsp_objrec #define tab_t struct nsp_tablerec #define val_t struct nsp_valrec #define nsp_t struct nsp_state /* should be typedef int(*NSP_CFUNC)(nsp_state *); */ typedef int(*NSP_CFUNC)(void *); #define NSP_FUNCTION(name) int name(nsp_state *N) #define NSP_CLASS(name) int name(nsp_state *N) #define NSP_CLASSMETHOD(name) int name(nsp_state *N) /* * define a callback function type so CDATA objects * can choose the terms of their own death. */ /* should be typedef void(*NSP_CFREE)(nsp_state *, obj_t *); */ typedef void(*NSP_CFREE)(void *, void *); typedef struct NSP_CDATA { /* standard header info for CDATA object */ char obj_type[16]; /* tell us all about yourself in 15 characters or less */ NSP_CFREE obj_term; /* now tell us how to kill you */ /* now begin the stuff that's type-specific */ } NSP_CDATA; typedef struct nsp_tablerec { obj_t *f; obj_t *i; obj_t *l; } nsp_tablerec; typedef struct nsp_valrec { unsigned short type; /* val type */ unsigned short attr; /* status flags (hidden, readonly, system, autosort, etc...) */ unsigned short refs; /* number of references to this node */ unsigned long size; /* storage size of string, nfunc or cdata */ obj_t *ztable; /* 'z' table for hierarchical lookups */ union { num_t num; char *str; NSP_CFUNC cfunc; NSP_CDATA *cdata; tab_t table; } d; } nsp_valrec; typedef struct nsp_objrec { obj_t *prev; obj_t *next; val_t *val; uint32 hash; signed long nval; char name[MAX_OBJNAMELEN + 1]; } nsp_objrec; typedef struct nsp_state { uchar *blockptr; uchar *blockend; uchar *readptr; obj_t g; obj_t l; obj_t r; short brk; short cnt; short ret; short err; short signal; /* intended for external signals to the parser. for now, non-zero just means to shut down */ short debug; short single; short strict; short warnings; short maxwarnings; char warnformat; jmp_buf *savjmp; struct timeval ttime; char numbuf[128]; char *outbuffer; unsigned short outbuflen; unsigned short outbufmax; char errbuf[256]; char *func; char *file; char *tracefn; /* debug info */ long int line_num; long int allocs; long int allocmem; long int frees; long int freemem; long int peakmem; long int counter1; } nsp_state; #ifndef NSP_NOFUNCTIONS /* exec */ nsp_state *nsp_newstate(void); void nsp_freestate(nsp_state *N); nsp_state *nsp_endstate(nsp_state *N); obj_t *nsp_exec(nsp_state *N, const char *string); int nsp_execfile(nsp_state *N, char *file); /* objects */ void nsp_setvaltype(nsp_state *N, obj_t *cobj, unsigned short type); void nsp_linkval(nsp_state *N, obj_t *cobj1, obj_t *cobj2); void nsp_unlinkval(nsp_state *N, obj_t *cobj); void nsp_freetable(nsp_state *N, obj_t *tobj); obj_t *nsp_getobj_ex(nsp_state *N, obj_t *tobj, char *oname, unsigned short followz, unsigned short *foundz); obj_t *nsp_getobj(nsp_state *N, obj_t *tobj, char *oname); obj_t *nsp_getiobj(nsp_state *N, obj_t *tobj, unsigned long oindex); obj_t *nsp_setobj(nsp_state *N, obj_t *tobj, char *oname, unsigned short otype, NSP_CFUNC _fptr, num_t _num, char *_str, size_t _slen); void nsp_strcat(nsp_state *N, obj_t *cobj, char *str, long len); void nsp_strmul(nsp_state *N, obj_t *cobj, unsigned long n); short nsp_tobool(nsp_state *N, obj_t *cobj); num_t nsp_tonum(nsp_state *N, obj_t *cobj); char *nsp_tostr(nsp_state *N, obj_t *cobj); char *nsp_zlink(nsp_state *N, obj_t *cobj1, obj_t *cobj2); /* parser */ obj_t *nsp_eval(nsp_state *N, const char *string); obj_t *nsp_evalf(nsp_state *N, const char *fmt, ...); #endif //#define nsp_isnull(o) (o==NULL||o->val==NULL||o->val->type==NT_NULL) #define nsp_isnull(o) (o==NULL||o->val==NULL||o->val->type==NT_NULL) #define nsp_isbool(o) (o!=NULL&&o->val!=NULL&&o->val->type==NT_BOOLEAN) #define nsp_isnum(o) (o!=NULL&&o->val!=NULL&&o->val->type==NT_NUMBER) #define nsp_isstr(o) (o!=NULL&&o->val!=NULL&&o->val->type==NT_STRING) #define nsp_istable(o) (o!=NULL&&o->val!=NULL&&o->val->type==NT_TABLE) #define nsp_istrue(o) (nsp_tobool(N, o)?1:0) #define nsp_typeof(o) (nsp_isnull(o)?NT_NULL:o->val->type) #define nsp_getnum(N,o,n) nsp_tonum(N, nsp_getobj(N,o,n)) #define nsp_getstr(N,o,n) nsp_tostr(N, nsp_getobj(N,o,n)) #define nsp_setnull(N,t,n) nsp_setobj(N, t, n, NT_NULL, (NSP_CFUNC)NULL, 0, NULL, 0) #define nsp_setnum(N,t,n,v) nsp_setobj(N, t, n, NT_NUMBER, (NSP_CFUNC)NULL, v, NULL, 0) #define nsp_setbool(N,t,n,v) nsp_setobj(N, t, n, NT_BOOLEAN, (NSP_CFUNC)NULL, v?1:0, NULL, 0) #define nsp_setstr(N,t,n,s,l) nsp_setobj(N, t, n, NT_STRING, (NSP_CFUNC)NULL, 0, s, l) #define nsp_settable(N,t,n) nsp_setobj(N, t, n, NT_TABLE, (NSP_CFUNC)NULL, 0, NULL, 0) #define nsp_setcfunc(N,t,n,p) nsp_setobj(N, t, n, NT_CFUNC, (NSP_CFUNC)p, 0, NULL, 0) #define nsp_setnfunc(N,t,n,s,l) nsp_setobj(N, t, n, NT_NFUNC, (NSP_CFUNC)NULL, 0, s, l) #define nsp_setcdata(N,t,n,s,l) nsp_setobj(N, t, n, NT_CDATA, (NSP_CFUNC)NULL, 0, (void *)s, l) #define nsp_setinum(N,t,n,v) nsp_setiobj(N, t, n, NT_NUMBER, (NSP_CFUNC)NULL, v, NULL, 0) #define nsp_setistr(N,t,n,s,l) nsp_setiobj(N, t, n, NT_STRING, (NSP_CFUNC)NULL, 0, s, l) #define nsp_setitable(N,t,n) nsp_setiobj(N, t, n, NT_TABLE, (NSP_CFUNC)NULL, 0, NULL, 0) #define nsp_seticfunc(N,t,n,p) nsp_setiobj(N, t, n, NT_CFUNC, (NSP_CFUNC)p, 0, NULL, 0) #define nsp_setinfunc(N,t,n,s,l) nsp_setiobj(N, t, n, NT_NFUNC, (NSP_CFUNC)NULL, 0, s, l) #define nsp_seticdata(N,t,n,s,l) nsp_setiobj(N, t, n, NT_CDATA, (NSP_CFUNC)NULL, 0, (void *)s, l) #ifdef __cplusplus } #endif #ifdef __cplusplus class NesObject { public: NesObject() { /* memset(O, 0, sizeof(O)); */ } ~NesObject() { /* nsp_unlink(O); */ } const char *errbuf() { /* return this->N->errbuf; */ } private: obj_t O; }; class NSPState { private: nsp_state *N; public: NSPState() { this->N=nsp_newstate(); } ~NSPState() { nsp_endstate(this->N); } obj_t *exec(const char *string) { return nsp_exec(this->N, string); } int execfile(char *file) { return nsp_execfile(this->N, file); } obj_t *eval(const char *string) { return nsp_eval(this->N, string); } /* obj_t *evalf(const char *fmt, ...) { return nsp_evalf(this->N, fmt, ...); } */ obj_t *getG() { return &this->N->g; } obj_t *getL() { return &this->N->l; } nsp_t *getN() { return this->N; } void setdebug(int x) { this->N->debug=x; } int err() { return this->N->err; } int warnings() { return this->N->warnings; } const char *errbuf() { return this->N->errbuf; } }; #endif #endif /* _NSP_H */