[英]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.