• tcl解释器——C语言


    注:区区做了一点点扩展,让这个小TCL能进行字符串的最最基本操作:连接和单字符提取。。。

    /**//* Tcl in ~ 500 lines of code by Salvatore antirez Sanfilippo. BSD licensed */
    /**//* Hacked by Joyer : add '.' and '|' command to support basic string op*/
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    enum ...{PICOL_OK, PICOL_ERR, PICOL_RETURN, PICOL_BREAK, PICOL_CONTINUE};
    enum ...{PT_ESC,PT_STR,PT_CMD,PT_VAR,PT_SEP,PT_EOL,PT_EOF};
    
    struct picolParser ...{
        char *text;
        char *p; /**//* current text position */
        int len; /**//* remaining length */
        char *start; /**//* token start */
        char *end; /**//* token end */
        int type; /**//* token type, PT_... */
        int insidequote; /**//* True if inside " " */
    };
    
    struct picolVar ...{
        char *name, *val;
        struct picolVar *next;
    };
    
    struct picolInterp; /**//* forward declaration */
    typedef int (*picolCmdFunc)(struct picolInterp *i, int argc, char **argv, void *privdata);
    
    struct picolCmd ...{
        char *name;
        picolCmdFunc func;
        void *privdata;
        struct picolCmd *next;
    };
    
    struct picolCallFrame ...{
        struct picolVar *vars;
        struct picolCallFrame *parent; /**//* parent is NULL at top level */
    };
    
    struct picolInterp ...{
        int level; /**//* Level of nesting */
        struct picolCallFrame *callframe;
        struct picolCmd *commands;
        char *result;
    };
    
    void picolInitParser(struct picolParser *p, char *text) ...{
        p->text = p->p = text;
        p->len = strlen(text);
        p->start = 0; p->end = 0; p->insidequote = 0;
        p->type = PT_EOL;
    }
    
    int picolParseSep(struct picolParser *p) ...{
        p->start = p->p;
        while(*p->p == ' ' || *p->p == ' ' || *p->p == ' ' || *p->p == ' ') ...{
            p->p++; p->len--;
        }
        p->end = p->p-1;
        p->type = PT_SEP;
        return PICOL_OK;
    }
    
    int picolParseEol(struct picolParser *p) ...{
        p->start = p->p;
        while(*p->p == ' ' || *p->p == ' ' || *p->p == ' ' || *p->p == ' ' ||
              *p->p == ';')
        ...{
            p->p++; p->len--;
        }
        p->end = p->p-1;
        p->type = PT_EOL;
        return PICOL_OK;
    }
    
    int picolParseCommand(struct picolParser *p) ...{
        int level = 1;
        int blevel = 0;
        p->start = ++p->p; p->len--;
        while (1) ...{
            if (p->len == 0) ...{
                break;
            } else if (*p->p == '[' && blevel == 0) ...{
                level++;
            } else if (*p->p == ']' && blevel == 0) ...{
                if (!--level) break;
            } else if (*p->p == '') ...{
                p->p++; p->len--;
            } else if (*p->p == '{') ...{
                blevel++;
            } else if (*p->p == '}') ...{
                if (blevel != 0) blevel--;
            }
            p->p++; p->len--;
        }
        p->end = p->p-1;
        p->type = PT_CMD;
        if (*p->p == ']') ...{
            p->p++; p->len--;
        }
        return PICOL_OK;
    }
    
    int picolParseVar(struct picolParser *p) ...{
        p->start = ++p->p; p->len--; /**//* skip the $ */
        while(1) ...{
            if ((*p->p >= 'a' && *p->p <= 'z') || (*p->p >= 'A' && *p->p <= 'Z') ||
                (*p->p >= '0' && *p->p <= '9') || *p->p == '_')
            ...{
                p->p++; p->len--; continue;
            }
            break;
        }
        if (p->start == p->p) ...{ /**//* It's just a single char string "$" */
            p->start = p->end = p->p-1;
            p->type = PT_STR;
        } else ...{
            p->end = p->p-1;
            p->type = PT_VAR;
        }
        return PICOL_OK;
    }
    
    int picolParseBrace(struct picolParser *p) ...{
        int level = 1;
        p->start = ++p->p; p->len--;
        while(1) ...{
            if (p->len >= 2 && *p->p == '') ...{
                p->p++; p->len--;
            } else if (p->len == 0 || *p->p == '}') ...{
                level--;
                if (level == 0 || p->len == 0) ...{
                    p->end = p->p-1;
                    if (p->len) ...{
                        p->p++; p->len--; /**//* Skip final closed brace */
                    }
                    p->type = PT_STR;
                    return PICOL_OK;
                }
            } else if (*p->p == '{')
                level++;
            p->p++; p->len--;
        }
        return PICOL_OK; /**//* unreached */
    }
    
    int picolParseString(struct picolParser *p) ...{
        int newword = (p->type == PT_SEP || p->type == PT_EOL || p->type == PT_STR);
        if (newword && *p->p == '{') return picolParseBrace(p);
        else if (newword && *p->p == '"') ...{
            p->insidequote = 1;
            p->p++; p->len--;
        }
        p->start = p->p;
        while(1) ...{
            if (p->len == 0) ...{
                p->end = p->p-1;
                p->type = PT_ESC;
                return PICOL_OK;
            }
            switch(*p->p) ...{
            case '':
                if (p->len >= 2) ...{
                    p->p++; p->len--;
                }
                break;
            case '$': case '[':
                p->end = p->p-1;
                p->type = PT_ESC;
                return PICOL_OK;
            case ' ': case ' ': case ' ': case ' ': case ';':
                if (!p->insidequote) ...{
                    p->end = p->p-1;
                    p->type = PT_ESC;
                    return PICOL_OK;
                }
                break;
            case '"':
                if (p->insidequote) ...{
                    p->end = p->p-1;
                    p->type = PT_ESC;
                    p->p++; p->len--;
                    p->insidequote = 0;
                    return PICOL_OK;
                }
                break;
            }
            p->p++; p->len--;
        }
        return PICOL_OK; /**//* unreached */
    }
    
    int picolParseComment(struct picolParser *p) ...{
        while(p->len && *p->p != ' ') ...{
            p->p++; p->len--;
        }
        return PICOL_OK;
    }
    
    int picolGetToken(struct picolParser *p) ...{
        while(1) ...{
            if (!p->len) ...{
                if (p->type != PT_EOL && p->type != PT_EOF)
                    p->type = PT_EOL;
                else
                    p->type = PT_EOF;
                return PICOL_OK;
            }
            switch(*p->p) ...{
            case ' ': case ' ': case ' ':
                if (p->insidequote) return picolParseString(p);
                return picolParseSep(p);
            case ' ': case ';':
                if (p->insidequote) return picolParseString(p);
                return picolParseEol(p);
            case '[':
                return picolParseCommand(p);
            case '$':
                return picolParseVar(p);
            case '#':
                if (p->type == PT_EOL) ...{
                    picolParseComment(p);
                    continue;
                }
                return picolParseString(p);
            default:
                return picolParseString(p);
            }
        }
        return PICOL_OK; /**//* unreached */
    }
    
    void picolInitInterp(struct picolInterp *i) ...{
        i->level = 0;
        i->callframe = malloc(sizeof(struct picolCallFrame));
        i->callframe->vars = NULL;
        i->callframe->parent = NULL;
        i->commands = NULL;
        i->result = strdup("");
    }
    
    void picolSetResult(struct picolInterp *i, char *s) ...{
        free(i->result);
        i->result = strdup(s);
    }
    
    struct picolVar *picolGetVar(struct picolInterp *i, char *name) ...{
        struct picolVar *v = i->callframe->vars;
        while(v) ...{
            if (strcmp(v->name,name) == 0) return v;
            v = v->next;
        }
        return NULL;
    }
    
    int picolSetVar(struct picolInterp *i, char *name, char *val) ...{
        struct picolVar *v = picolGetVar(i,name);
        if (v) ...{
            free(v->val);
            v->val = strdup(val);
        } else ...{
            v = malloc(sizeof(*v));
            v->name = strdup(name);
            v->val = strdup(val);
            v->next = i->callframe->vars;
            i->callframe->vars = v;
        }
        return PICOL_OK;
    }
    
    struct picolCmd *picolGetCommand(struct picolInterp *i, char *name) ...{
        struct picolCmd *c = i->commands;
        while(c) ...{
            if (strcmp(c->name,name) == 0) return c;
            c = c->next;
        }
        return NULL;
    }
    
    int picolRegisterCommand(struct picolInterp *i, char *name, picolCmdFunc f, void *privdata) ...{
        struct picolCmd *c = picolGetCommand(i,name);
        char errbuf[1024];
        if (c) ...{
            snprintf(errbuf,1024,"Command '%s' already defined",name);
            picolSetResult(i,errbuf);
            return PICOL_ERR;
        }
        c = malloc(sizeof(*c));
        c->name = strdup(name);
        c->func = f;
        c->privdata = privdata;
        c->next = i->commands;
        i->commands = c;
        return PICOL_OK;
    }
    
    /**//* EVAL! */
    int picolEval(struct picolInterp *i, char *t) ...{
        struct picolParser p;
        int argc = 0, j;
        char **argv = NULL;
        char errbuf[1024];
        int retcode = PICOL_OK;
        picolSetResult(i,"");
        picolInitParser(&p,t);
        while(1) ...{
            char *t;
            int tlen;
            int prevtype = p.type;
            picolGetToken(&p);
            if (p.type == PT_EOF) break;
            tlen = p.end-p.start+1;
            if (tlen < 0) tlen = 0;
            t = malloc(tlen+1);
            memcpy(t, p.start, tlen);
            t[tlen] = '';
            if (p.type == PT_VAR) ...{
                struct picolVar *v = picolGetVar(i,t);
                if (!v) ...{
                    snprintf(errbuf,1024,"No such variable '%s'",t);
                    free(t);
                    picolSetResult(i,errbuf);
                    retcode = PICOL_ERR;
                    goto err;
                }
                free(t);
                t = strdup(v->val);
            } else if (p.type == PT_CMD) ...{
                retcode = picolEval(i,t);
                free(t);
                if (retcode != PICOL_OK) goto err;
                t = strdup(i->result);
            } else if (p.type == PT_ESC) ...{
                /**//* XXX: escape handling missing! */
            } else if (p.type == PT_SEP) ...{
                prevtype = p.type;
                free(t);
                continue;
            }
            /**//* We have a complete command + args. Call it! */
            if (p.type == PT_EOL) ...{
                struct picolCmd *c;
                free(t);
                prevtype = p.type;
                if (argc) ...{
                    if ((c = picolGetCommand(i,argv[0])) == NULL) ...{
                        snprintf(errbuf,1024,"No such command '%s'",argv[0]);
                        picolSetResult(i,errbuf);
                        retcode = PICOL_ERR;
                        goto err;
                    }
                    retcode = c->func(i,argc,argv,c->privdata);
                    if (retcode != PICOL_OK) goto err;
                }
                /**//* Prepare for the next command */
                for (j = 0; j < argc; j++) free(argv[j]);
                free(argv);
                argv = NULL;
                argc = 0;
                continue;
            }
            /**//* We have a new token, append to the previous or as new arg? */
            if (prevtype == PT_SEP || prevtype == PT_EOL) ...{
                argv = realloc(argv, sizeof(char*)*(argc+1));
                argv[argc] = t;
                argc++;
            } else ...{ /**//* Interpolation */
                int oldlen = strlen(argv[argc-1]), tlen = strlen(t);
                argv[argc-1] = realloc(argv[argc-1], oldlen+tlen+1);
                memcpy(argv[argc-1]+oldlen, t, tlen);
                argv[argc-1][oldlen+tlen]='';
                free(t);
            }
            prevtype = p.type;
        }
    err:
        for (j = 0; j < argc; j++) free(argv[j]);
        free(argv);
        return retcode;
    }
    
    /**//* ACTUAL COMMANDS! */
    int picolArityErr(struct picolInterp *i, char *name) ...{
        char buf[1024];
        snprintf(buf,1024,"Wrong number of args for %s",name);
        picolSetResult(i,buf);
        return PICOL_ERR;
    }
    
    int picolCommandMath(struct picolInterp *i, int argc, char **argv, void *pd) ...{
      char rawbuf[1024]; int a, b, c, len; char *buf = rawbuf;
        if (argc != 3) return picolArityErr(i,argv[0]);
        a = atoi(argv[1]); b = atoi(argv[2]);
        if (argv[0][0] == '+') c = a+b;
        else if (argv[0][0] == '-') c = a-b;
        else if (argv[0][0] == '*') c = a*b;
        else if (argv[0][0] == '/') c = a/b;
        else if (argv[0][0] == '>' && argv[0][1] == '') c = a > b;
        else if (argv[0][0] == '>' && argv[0][1] == '=') c = a >= b;
        else if (argv[0][0] == '<' && argv[0][1] == '') c = a < b;
        else if (argv[0][0] == '<' && argv[0][1] == '=') c = a <= b;
        else if (argv[0][0] == '=' && argv[0][1] == '=') c = a == b;
        else if (argv[0][0] == '!' && argv[0][1] == '=') c = a != b;
        else if (argv[0][0] == '.') ...{ /**//*字符串连接*/
          len = strlen(argv[1]) + strlen(argv[2]);
          if (len>1024)...{
        buf = malloc(len+1);
        len = len+1;
          }
          else...{
        len=1024;
          }
          snprintf(buf, len, "%s%s", argv[1], argv[2]);
          picolSetResult(i,buf);
          if (buf!=rawbuf)
        free(buf);
          return PICOL_OK;
        }
        else if (argv[0][0] == '|') ...{ /**//*字符串提取*/
          snprintf(buf, 1024, "%c", argv[1][b]);
          picolSetResult(i,buf);
          return PICOL_OK;
        }
        else c = 0; /**//* I hate warnings */
        snprintf(buf,64,"%d",c);
        picolSetResult(i,buf);
        return PICOL_OK;
    }
    
    int picolCommandSet(struct picolInterp *i, int argc, char **argv, void *pd) ...{
        if (argc != 3) return picolArityErr(i,argv[0]);
        picolSetVar(i,argv[1],argv[2]);
        picolSetResult(i,argv[2]);
        return PICOL_OK;
    }
    
    int picolCommandPuts(struct picolInterp *i, int argc, char **argv, void *pd) ...{
        if (argc != 2) return picolArityErr(i,argv[0]);
        printf("%s ", argv[1]);
        return PICOL_OK;
    }
    
    int picolCommandIf(struct picolInterp *i, int argc, char **argv, void *pd) ...{
        int retcode;
        if (argc != 3 && argc != 5) return picolArityErr(i,argv[0]);
        if ((retcode = picolEval(i,argv[1])) != PICOL_OK) return retcode;
        if (atoi(i->result)) return picolEval(i,argv[2]);
        else if (argc == 5) return picolEval(i,argv[4]);
        return PICOL_OK;
    }
    
    int picolCommandWhile(struct picolInterp *i, int argc, char **argv, void *pd) ...{
        if (argc != 3) return picolArityErr(i,argv[0]);
        while(1) ...{
            int retcode = picolEval(i,argv[1]);
            if (retcode != PICOL_OK) return retcode;
            if (atoi(i->result)) ...{
                if ((retcode = picolEval(i,argv[2])) == PICOL_CONTINUE) continue;
                else if (retcode == PICOL_OK) continue;
                else if (retcode == PICOL_BREAK) return PICOL_OK;
                else return retcode;
            } else ...{
                return PICOL_OK;
            }
        }
    }
    
    int picolCommandRetCodes(struct picolInterp *i, int argc, char **argv, void *pd) ...{
        if (argc != 1) return picolArityErr(i,argv[0]);
        if (strcmp(argv[0],"break") == 0) return PICOL_BREAK;
        else if (strcmp(argv[0],"continue") == 0) return PICOL_CONTINUE;
        return PICOL_OK;
    }
    
    void picolDropCallFrame(struct picolInterp *i) ...{
        struct picolCallFrame *cf = i->callframe;
        struct picolVar *v = cf->vars, *t;
        while(v) ...{
            t = v->next;
            free(v->name);
            free(v->val);
            free(v);
            v = t;
        }
        i->callframe = cf->parent;
        free(cf);
    }
    
    int picolCommandCallProc(struct picolInterp *i, int argc, char **argv, void *pd) ...{
        char **x=pd, *alist=x[0], *body=x[1], *p=strdup(alist), *tofree;
        struct picolCallFrame *cf = malloc(sizeof(*cf));
        int arity = 0, done = 0, errcode = PICOL_OK;
        char errbuf[1024];
        cf->vars = NULL;
        cf->parent = i->callframe;
        i->callframe = cf;
        tofree = p;
        while(1) ...{
            char *start = p;
            while(*p != ' ' && *p != '') p++;
            if (*p != '' && p == start) ...{
                p++; continue;
            }
            if (p == start) break;
            if (*p == '') done=1; else *p = '';
            if (++arity > argc-1) goto arityerr;
            picolSetVar(i,start,argv[arity]);
            p++;
            if (done) break;
        }
        free(tofree);
        if (arity != argc-1) goto arityerr;
        errcode = picolEval(i,body);
        if (errcode == PICOL_RETURN) errcode = PICOL_OK;
        picolDropCallFrame(i); /**//* remove the called proc callframe */
        return errcode;
    arityerr:
        snprintf(errbuf,1024,"Proc '%s' called with wrong arg num",argv[0]);
        picolSetResult(i,errbuf);
        picolDropCallFrame(i); /**//* remove the called proc callframe */
        return PICOL_ERR;
    }
    
    int picolCommandProc(struct picolInterp *i, int argc, char **argv, void *pd) ...{
        char **procdata = malloc(sizeof(char*)*2);
        if (argc != 4) return picolArityErr(i,argv[0]);
        procdata[0] = strdup(argv[2]); /**//* arguments list */
        procdata[1] = strdup(argv[3]); /**//* procedure body */
        return picolRegisterCommand(i,argv[1],picolCommandCallProc,procdata);
    }
    
    int picolCommandReturn(struct picolInterp *i, int argc, char **argv, void *pd) ...{
        if (argc != 1 && argc != 2) return picolArityErr(i,argv[0]);
        picolSetResult(i, (argc == 2) ? argv[1] : "");
        return PICOL_RETURN;
    }
    
    void picolRegisterCoreCommands(struct picolInterp *i) ...{
      int j; char *name[] = ...{"+","-","*","/",">",">=","<","<=","==","!=",".","|"};
        for (j = 0; j < (int)(sizeof(name)/sizeof(char*)); j++)
            picolRegisterCommand(i,name[j],picolCommandMath,NULL);
        picolRegisterCommand(i,"set",picolCommandSet,NULL);
        picolRegisterCommand(i,"puts",picolCommandPuts,NULL);
        picolRegisterCommand(i,"if",picolCommandIf,NULL);
        picolRegisterCommand(i,"while",picolCommandWhile,NULL);
        picolRegisterCommand(i,"break",picolCommandRetCodes,NULL);
        picolRegisterCommand(i,"continue",picolCommandRetCodes,NULL);
        picolRegisterCommand(i,"proc",picolCommandProc,NULL);
        picolRegisterCommand(i,"return",picolCommandReturn,NULL);
    }
    
    int main(int argc, char **argv) ...{
        struct picolInterp interp;
        picolInitInterp(&interp);
        picolRegisterCoreCommands(&interp);
        if (argc == 1) ...{
            while(1) ...{
                char clibuf[1024];
                int retcode;
                printf("picol> "); fflush(stdout);
                if (fgets(clibuf,1024,stdin) == NULL) return 0;
                retcode = picolEval(&interp,clibuf);
                if (interp.result[0] != '')
                    printf("[%d] %s ", retcode, interp.result);
            }
        } else if (argc == 2) ...{
            char buf[1024*16];
            FILE *fp = fopen(argv[1],"r");
            if (!fp) ...{
                perror("open"); exit(1);
            }
            buf[fread(buf,1,1024*16,fp)] = '';
            fclose(fp);
            if (picolEval(&interp,buf) != PICOL_OK) printf("%s ", interp.result);
        }
        return 0;
    }
  • 相关阅读:
    用图片来代替字符串
    下载网页时的 有gzip压缩的处理
    位置不固定验证码的识别
    CookieContainer 与 Session
    Thread Pool 备忘
    用 SGMLReader把子HTML 转 XML
    非asp.net控件实现回发 button
    ajax.net ??= 回车
    如何写需求分析
    jsp中地址
  • 原文地址:https://www.cnblogs.com/church/p/2612104.html
Copyright © 2020-2023  润新知