简体   繁体   中英

Converting a string to a line of code in C

I am trying to find a way to convert a string to the lines of my code.

For example, i want to try someting like this:

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

So that this program outputs "6" (3+3). I want to this for building a function plotter.. But here I get stuck and can't find any way. Would you please show me a way to convert these strings to lines of code?

That's not possible. C is not a reflective language and doesn't have any sort of eval() .

You could of course invoke an external compiler and run the resulting program, or you could try and find a compiler library that includes a C compiler in your program, but there's no "native" solution.

AC program is statically compiled, once, and the compiled binary retains no knowledge of the fact that it was written in C. The compilation process is entirely unconnected to the program runtime. Typically, only interpreted languages offer eval() , because the interpreter is active during program execution and can dynamically manipulate the program code. In a compiled language like C, this entire idea doesn't fit in, or make sense even.

If you want to write a calculator, you'll have to implement your own parser and computation logic.

You'd have to parse and evaluate expression yourself. C++ doesn't postpone till runtime what it can do at compile-time.

You cannot dynamically compile or evaluate code written in C (actually you can, but it is not that trivial, as it requires you to embed a compiler or an interpreter). The best approach would be to use a scripting language like Lua, Python, JavaScript etc.

Lua has a good interpreter written in C which is small and fast (Blizzard uses it to script WoW). If you need more performance, look at V8, the JavaScript engine from Google Chrome, which is an advanced scripting engine that features JIT compilation and much more. Or you could use Python, Perl, Ruby or even PHP. The downside of using a scripting language is that you must learn a second language in order to build your program, but the benefits will show up shortly.

Note that these are only few examples, but there are thousands of libraries that do this job really well, and you must decide which is the best for your particular needs.

#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;
}

DEMO

>calc
x + 3
6

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

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

From what I understand, you would like to replace at runtime your 4th line str by anything the user gave on the standard input of your program. In your example, the user would type something like below (at your program command prompt) :

(x+3);

and your 4th line of code would then look like :

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

It is not possible in C or C++ or any statically compiled language. Your compilation procedure happens and has to successfully complete before you can go to runtime. Thus, if you were able to modify the source code then, you would have to recompile before being able to execute a code taking into account your new line. Clearly not a good approach to your problem.

If you are sure that you want to/have to do this in C and not in some interpreted language, have a look at Lex and Yacc.

As already stated by others here, C is not an interpreted language, thus you cannot use C to interprete commands right away. In other words, you'd have to provide (develop) an interpreter in C.

Lexx and Yacc greatly simplify the process of writing an interpreter, although this is a rather advanved topic, I'm afraid.

Look here for a starter: http://epaperpress.com/lexandyacc/

Above all, I believe you don't understand well the problem you want to solve... Read more about interpreters

First, the local x is not visible outside its block, so even if you had some magical meta-programming evaluator you won't be able to do what you want.

In addition of what other people suggest (coding your domain specific language, embedding an existing interpreter, ...) -and assuming you use Linux- you might consider using TinyCC which also gives a "libtcc.h" containing a tcc_compile_string function which compiles a string containing C code to (poor) machine code.

You can also generate machine code with LLVM , GNU lightning , LibJit

You could also generate C code, run its compilation into a shared object, and dynamically load it with dlopen

What you want to do is expression evaluation . I suggest 2 methods which perhaps help you to get closer to the expected solution.

  1. Evaluate the expression with a binary tree: build a tree wich represents the expression and the precedence among the operators.

  2. May be it was mentioned above. Polish-form, stack-based evaluation. First build the polish-form of the original expression with a stack, and than evaluate the polish-form with a stack again. And the last: use google with these keywoards :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM