📄 jim.c
字号:
pc->tstart = ++pc->p; pc->len--;
pc->tline = pc->linenr;
while (1) {
if (*pc->p == '\\' && pc->len >= 2) {
pc->p++; pc->len--;
if (*pc->p == '\n')
pc->linenr++;
} else if (*pc->p == '{') {
level++;
} else if (pc->len == 0 || *pc->p == '}') {
level--;
if (pc->len == 0 || level == 0) {
pc->tend = pc->p-1;
if (pc->len != 0) {
pc->p++; pc->len--;
}
pc->tt = JIM_TT_STR;
return JIM_OK;
}
} else if (*pc->p == '\n') {
pc->linenr++;
}
pc->p++; pc->len--;
}
return JIM_OK; /* unreached */
}
int JimParseStr(struct JimParserCtx *pc)
{
int newword = (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR);
if (newword && *pc->p == '{') {
return JimParseBrace(pc);
} else if (newword && *pc->p == '"') {
pc->state = JIM_PS_QUOTE;
pc->p++; pc->len--;
}
pc->tstart = pc->p;
pc->tline = pc->linenr;
while (1) {
if (pc->len == 0) {
pc->tend = pc->p-1;
pc->tt = JIM_TT_ESC;
return JIM_OK;
}
switch(*pc->p) {
case '\\':
if (pc->state == JIM_PS_DEF &&
*(pc->p+1) == '\n') {
pc->tend = pc->p-1;
pc->tt = JIM_TT_ESC;
return JIM_OK;
}
if (pc->len >= 2) {
pc->p++; pc->len--;
}
break;
case '$':
case '[':
pc->tend = pc->p-1;
pc->tt = JIM_TT_ESC;
return JIM_OK;
case ' ':
case '\t':
case '\n':
case '\r':
case ';':
if (pc->state == JIM_PS_DEF) {
pc->tend = pc->p-1;
pc->tt = JIM_TT_ESC;
return JIM_OK;
} else if (*pc->p == '\n') {
pc->linenr++;
}
break;
case '"':
if (pc->state == JIM_PS_QUOTE) {
pc->tend = pc->p-1;
pc->tt = JIM_TT_ESC;
pc->p++; pc->len--;
pc->state = JIM_PS_DEF;
return JIM_OK;
}
break;
}
pc->p++; pc->len--;
}
return JIM_OK; /* unreached */
}
int JimParseComment(struct JimParserCtx *pc)
{
while (*pc->p) {
if (*pc->p == '\n') {
pc->linenr++;
if (*(pc->p-1) != '\\') {
pc->p++; pc->len--;
return JIM_OK;
}
}
pc->p++; pc->len--;
}
return JIM_OK;
}
/* xdigitval and odigitval are helper functions for JimParserGetToken() */
static int xdigitval(int c)
{
if (c >= '0' && c <= '9') return c-'0';
if (c >= 'a' && c <= 'f') return c-'a'+10;
if (c >= 'A' && c <= 'F') return c-'A'+10;
return -1;
}
static int odigitval(int c)
{
if (c >= '0' && c <= '7') return c-'0';
return -1;
}
/* Perform Tcl escape substitution of 's', storing the result
* string into 'dest'. The escaped string is guaranteed to
* be the same length or shorted than the source string.
* Slen is the length of the string at 's', if it's -1 the string
* length will be calculated by the function.
*
* The function returns the length of the resulting string. */
static int JimEscape(char *dest, const char *s, int slen)
{
char *p = dest;
int i, len;
if (slen == -1)
slen = strlen(s);
for (i = 0; i < slen; i++) {
switch(s[i]) {
case '\\':
switch(s[i+1]) {
case 'a': *p++ = 0x7; i++; break;
case 'b': *p++ = 0x8; i++; break;
case 'f': *p++ = 0xc; i++; break;
case 'n': *p++ = 0xa; i++; break;
case 'r': *p++ = 0xd; i++; break;
case 't': *p++ = 0x9; i++; break;
case 'v': *p++ = 0xb; i++; break;
case '\0': *p++ = '\\'; i++; break;
case '\n': *p++ = ' '; i++; break;
default:
if (s[i+1] == 'x') {
int val = 0;
int c = xdigitval(s[i+2]);
if (c == -1) {
*p++ = 'x';
i++;
break;
}
val = c;
c = xdigitval(s[i+3]);
if (c == -1) {
*p++ = val;
i += 2;
break;
}
val = (val*16)+c;
*p++ = val;
i += 3;
break;
} else if (s[i+1] >= '0' && s[i+1] <= '7')
{
int val = 0;
int c = odigitval(s[i+1]);
val = c;
c = odigitval(s[i+2]);
if (c == -1) {
*p++ = val;
i ++;
break;
}
val = (val*8)+c;
c = odigitval(s[i+3]);
if (c == -1) {
*p++ = val;
i += 2;
break;
}
val = (val*8)+c;
*p++ = val;
i += 3;
} else {
*p++ = s[i+1];
i++;
}
break;
}
break;
default:
*p++ = s[i];
break;
}
}
len = p-dest;
*p++ = '\0';
return len;
}
/* Returns a dynamically allocated copy of the current token in the
* parser context. The function perform conversion of escapes if
* the token is of type JIM_TT_ESC.
*
* Note that after the conversion, tokens that are grouped with
* braces in the source code, are always recognizable from the
* identical string obtained in a different way from the type.
*
* For exmple the string:
*
* {expand}$a
*
* will return as first token "expand", of type JIM_TT_STR
*
* While the string:
*
* expand$a
*
* will return as first token "expand", of type JIM_TT_ESC
*/
char *JimParserGetToken(struct JimParserCtx *pc,
int *lenPtr, int *typePtr, int *linePtr)
{
const char *start, *end;
char *token;
int len;
start = JimParserTstart(pc);
end = JimParserTend(pc);
if (start > end) {
if (lenPtr) *lenPtr = 0;
if (typePtr) *typePtr = JimParserTtype(pc);
if (linePtr) *linePtr = JimParserTline(pc);
token = Jim_Alloc(1);
token[0] = '\0';
return token;
}
len = (end-start)+1;
token = Jim_Alloc(len+1);
if (JimParserTtype(pc) != JIM_TT_ESC) {
/* No escape conversion needed? Just copy it. */
memcpy(token, start, len);
token[len] = '\0';
} else {
/* Else convert the escape chars. */
len = JimEscape(token, start, len);
}
if (lenPtr) *lenPtr = len;
if (typePtr) *typePtr = JimParserTtype(pc);
if (linePtr) *linePtr = JimParserTline(pc);
return token;
}
/* The following functin is not really part of the parsing engine of Jim,
* but it somewhat related. Given an string and its length, it tries
* to guess if the script is complete or there are instead " " or { }
* open and not completed. This is useful for interactive shells
* implementation and for [info complete].
*
* If 'stateCharPtr' != NULL, the function stores ' ' on complete script,
* '{' on scripts incomplete missing one or more '}' to be balanced.
* '"' on scripts incomplete missing a '"' char.
*
* If the script is complete, 1 is returned, otherwise 0. */
int Jim_ScriptIsComplete(const char *s, int len, char *stateCharPtr)
{
int level = 0;
int state = ' ';
while(len) {
switch (*s) {
case '\\':
if (len > 1)
s++;
break;
case '"':
if (state == ' ') {
state = '"';
} else if (state == '"') {
state = ' ';
}
break;
case '{':
if (state == '{') {
level++;
} else if (state == ' ') {
state = '{';
level++;
}
break;
case '}':
if (state == '{') {
level--;
if (level == 0)
state = ' ';
}
break;
}
s++;
len--;
}
if (stateCharPtr)
*stateCharPtr = state;
return state == ' ';
}
/* -----------------------------------------------------------------------------
* Tcl Lists parsing
* ---------------------------------------------------------------------------*/
static int JimParseListSep(struct JimParserCtx *pc);
static int JimParseListStr(struct JimParserCtx *pc);
int JimParseList(struct JimParserCtx *pc)
{
if (pc->len == 0) {
pc->tstart = pc->tend = pc->p;
pc->tline = pc->linenr;
pc->tt = JIM_TT_EOL;
pc->eof = 1;
return JIM_OK;
}
switch(*pc->p) {
case ' ':
case '\n':
case '\t':
case '\r':
if (pc->state == JIM_PS_DEF)
return JimParseListSep(pc);
else
return JimParseListStr(pc);
break;
default:
return JimParseListStr(pc);
break;
}
return JIM_OK;
}
int JimParseListSep(struct JimParserCtx *pc)
{
pc->tstart = pc->p;
pc->tline = pc->linenr;
while (*pc->p == ' ' || *pc->p == '\t' || *pc->p == '\r' || *pc->p == '\n')
{
pc->p++; pc->len--;
}
pc->tend = pc->p-1;
pc->tt = JIM_TT_SEP;
return JIM_OK;
}
int JimParseListStr(struct JimParserCtx *pc)
{
int newword = (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
pc->tt == JIM_TT_NONE);
if (newword && *pc->p == '{') {
return JimParseBrace(pc);
} else if (newword && *pc->p == '"') {
pc->state = JIM_PS_QUOTE;
pc->p++; pc->len--;
}
pc->tstart = pc->p;
pc->tline = pc->linenr;
while (1) {
if (pc->len == 0) {
pc->tend = pc->p-1;
pc->tt = JIM_TT_ESC;
return JIM_OK;
}
switch(*pc->p) {
case '\\':
pc->p++; pc->len--;
break;
case ' ':
case '\t':
case '\n':
case '\r':
if (pc->state == JIM_PS_DEF) {
pc->tend = pc->p-1;
pc->tt = JIM_TT_ESC;
return JIM_OK;
} else if (*pc->p == '\n') {
pc->linenr++;
}
break;
case '"':
if (pc->state == JIM_PS_QUOTE) {
pc->tend = pc->p-1;
pc->tt = JIM_TT_ESC;
pc->p++; pc->len--;
pc->state = JIM_PS_DEF;
return JIM_OK;
}
break;
}
pc->p++; pc->len--;
}
return JIM_OK; /* unreached */
}
/* -----------------------------------------------------------------------------
* Jim_Obj related functions
* ---------------------------------------------------------------------------*/
/* Return a new initialized object. */
Jim_Obj *Jim_NewObj(Jim_Interp *interp)
{
Jim_Obj *objPtr;
/* -- Check if there are objects in the free list -- */
if (interp->freeList != NULL) {
/* -- Unlink the object from the free list -- */
objPtr = interp->freeList;
interp->freeList = objPtr->nextObjPtr;
} else {
/* -- No ready to use objects: allocate a new one -- */
objPtr = Jim_Alloc(sizeof(*objPtr));
}
/* Object is returned with refCount of 0. Every
* kind of GC implemented should take care to don't try
* to scan objects with refCount == 0. */
objPtr->refCount = 0;
/* All the other fields are left not initialized to save time.
* The caller will probably want set they to the right
* value anyway. */
/* -- Put the object into the live list -- */
objPtr->prevObjPtr = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -