📄 jim.c
字号:
/* ----------------------- StringCopy Hash Table Type ------------------------*/
static unsigned int JimStringCopyHTHashFunction(const void *key)
{
return Jim_GenHashFunction(key, strlen(key));
}
static const void *JimStringCopyHTKeyDup(void *privdata, const void *key)
{
int len = strlen(key);
char *copy = Jim_Alloc(len+1);
JIM_NOTUSED(privdata);
memcpy(copy, key, len);
copy[len] = '\0';
return copy;
}
static void *JimStringKeyValCopyHTValDup(void *privdata, const void *val)
{
int len = strlen(val);
char *copy = Jim_Alloc(len+1);
JIM_NOTUSED(privdata);
memcpy(copy, val, len);
copy[len] = '\0';
return copy;
}
static int JimStringCopyHTKeyCompare(void *privdata, const void *key1,
const void *key2)
{
JIM_NOTUSED(privdata);
return strcmp(key1, key2) == 0;
}
static void JimStringCopyHTKeyDestructor(void *privdata, const void *key)
{
JIM_NOTUSED(privdata);
Jim_Free((void*)key); /* ATTENTION: const cast */
}
static void JimStringKeyValCopyHTValDestructor(void *privdata, void *val)
{
JIM_NOTUSED(privdata);
Jim_Free((void*)val); /* ATTENTION: const cast */
}
static Jim_HashTableType JimStringCopyHashTableType = {
JimStringCopyHTHashFunction, /* hash function */
JimStringCopyHTKeyDup, /* key dup */
NULL, /* val dup */
JimStringCopyHTKeyCompare, /* key compare */
JimStringCopyHTKeyDestructor, /* key destructor */
NULL /* val destructor */
};
/* This is like StringCopy but does not auto-duplicate the key.
* It's used for intepreter's shared strings. */
static Jim_HashTableType JimSharedStringsHashTableType = {
JimStringCopyHTHashFunction, /* hash function */
NULL, /* key dup */
NULL, /* val dup */
JimStringCopyHTKeyCompare, /* key compare */
JimStringCopyHTKeyDestructor, /* key destructor */
NULL /* val destructor */
};
/* This is like StringCopy but also automatically handle dynamic
* allocated C strings as values. */
static Jim_HashTableType JimStringKeyValCopyHashTableType = {
JimStringCopyHTHashFunction, /* hash function */
JimStringCopyHTKeyDup, /* key dup */
JimStringKeyValCopyHTValDup, /* val dup */
JimStringCopyHTKeyCompare, /* key compare */
JimStringCopyHTKeyDestructor, /* key destructor */
JimStringKeyValCopyHTValDestructor, /* val destructor */
};
typedef struct AssocDataValue {
Jim_InterpDeleteProc *delProc;
void *data;
} AssocDataValue;
static void JimAssocDataHashTableValueDestructor(void *privdata, void *data)
{
AssocDataValue *assocPtr = (AssocDataValue *)data;
if (assocPtr->delProc != NULL)
assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data);
Jim_Free(data);
}
static Jim_HashTableType JimAssocDataHashTableType = {
JimStringCopyHTHashFunction, /* hash function */
JimStringCopyHTKeyDup, /* key dup */
NULL, /* val dup */
JimStringCopyHTKeyCompare, /* key compare */
JimStringCopyHTKeyDestructor, /* key destructor */
JimAssocDataHashTableValueDestructor /* val destructor */
};
/* -----------------------------------------------------------------------------
* Stack - This is a simple generic stack implementation. It is used for
* example in the 'expr' expression compiler.
* ---------------------------------------------------------------------------*/
void Jim_InitStack(Jim_Stack *stack)
{
stack->len = 0;
stack->maxlen = 0;
stack->vector = NULL;
}
void Jim_FreeStack(Jim_Stack *stack)
{
Jim_Free(stack->vector);
}
int Jim_StackLen(Jim_Stack *stack)
{
return stack->len;
}
void Jim_StackPush(Jim_Stack *stack, void *element) {
int neededLen = stack->len+1;
if (neededLen > stack->maxlen) {
stack->maxlen = neededLen*2;
stack->vector = Jim_Realloc(stack->vector, sizeof(void*)*stack->maxlen);
}
stack->vector[stack->len] = element;
stack->len++;
}
void *Jim_StackPop(Jim_Stack *stack)
{
if (stack->len == 0) return NULL;
stack->len--;
return stack->vector[stack->len];
}
void *Jim_StackPeek(Jim_Stack *stack)
{
if (stack->len == 0) return NULL;
return stack->vector[stack->len-1];
}
void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc)(void *ptr))
{
int i;
for (i = 0; i < stack->len; i++)
freeFunc(stack->vector[i]);
}
/* -----------------------------------------------------------------------------
* Parser
* ---------------------------------------------------------------------------*/
/* Token types */
#define JIM_TT_NONE -1 /* No token returned */
#define JIM_TT_STR 0 /* simple string */
#define JIM_TT_ESC 1 /* string that needs escape chars conversion */
#define JIM_TT_VAR 2 /* var substitution */
#define JIM_TT_DICTSUGAR 3 /* Syntax sugar for [dict get], $foo(bar) */
#define JIM_TT_CMD 4 /* command substitution */
#define JIM_TT_SEP 5 /* word separator */
#define JIM_TT_EOL 6 /* line separator */
/* Additional token types needed for expressions */
#define JIM_TT_SUBEXPR_START 7
#define JIM_TT_SUBEXPR_END 8
#define JIM_TT_EXPR_NUMBER 9
#define JIM_TT_EXPR_OPERATOR 10
/* Parser states */
#define JIM_PS_DEF 0 /* Default state */
#define JIM_PS_QUOTE 1 /* Inside "" */
/* Parser context structure. The same context is used both to parse
* Tcl scripts and lists. */
struct JimParserCtx {
const char *prg; /* Program text */
const char *p; /* Pointer to the point of the program we are parsing */
int len; /* Left length of 'prg' */
int linenr; /* Current line number */
const char *tstart;
const char *tend; /* Returned token is at tstart-tend in 'prg'. */
int tline; /* Line number of the returned token */
int tt; /* Token type */
int eof; /* Non zero if EOF condition is true. */
int state; /* Parser state */
int comment; /* Non zero if the next chars may be a comment. */
};
#define JimParserEof(c) ((c)->eof)
#define JimParserTstart(c) ((c)->tstart)
#define JimParserTend(c) ((c)->tend)
#define JimParserTtype(c) ((c)->tt)
#define JimParserTline(c) ((c)->tline)
static int JimParseScript(struct JimParserCtx *pc);
static int JimParseSep(struct JimParserCtx *pc);
static int JimParseEol(struct JimParserCtx *pc);
static int JimParseCmd(struct JimParserCtx *pc);
static int JimParseVar(struct JimParserCtx *pc);
static int JimParseBrace(struct JimParserCtx *pc);
static int JimParseStr(struct JimParserCtx *pc);
static int JimParseComment(struct JimParserCtx *pc);
static char *JimParserGetToken(struct JimParserCtx *pc,
int *lenPtr, int *typePtr, int *linePtr);
/* Initialize a parser context.
* 'prg' is a pointer to the program text, linenr is the line
* number of the first line contained in the program. */
void JimParserInit(struct JimParserCtx *pc, const char *prg,
int len, int linenr)
{
pc->prg = prg;
pc->p = prg;
pc->len = len;
pc->tstart = NULL;
pc->tend = NULL;
pc->tline = 0;
pc->tt = JIM_TT_NONE;
pc->eof = 0;
pc->state = JIM_PS_DEF;
pc->linenr = linenr;
pc->comment = 1;
}
int JimParseScript(struct JimParserCtx *pc)
{
while(1) { /* the while is used to reiterate with continue if needed */
if (!pc->len) {
pc->tstart = pc->p;
pc->tend = pc->p-1;
pc->tline = pc->linenr;
pc->tt = JIM_TT_EOL;
pc->eof = 1;
return JIM_OK;
}
switch(*(pc->p)) {
case '\\':
if (*(pc->p+1) == '\n')
return JimParseSep(pc);
else {
pc->comment = 0;
return JimParseStr(pc);
}
break;
case ' ':
case '\t':
case '\r':
if (pc->state == JIM_PS_DEF)
return JimParseSep(pc);
else {
pc->comment = 0;
return JimParseStr(pc);
}
break;
case '\n':
case ';':
pc->comment = 1;
if (pc->state == JIM_PS_DEF)
return JimParseEol(pc);
else
return JimParseStr(pc);
break;
case '[':
pc->comment = 0;
return JimParseCmd(pc);
break;
case '$':
pc->comment = 0;
if (JimParseVar(pc) == JIM_ERR) {
pc->tstart = pc->tend = pc->p++; pc->len--;
pc->tline = pc->linenr;
pc->tt = JIM_TT_STR;
return JIM_OK;
} else
return JIM_OK;
break;
case '#':
if (pc->comment) {
JimParseComment(pc);
continue;
} else {
return JimParseStr(pc);
}
default:
pc->comment = 0;
return JimParseStr(pc);
break;
}
return JIM_OK;
}
}
int JimParseSep(struct JimParserCtx *pc)
{
pc->tstart = pc->p;
pc->tline = pc->linenr;
while (*pc->p == ' ' || *pc->p == '\t' || *pc->p == '\r' ||
(*pc->p == '\\' && *(pc->p+1) == '\n')) {
if (*pc->p == '\\') {
pc->p++; pc->len--;
pc->linenr++;
}
pc->p++; pc->len--;
}
pc->tend = pc->p-1;
pc->tt = JIM_TT_SEP;
return JIM_OK;
}
int JimParseEol(struct JimParserCtx *pc)
{
pc->tstart = pc->p;
pc->tline = pc->linenr;
while (*pc->p == ' ' || *pc->p == '\n' ||
*pc->p == '\t' || *pc->p == '\r' || *pc->p == ';') {
if (*pc->p == '\n')
pc->linenr++;
pc->p++; pc->len--;
}
pc->tend = pc->p-1;
pc->tt = JIM_TT_EOL;
return JIM_OK;
}
/* Todo. Don't stop if ']' appears inside {} or quoted.
* Also should handle the case of puts [string length "]"] */
int JimParseCmd(struct JimParserCtx *pc)
{
int level = 1;
int blevel = 0;
pc->tstart = ++pc->p; pc->len--;
pc->tline = pc->linenr;
while (1) {
if (pc->len == 0) {
break;
} else if (*pc->p == '[' && blevel == 0) {
level++;
} else if (*pc->p == ']' && blevel == 0) {
level--;
if (!level) break;
} else if (*pc->p == '\\') {
pc->p++; pc->len--;
} else if (*pc->p == '{') {
blevel++;
} else if (*pc->p == '}') {
if (blevel != 0)
blevel--;
} else if (*pc->p == '\n')
pc->linenr++;
pc->p++; pc->len--;
}
pc->tend = pc->p-1;
pc->tt = JIM_TT_CMD;
if (*pc->p == ']') {
pc->p++; pc->len--;
}
return JIM_OK;
}
int JimParseVar(struct JimParserCtx *pc)
{
int brace = 0, stop = 0, ttype = JIM_TT_VAR;
pc->tstart = ++pc->p; pc->len--; /* skip the $ */
pc->tline = pc->linenr;
if (*pc->p == '{') {
pc->tstart = ++pc->p; pc->len--;
brace = 1;
}
if (brace) {
while (!stop) {
if (*pc->p == '}' || pc->len == 0) {
stop = 1;
if (pc->len == 0)
continue;
}
else if (*pc->p == '\n')
pc->linenr++;
pc->p++; pc->len--;
}
if (pc->len == 0)
pc->tend = pc->p-1;
else
pc->tend = pc->p-2;
} else {
while (!stop) {
if (!((*pc->p >= 'a' && *pc->p <= 'z') ||
(*pc->p >= 'A' && *pc->p <= 'Z') ||
(*pc->p >= '0' && *pc->p <= '9') || *pc->p == '_'))
stop = 1;
else {
pc->p++; pc->len--;
}
}
/* Parse [dict get] syntax sugar. */
if (*pc->p == '(') {
while (*pc->p != ')' && pc->len) {
pc->p++; pc->len--;
if (*pc->p == '\\' && pc->len >= 2) {
pc->p += 2; pc->len -= 2;
}
}
if (*pc->p != '\0') {
pc->p++; pc->len--;
}
ttype = JIM_TT_DICTSUGAR;
}
pc->tend = pc->p-1;
}
/* Check if we parsed just the '$' character.
* That's not a variable so an error is returned
* to tell the state machine to consider this '$' just
* a string. */
if (pc->tstart == pc->p) {
pc->p--; pc->len++;
return JIM_ERR;
}
pc->tt = ttype;
return JIM_OK;
}
int JimParseBrace(struct JimParserCtx *pc)
{
int level = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -