[英]Converting a string to a line of code in 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)。 我要用它來構建函數繪圖儀。。但是在這里我被卡住了,找不到任何方法。 您能告訴我一種將這些字符串轉換為代碼行的方法嗎?
那不可能 C不是一種反射性語言,沒有任何eval()
。
您當然可以調用外部編譯器並運行生成的程序,或者可以嘗試找到在程序中包含C編譯器的編譯器庫,但是沒有“本機”解決方案。
AC程序一次被靜態編譯,並且編譯后的二進制文件不知道它是用C編寫的事實。編譯過程完全與程序運行時無關。 通常,僅解釋型語言提供eval()
,因為解釋器在程序執行期間處於活動狀態並且可以動態地操縱程序代碼。 在像C這樣的編譯語言中,整個想法不適合甚至不可行。
如果要編寫計算器,則必須實現自己的解析器和計算邏輯。
您必須自己分析和評估表達式。 C ++不會將其在編譯時可以完成的工作推遲到運行時。
您不能動態地編譯或評估用C語言編寫的代碼(實際上可以,但是它並不是那么簡單,因為它要求您嵌入編譯器或解釋器)。 最好的方法是使用腳本語言,例如Lua,Python,JavaScript等。
Lua有一個很好的解釋器,它用C編寫,既小又快速(Blizzard使用它來編寫WoW腳本)。 如果您需要更高的性能,請查看V8,這是來自Google Chrome的JavaScript引擎,它是具有JIT編譯功能以及更多功能的高級腳本引擎。 或者,您可以使用Python,Perl,Ruby甚至PHP。 使用腳本語言的缺點是,您必須學習第二種語言才能構建程序,但是好處很快就會顯現出來。
請注意,這些只是幾個示例,但是有成千上萬個庫確實可以很好地完成此工作,並且您必須確定哪種庫最適合您的特定需求。
#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行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 ,它還會提供一個包含包含tcc_compile_string
函數的“ libtcc.h”並進行編譯包含C代碼到(較差)機器代碼的字符串。
您還可以使用LLVM , GNU lightning , LibJit生成機器代碼
您還可以生成C代碼,將其編譯運行到共享庫中,然后使用dlopen動態加載它
您要做的是表達評估 。 我建議兩種方法可能會幫助您更接近預期的解決方案。
用二叉樹評估表達式:構建一個樹,該樹表示表達式和運算符之間的優先級。
可能是上面提到的。 波蘭語形式的基於堆棧的評估。 首先使用堆棧構建原始表達式的修飾形式,然后再次使用堆棧評估修飾形式。 最后:將google與這些關鍵技巧結合使用:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.