将字符串转换为C中的代码行

时间:2011-11-07 15:03:23

标签: c

我正在尝试找到一种将字符串转换为代码行的方法。

例如,我想尝试这样的事情:

int x=3;
char str[80];
gets(str);  // Assuming the user gives input: "x + 3"
y = str;
printf("%d",y); // Output: "6" (3 + 3)

这个程序输出“6”(3 + 3)。 我想建立一个功能绘图仪。但在这里我卡住了,找不到任何方法。你能告诉我一种将这些字符串转换为代码行的方法吗?

8 个答案:

答案 0 :(得分:8)

那是不可能的。 C不是反射语言,没有任何eval()

您当然可以调用外部编译器并运行生成的程序,或者您可以尝试在程序中找到包含C编译器的编译器库,但是没有“本机”解决方案。

C程序被静态编译一次,并且编译后的二进制文件不知道它是用C语言编写的。编译过程完全与程序运行时无关。通常,只有解释的语言提供eval(),因为解释器在程序执行期间处于活动状态,并且可以动态操作程序代码。在像C这样的编译语言中,这整个想法都不适合,甚至没有意义。

如果你想编写一个计算器,你必须实现自己的解析器和计算逻辑。

答案 1 :(得分:2)

您必须自己解析和评估表达式。 C ++不会推迟到运行时它在编译时可以做什么。

答案 2 :(得分:1)

你无法动态编译或评估用C编写的代码(实际上你可以,但它并不是那么简单,因为它要求你嵌入编译器或解释器)。最好的方法是使用Lua,Python,JavaScript等脚本语言。

Lua有一个很好的口译员,用C语写,小而快(暴雪用它来编写WoW脚本)。如果您需要更高的性能,请查看V8,这是Google Chrome的JavaScript引擎,它是一个高级脚本引擎,具有JIT编译功能等等。或者您可以使用Python,Perl,Ruby甚至PHP。使用脚本语言的缺点是你必须学习第二语言才能构建你的程序,但好处很快就会出现。

请注意,这些只是少数几个例子,但是有成千上万的图书馆能够很好地完成这项工作,您必须确定哪种图书馆最适合您的特定需求。

答案 3 :(得分:1)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

/*
int replace(source_string, search_string, replace_string, start_position, replace_limit, ignore_case, output_buff)
return value : count of replace
*/
int replace(const char *s, const char *find, const char *rep, size_t pos, int count, int ignore, char *buff){
    size_t i, len_f, len_r;
    int rep_count=0;
    int (*cmp)(const char*, const char*, size_t);

    cmp = (ignore) ?  strnicmp : strncmp;
    len_f = strlen(find);
    len_r = strlen(rep);

    for(i=0;i<pos;i++)//output until start position
        *buff++ = *s++;

    while(rep_count != count){
        if(cmp(s, find, len_f)){ //not match
            *buff++ = *s++;
        } else { //match
//          strncpy(buff, rep, len_r);
//          buff += len_r;
            for(i=0;i<len_r;i++)
                *buff++ = rep[i];
            s += len_f;
            rep_count++;
        }
        if(*s=='\0')//end of string
            break;
    }
    while(*s){ //rest string output
        *buff++ = *s++;
    }
    *buff = '\0';

    return rep_count;
}

#define MAXLEN    80
#define STACKSIZE 3

int calc(char *str){
/* "(3+5)*7-2" => 54  */
    char cstack[STACKSIZE]; /* op stack */
    int  vstack[STACKSIZE]; /* value stack */
    int  vsp,csp;
    int level;
    int sign=0;
    int wk=0;
    char buff[MAXLEN];
    char *p,*pwk,cwk;

    /* trim */
    for(pwk=p=str;*p;p++)
        if(*p=='\t' || *p==' ')
            continue;
        else
            *pwk++=*p;
    *pwk=*p;
    vsp=csp=STACKSIZE;
    cstack[--csp]='@';/* empty mark */
    p=str;
    while(*p){
        if(isdigit(*p)){
            if(sign==0)sign=1;
            wk=wk*10+ *p++ - '0';
        } else { /* Characters except the number of occurrences -> determined  the number  */
            if(sign!=0)vstack[--vsp]=sign*wk; /* push num */
            wk=0;             /* wk initialize for next step */
            sign=0;
            switch(*p){
            case '*':
            case '/':
                cwk=cstack[csp];
                if(cwk=='@' || cwk=='+' || cwk=='-')
                    cstack[--csp]=*p;
                else{
                    if(cwk=='*')
                        vstack[vsp+1]*=vstack[vsp];
                    else if(cwk=='/')
                        vstack[vsp+1]/=vstack[vsp];
                    vsp++;
                    cstack[csp]=*p;
                }
                p++;
                break;
            case '-':
                if(str==p){
                    sign=-1;
                    p++;
                    break;
                } else if(NULL!=strchr("*/+-",*(p-1))){
                    sign=-1;
                    p++;
                    break;
                }
            case '+':
                cwk=cstack[csp];
                if(cwk=='@')
                    cstack[--csp]=*p;
                else {
                    switch(cwk){
                    case '+':
                        vstack[vsp+1]+=vstack[vsp];break;
                    case '-':
                        vstack[vsp+1]-=vstack[vsp];break;
                    case '*':
                        vstack[vsp+1]*=vstack[vsp];break;
                    case '/':
                        vstack[vsp+1]/=vstack[vsp];break;
                    }
                    vsp++;
                    cstack[csp]=*p;
                }
                p++;
                break;
            case '(': /* (expression) -> call calc(expression) */
                p++;
                level=1;
                sign=1;
                for(pwk=buff;*p;p++){
                    if(*p==')'){
                        if(--level==0){
                            *pwk='\0';
                            wk=calc(buff);
                            break;
                        }
                    } else if(*p=='('){
                        level++;
                    }
                    *pwk++=*p;
                }
                if(level){/* paren unmatch */
                    *pwk='\0';
                    wk=calc(buff);
                } else
                    p++;
                break;
            case ')':/* never */
                p++;
                fprintf(stderr,"too many ')'\n");
                break;
            default:
                fprintf(stderr, "'%c'is  not allowed\n",*p++);
            }
        }
    }
    vstack[--vsp]=sign*wk;
    while('@'!=(cwk=cstack[csp++])){
        switch(cwk){
        case '+':
            vstack[vsp+1]+=vstack[vsp];break;
        case '-':
            vstack[vsp+1]-=vstack[vsp];break;
        case '*':
            vstack[vsp+1]*=vstack[vsp];break;
        case '/':
            vstack[vsp+1]/=vstack[vsp];break;
        }
        vsp++;
    }
    return (vstack[vsp]);
}

int main(void){
    int x = 3, y;
    char str[128];
    char buff[128];
    char strX[16];

    sprintf(strX, "%d", x);
    gets(str);
    replace(str, "x", strX, 0, -1, 1, buff);
    y = calc(buff);
    printf("%d\n", y);
    return 0;
}

<强>样本

>calc
x + 3
6

>calc
x * x + 2 * x + 1
16

>calc
(3+5)*7-2
54

答案 4 :(得分:0)

根据我的理解,您希望用您在程序的标准输入上提供的任何内容替换在运行时您的第4行 str 。在您的示例中,用户将键入类似下面的内容(在程序命令提示符下):

(x+3);

然后您的第4行代码如下:

y = (x+3); // assuming y was declared as an integer somewhere before

在C或C ++或任何静态编译的语言中是不可能的。您的编译过程发生并且必须先成功完成才能进入运行时。因此,如果您能够修改源代码,则必须重新编译才能在考虑新行的情况下执行代码。显然不是解决问题的好方法。

答案 5 :(得分:0)

如果您确定要/必须在C语言中执行此操作而不是某种解释语言,请查看Lex和Yacc。

正如其他人已经说过的那样,C不是解释性语言,因此您无法立即使用C来解释命令。换句话说,你必须用C语言提供(开发)一个翻译。

Lexx和Yacc极大地简化了编写口译员的过程,虽然这是一个相当有道理的话题,我很害怕。

在这里寻找首发:http://epaperpress.com/lexandyacc/

答案 6 :(得分:0)

最重要的是,我相信你不太了解你想要解决的问题...阅读更多关于口译员的信息

首先,本地x在其区块之外是不可见的,所以即使你有一些神奇的元编程评估器,你也无法做你想做的事。

除了其他人的建议(编写您的域特定语言,嵌入现有的解释器,......) - 并假设您使用Linux-您可以考虑使用TinyCC,它也提供“libtcc.h” “包含tcc_compile_string函数,该函数将包含C代码的字符串编译为(差)机器代码。

您还可以使用LLVMGNU lightningLibJit生成机器代码

您还可以生成C代码,将其编译运行到共享对象中,并使用dlopen

动态加载它

答案 7 :(得分:0)

您要做的是表达式评估。我建议使用两种方法来帮助您更接近预期的解决方案。

  1. 使用二叉树评估表达式:构建一个表示运算符之间的表达式和优先级的树。

  2. 可能是上面提到的。波兰形式,基于堆栈的评估。首先使用堆栈构建原始表达式的抛光形式,然后再次使用堆栈评估抛光形式。最后一个:使用google与这些keywoards:)