@@ -57,8 +57,14 @@
#include "config.h"
#include "subscript.h"
#include <assert.h>
+#if INTERFACE
+typedef struct Subscript Subscript;
+#define SBS_OK 0
+#define SBS_ERROR 1
+#endif
+
/*
** Configuration constants
*/
#define SBSCONFIG_NHASH 41 /* Size of the hash table */
@@ -157,9 +163,9 @@
int size; /* Number of bytes in string, not counting final zero */
char *z; /* Pointer to string content */
} str; /* Value if SBSVAL_STR */
struct {
- int (*xVerb)(Subscript*), void*); /* Function to do the work */
+ int (*xVerb)(Subscript*, void*); /* Function to do the work */
void *pArg; /* 2nd parameter to xVerb */
} verb; /* Value if SBSVAL_VERB */
} u;
};
@@ -183,11 +189,11 @@
/*
** An entry in the hash table is an instance of this structure.
*/
-typedef struct UsHashEntry UsHashEntry;
-struct UsHashEntry {
- UsHashEntry *pNext; /* Next entry with the same hash on zKey */
+typedef struct SbsHashEntry SbsHashEntry;
+struct SbsHashEntry {
+ SbsHashEntry *pNext; /* Next entry with the same hash on zKey */
SbSValue val; /* The payload */
int nKey; /* Length of the key */
char zKey[0]; /* The key */
};
@@ -194,11 +200,11 @@
/*
** A hash table is an instance of the following structure.
*/
-typedef struct UsHashTab UsHashTab;
-struct UsHashTab {
- UsHashEntry *aHash[SBSCONFIG_NHASH]; /* The hash table */
+typedef struct SbsHashTab SbsHashTab;
+struct SbsHashTab {
+ SbsHashEntry *aHash[SBSCONFIG_NHASH]; /* The hash table */
};
/*
** Compute a hash on a string.
@@ -217,14 +223,14 @@
** Look up a value in the hash table. Return a pointer to the value.
** Return NULL if not found.
*/
static const SbSValue *sbs_fetch(
- sbs_hash *pHash,
+ SbsHashTab *pHash,
const char *zKey,
int nKey
){
int h;
- UsHashEntry *p;
+ SbsHashEntry *p;
if( nKey<0 ) nKey = strlen(zKey);
h = sbs_hash(zKey, nKey);
for(p = pHash->aHash[h]; p; p=p->pNext){
@@ -242,15 +248,15 @@
** If the value in the 4th argument needs to be reset or freed,
** the hash table will take over responsibiliity for doing so.
*/
static int sbs_store(
- sbs_hash *pHash, /* Insert into this hash table */
- const char *zKey, /* The key */
- int nKey, /* Size of the key */
+ SbsHashTab *pHash, /* Insert into this hash table */
+ const char *zKey, /* The key */
+ int nKey, /* Size of the key */
const SbSValue *pValue /* The value to be stored */
){
int h;
- UsHashEntry *p;
+ SbsHashEntry *p, *pNew;
if( nKey<0 ) nKey = strlen(zKey);
h = sbs_hash(zKey, nKey);
for(p = pHash->aHash[h]; p; p=p->pNext){
@@ -274,11 +280,11 @@
/*
** Reset a hash table.
*/
-static void sbs_hash_reset(sbs_hash *pHash){
+static void sbs_hash_reset(SbsHashTab *pHash){
int i;
- UsHashEntry *p, *pNext;
+ SbsHashEntry *p, *pNext;
for(i=0; i<SBSCONFIG_NHASH; i++){
for(p=pHash->aHash[i]; p; p=pNext){
pNext = p->pNext;
sbs_value_reset(&p->val);
@@ -292,19 +298,17 @@
** An instance of the Subscript interpreter
*/
struct Subscript {
int nStack; /* Number of entries on stack */
- UsHashTab symTab; /* The symbol table */
+ SbsHashTab symTab; /* The symbol table */
char zErrMsg[SBSCONFIG_ERRSIZE]; /* Space to write an error message */
SbSValue aStack[SBSCONFIG_NSTACK]; /* The stack */
};
-
/*
** Push a value onto the stack of an interpreter
*/
static int sbs_push(Subscript *p, SbSValue *pVal){
- SbSValue *pStk;
if( p->nStack>=SBSCONFIG_NSTACK ){
sqlite3_snprintf(SBSCONFIG_ERRSIZE, p->zErrMsg, "stack overflow");
return SBS_ERROR;
}
@@ -372,15 +376,15 @@
** Return 0 on success and non-zero if there is an error.
*/
int SbS_Push(
struct Subscript *p, /* Push onto this interpreter */
- const char *z, /* String value to push */
- int n, /* Length of the string, or -1 */
- int dyn /* If true, z was obtained from malloc */
+ char *z, /* String value to push */
+ int n, /* Length of the string, or -1 */
+ int dyn /* If true, z was obtained from malloc */
){
SbSValue v;
v.flags = SBSVAL_STR;
- if( needToFree ){
+ if( dyn ){
v.flags |= SBSVAL_DYN;
}
if( n<0 ) n = strlen(z);
v.u.str.size = n;
@@ -456,9 +460,9 @@
*/
int SbS_StackValueInt(struct Subscript *p, int N){
int n, v;
int isNeg = 0;
- char *z = SbS_StackValue(p, N, &n);
+ const char *z = SbS_StackValue(p, N, &n);
v = 0;
if( n==0 ) return 0;
if( z[0]=='-' ){
isNeg = 1;
@@ -491,9 +495,9 @@
struct Subscript *p, /* The interpreter we are interrogating */
const char *zKey, /* Name of the variable. Case sensitive */
int *pLength /* Write the length here */
){
- SbSValue *pVal;
+ const SbSValue *pVal;
pVal = sbs_fetch(&p->symTab, zKey, -1);
if( pVal==0 || (pVal->flags & SBSVAL_STR)==0 ){
*pLength = 0;
@@ -509,32 +513,97 @@
** fewer than N elements. This is utility routine used in
** the implementation of verbs.
*/
int SbS_RequireStack(struct Subscript *p, int N, const char *zCmd){
- if( p->nStack>N ) return 0;
+ if( p->nStack>=N ) return 0;
sqlite3_snprintf(sizeof(p->zErrMsg), p->zErrMsg,
"\"%s\" requires at least %d stack elements - only found %d",
zCmd, N, p->nStack);
return 1;
}
/*
-** The built-in "set" command:
-**
-** STRING NAME set
+** Subscript command: STRING NAME set
**
** Write the value of STRING into variable called NAME.
*/
static int setCmd(Subscript *p, void *pNotUsed){
SbSValue *pTos;
SbSValue *pNos;
if( SbS_RequireStack(p, 2, "set") ) return SBS_ERROR;
- pTos = p->aStack[--p->nStack];
- pNos = p->aStack[--p->nStack];
+ pTos = &p->aStack[--p->nStack];
+ pNos = &p->aStack[--p->nStack];
sbs_store(&p->symTab, pTos->u.str.z, pTos->u.str.size, pNos);
sbs_value_reset(pTos);
return 0;
}
+
+/*
+** Subscript command: INTEGER not INTEGER
+*/
+static int notCmd(struct Subscript *p, void *pNotUsed){
+ int n;
+ if( SbS_RequireStack(p, 1, "not") ) return 1;
+ n = SbS_StackValueInt(p, 0);
+ SbS_Pop(p, 1);
+ SbS_PushInt(p, !n);
+ return 0;
+}
+
+/*
+** Subscript command: INTEGER INTEGER max INTEGER
+*/
+static int maxCmd(struct Subscript *p, void *pNotUsed){
+ int a, b;
+ if( SbS_RequireStack(p, 2, "max") ) return 1;
+ a = SbS_StackValueInt(p, 0);
+ b = SbS_StackValueInt(p, 1);
+ SbS_Pop(p, 2);
+ SbS_PushInt(p, a>b ? a : b);
+ return 0;
+}
+
+/*
+** Subscript command: INTEGER INTEGER and INTEGER
+*/
+static int andCmd(struct Subscript *p, void *pNotUsed){
+ int a, b;
+ if( SbS_RequireStack(p, 2, "max") ) return 1;
+ a = SbS_StackValueInt(p, 0);
+ b = SbS_StackValueInt(p, 1);
+ SbS_Pop(p, 2);
+ SbS_PushInt(p, a && b);
+ return 0;
+}
+
+/*
+** Subscript command: STRING puts
+*/
+static int putsCmd(struct Subscript *p, void *pNotUsed){
+ int size;
+ const char *z;
+ if( SbS_RequireStack(p, 1, "puts") ) return 1;
+ z = SbS_StackValue(p, 0, &size);
+ printf("%.*s\n", size, z);
+ SbS_Pop(p, 1);
+ return 0;
+}
+
+
+/*
+** A table of built-in commands
+*/
+static const struct {
+ const char *zCmd;
+ int nCmd;
+ int (*xCmd)(Subscript*,void*);
+} aBuiltin[] = {
+ { "and", 3, andCmd },
+ { "max", 3, maxCmd },
+ { "not", 3, notCmd },
+ { "puts", 4, putsCmd },
+ { "set", 3, setCmd },
+};
/*
** Create a new subscript interpreter
@@ -544,9 +613,8 @@
p = malloc( sizeof(*p) );
if( p ){
memset(p, 0, sizeof(*p));
- SbS_AddVerb(p, "set", setCmd, 0);
}
return p;
}
@@ -559,9 +627,9 @@
if( nScript<0 ) nScript = strlen(zScript);
while( nScript>0 && rc==SBS_OK ){
int n;
int ttype;
- n = sbs_token_type(zScript, nScript, &ttype);
+ n = sbs_next_token(zScript, nScript, &ttype);
switch( ttype ){
case SBSTT_WHITESPACE: {
break;
}
@@ -575,29 +643,43 @@
nScript = n;
break;
}
case SBSTT_INTEGER: {
- rc = sbs_push(p, zScript, n);
+ rc = SbS_Push(p, (char*)zScript, n, 0);
break;
}
case SBSTT_NAME: {
- rc = sbs_push(p, &zScript[1], n-1);
+ rc = SbS_Push(p, (char*)&zScript[1], n-1, 0);
break;
}
case SBSTT_STRING: {
- rc = sbs_push(p, &zScript[1], n-2);
+ rc = SbS_Push(p, (char*)&zScript[1], n-2, 0);
break;
}
case SBSTT_VERB: {
- SbSValue *pVal = sbs_fetch(p->pHash, zScript, nScript);
+ const SbSValue *pVal = sbs_fetch(&p->symTab, (char*)zScript, n);
if( pVal==0 ){
+ int upr = sizeof(aBuiltin)/sizeof(aBuiltin[0]) - 1;
+ int lwr = 0;
rc = SBS_ERROR;
+ while( upr>=lwr ){
+ int i = (upr+lwr)/2;
+ int c = strncmp(zScript, aBuiltin[i].zCmd, n);
+ if( c==0 ){
+ rc = aBuiltin[i].xCmd(p, 0);
+ break;
+ }else if( c<0 ){
+ upr = i-1;
+ }else{
+ lwr = i+1;
+ }
+ }
}else if( pVal->flags & SBSVAL_VERB ){
rc = pVal->u.verb.xVerb(p, pVal->u.verb.pArg);
}else if( pVal->flags & SBSVAL_EXEC ){
rc = SbS_Eval(p, pVal->u.str.z, pVal->u.str.size);
}else{
- rc = sbs_push(p, pVal->u.str.z, pVal->u.str.size);
+ rc = SbS_Push(p, pVal->u.str.z, pVal->u.str.size, 0);
}
break;
}
}
@@ -604,5 +686,17 @@
zScript += n;
nScript -= n;
}
return rc;
+}
+
+/*
+** COMMAND: test-subscript
+*/
+void test_subscript(void){
+ Subscript *p;
+ if( g.argc<3 ){
+ usage("SCRIPT");
+ }
+ p = SbS_Create();
+ SbS_Eval(p, g.argv[2], strlen(g.argv[2]));
}