Преобразование строки в строку кода в 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). Я хочу это для построения функции плоттера. Но здесь я застреваю и не могу найти никакого способа. Не могли бы вы показать мне способ конвертировать эти строки в строки кода?

То, что вы хотите сделать, это оценка выражений . Я предлагаю 2 метода, которые, возможно, помогут вам приблизиться к ожидаемому решению.

  1. Оцените выражение с помощью двоичного дерева: постройте дерево, которое представляет выражение и приоритет среди операторов.

  2. Может быть, это было упомянуто выше. Польская форма, оценка на основе стека. Сначала создайте польский формат исходного выражения со стеком, а затем снова оцените полировку. И последнее: используйте Google с этими клавишами 🙂

Это невозможно. C не является отражающим языком и не имеет своего рода eval() .

Конечно, вы могли бы вызвать внешний компилятор и запустить результирующую программу, или вы могли бы попробовать найти библиотеку компилятора, которая содержит компилятор C в вашей программе, но нет «родного» решения.

Программа AC статически компилируется один раз, а скомпилированный двоичный файл не знает о том, что он был написан на C. Процесс компиляции полностью не связан с исполняемой программой. Как правило, только интерпретируемые языки предлагают eval() , потому что интерпретатор активен во время выполнения программы и может динамически манипулировать программным кодом. На компилированном языке, таком как C, вся эта идея не подходит или даже имеет смысл.

Если вы хотите написать калькулятор, вам придется реализовать свой собственный парсер и вычислительную логику.

Вам придется анализировать и оценивать выражение самостоятельно. C ++ не откладывает до времени выполнения, что он может делать во время компиляции.

Вы не можете динамически компилировать или оценивать код, написанный на C (на самом деле вы можете это сделать, но это не так просто, поскольку вам требуется встроить компилятор или интерпретатор). Лучшим подходом было бы использовать язык сценариев, такой как Lua, Python, JavaScript и т. Д.

У Lua есть хороший интерпретатор, написанный на C, который маленький и быстрый (Blizzard использует его для скрипта WoW). Если вам нужна более высокая производительность, посмотрите на движок JavaScript V8 от Google Chrome, который является усовершенствованным механизмом сценариев, который содержит компиляцию JIT и многое другое. Или вы можете использовать Python, Perl, Ruby или даже PHP. Недостатком использования языка сценариев является то, что вы должны изучить второй язык, чтобы создать свою программу, но преимущества скоро появятся.

Обратите внимание, что это всего лишь несколько примеров, но есть тысячи библиотек, которые действительно выполняют эту работу, и вы должны решить, какой из них лучше всего подходит для ваших конкретных потребностей.

 #include  #include  #include  #include  /* 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 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; } в #include  #include  #include  #include  /* 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 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; } в #include  #include  #include  #include  /* 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 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 

Насколько я понимаю, вы хотели бы заменить во время выполнения своей 4-й строки str тем, что пользователь дал на стандартный ввод вашей программы. В вашем примере пользователь будет вводить что-то вроде ниже (в командной строке программы):

 (x+3); 

и ваша четвертая строка кода будет выглядеть так:

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

Это невозможно в C или C ++ или любом статически скомпилированном языке. Процедура компиляции выполняется и должна быть успешно завершена, прежде чем вы сможете перейти во время выполнения. Таким образом, если вы смогли изменить исходный код, тогда вам придется перекомпилировать, прежде чем сможете выполнить код с учетом вашей новой строки. Очевидно, что это не очень хороший подход к вашей проблеме.

Если вы уверены, что хотите / должны сделать это на C, а не на некотором интерпретированном языке, взгляните на Lex и Yacc.

Как уже сказано другими здесь, C не является интерпретированным языком, поэтому вы не можете сразу использовать C для интерпретации команд. Другими словами, вам нужно будет предоставить (разработать) интерпретатор в C.

Я думаю, что Lexx и Yacc значительно упрощают процесс написания интерпретатора, хотя это довольно продвинутая тема.

Посмотрите на стартер: http://epaperpress.com/lexandyacc/

Прежде всего, я считаю, что вы плохо понимаете проблему, которую хотите решить … Подробнее о переводчиках

Во-первых, локальный x не виден вне его блока, поэтому, даже если у вас есть магический метапрограммирующий оценщик, вы не сможете делать то, что хотите.

В дополнение к тому, что предлагают другие люди (кодирование вашего языка на конкретном домене, встраивание существующего интерпретатора …), и если вы используете Linux, вы можете рассмотреть возможность использования TinyCC, который также предоставляет «libtcc.h», содержащий функцию tcc_compile_string которая компилирует строка, содержащая код C (плохой) машинный код.

Вы также можете сгенерировать машинный код с LLVM , молнией GNU , LibJit

Вы также можете генерировать C-код, запускать его компиляцию в общий объект и динамически загружать его с помощью dlopen