好让说,我有一个字符串,如这在文本文件中:
((( var1 AND var2 AND var3) OR var4) AND ((var5 OR var6) AND var7))
解析这到C程序和增值经销商的处理方式,并设置正确后,它最终会看起来像这样:
((( 1 AND 0 AND 0) OR 1) AND ((0 OR 1) AND 1))
是否有任何有用的库在那里评估将被表示为这样一个字符串表达式? 我想我可以只调用一个Perl程序与字符串作为参数,将能够轻松地返回结果,但不知道是否有在C库,这样做,或是否有解决任何已知的算法这样的表述?
编辑:什么我其实是在寻找的东西,会吐出一个答案的表情,也许是解析一个坏词。 即1或0
在坚果壳其包含一串需要进行评估,以0或1的随机表达式(已经知道是在正确的格式)的文件(上面的计算结果为1,因为它导致在(1和1)。
我试着写了这个布尔表达式求值问题的最紧凑的C代码。 这是我最后的代码:
编辑:删除
这里是添加否定处理:
加入的测试代码:EDIT
char *eval( char *expr, int *res ){
enum { LEFT, OP1, MID, OP2, RIGHT } state = LEFT;
enum { AND, OR } op;
int mid=0, tmp=0, NEG=0;
for( ; ; expr++, state++, NEG=0 ){
for( ;; expr++ )
if( *expr == '!' ) NEG = !NEG;
else if( *expr != ' ' ) break;
if( *expr == '0' ){ tmp = NEG; }
else if( *expr == '1' ){ tmp = !NEG; }
else if( *expr == 'A' ){ op = AND; expr+=2; }
else if( *expr == '&' ){ op = AND; expr+=1; }
else if( *expr == 'O' ){ op = OR; expr+=1; }
else if( *expr == '|' ){ op = OR; expr+=1; }
else if( *expr == '(' ){ expr = eval( expr+1, &tmp ); if(NEG) tmp=!tmp; }
else if( *expr == '\0' ||
*expr == ')' ){ if(state == OP2) *res |= mid; return expr; }
if( state == LEFT ){ *res = tmp; }
else if( state == MID && op == OR ){ mid = tmp; }
else if( state == MID && op == AND ){ *res &= tmp; state = LEFT; }
else if( state == OP2 && op == OR ){ *res |= mid; state = OP1; }
else if( state == RIGHT ){ mid &= tmp; state = MID; }
}
}
测试:
#include <stdio.h>
void test( char *expr, int exprval ){
int result;
eval( expr, &result );
printf("expr: '%s' result: %i %s\n",expr,result,result==exprval?"OK":"FAILED");
}
#define TEST(x) test( #x, x )
#define AND &&
#define OR ||
int main(void){
TEST( ((( 1 AND 0 AND 0) OR 1) AND ((0 OR 1) AND 1)) );
TEST( !(0 OR (1 AND 0)) OR !1 AND 0 );
}
您可以嵌入LUA在程序中,然后调用它的解释器来计算表达式。
这是很容易推出自己的递归下降解析器像这些简单的表达式。
我有大约实现递归体面解析器,所以我刷了起来,这是类似的计划。
#include <stdio.h> #include <stdlib.h>
INT门(INT pOprd1,INT pOprd2){如果(pOprd1 == -1)返回pOprd2; 返回pOprd1 || pOprd2; } INT doAND(INT pOprd1,INT pOprd2){如果(pOprd1 == -1)返回pOprd2; 返回pOprd1 && pOprd2; } INT doProcess(炭pOpert,INT pOprd1,INT pOprd2){如果(pOpert == '0')返回pOprd2; 如果(pOpert == 'O')的返回门(pOprd1,pOprd2); 如果(pOpert == 'A')返回doAND(pOprd1,pOprd2); 看跌期权( “未知运营商!!!”); 出口(-1); } INT * doParse(炭PSTR,INT PSTART){炭℃; INT I = PSTART; int值= -1; 炭算= '0'; 为(;!(C = PSTR [I])= 0;我++){如果(C == '0'){值= doProcess(操作员,价值,0); 继续; }如果(C == '1'){值= doProcess(操作员,价值,1); 继续; }如果(C =='“)继续; 如果(C == ')'){INT aReturn; aReturn = malloc(2*sizeof aReturn); aReturn = malloc的(2 *的sizeof aReturn); aReturn[0] = Value; aReturn [0] =值; aReturn[1] = i + 1; aReturn [1] = I + 1; return aReturn; 返回aReturn; } if (C == '(') { int * aResult = doParse(pStr, i + 1); Value = doProcess(Operator, Value, aResult[0]); i = aResult[1]; if (pStr[i] == 0) break; continue; } if ((C == 'A') && ((pStr[i + 1] == 'N') && (pStr[i + 2] == 'D'))) { if ((Operator == '0') || (Operator == 'A')) { Operator = 'A'; i += 2; continue; } else { puts("Mix Operators are not allowed (AND)!!!"); exit(-1); } } if ((C == 'O') && (pStr[i + 1] == 'R')) { if ((Operator == '0') || (Operator == 'O')) { Operator = 'O'; i += 1; continue; } else { puts("Mix Operators are not allowed (OR)!!!"); exit(-1); } } printf("Unknown character: '%c (\"%s\"[%d])'!!!", C, pStr, i); exit(-1); } int* aReturn; aReturn = malloc(2*sizeof aReturn); aReturn[0] = Value; aReturn[1] = i; return aReturn; } }如果(C == '('){INT * aResult = doParse(PSTR,I + 1);值= doProcess(操作员,价值,aResult [0]); I = aResult [1];如果(PSTR [I ] == 0)断裂;继续;}如果((C == 'A')&&((PSTR第[i + 1] == 'N')&&(PSTR第[i + 2] == 'd')) ){如果((操作员== '0')||(操作员== 'A')){算= 'A'; I + = 2;继续;}其他{看跌期权(“混合算不准(AND )!!!“);出口(-1);}}如果((C == 'O')&&(PSTR第[i + 1] == 'R')){如果((操作员== '0' )||(操作员== 'O')){算= 'O'; I + = 1;继续;}其他{看跌期权( “混合算不准(OR)!!!”);出口(-1 );}} printf的( “未知字符: '%C(\ ”%s \“ 的[%d])' !!!”,C,PSTR,I);出口(-1);} * INT aReturn; aReturn = malloc的(2 *的sizeof aReturn); aReturn [0] =值; aReturn [1] = I;返回aReturn;}
这是一个测试代码:
int main(void) { char* aExpr = "1"; int* aResult = doParse(aExpr, 0); printf("%s = %d\n", aExpr, ((int*)aResult)[0]); free(aResult); aExpr = "0"; aResult = doParse(aExpr, 0); printf("%s = %d\n", aExpr, ((int*)aResult)[0]); free(aResult); aExpr = "1 AND 0"; aResult = doParse(aExpr, 0); printf("%s = %d\n", aExpr, ((int*)aResult)[0]); free(aResult); aExpr = "1 AND 1"; aResult = doParse(aExpr, 0); printf("%s = %d\n", aExpr, ((int*)aResult)[0]); free(aResult); aExpr = "0 OR 0 OR 0"; aResult = doParse(aExpr, 0); printf("%s = %d\n", aExpr, ((int*)aResult)[0]); free(aResult); aExpr = "1 OR 0 OR 0"; aResult = doParse(aExpr, 0); printf("%s = %d\n", aExpr, ((int*)aResult)[0]); free(aResult); aExpr = "1 OR 1 OR 0"; aResult = doParse(aExpr, 0); printf("%s = %d\n", aExpr, ((int*)aResult)[0]); free(aResult); aExpr = "(1 OR 0)"; aResult = doParse(aExpr, 0); printf("%s = %d\n", aExpr, ((int*)aResult)[0]); free(aResult); aExpr = "(0 OR 0)"; aResult = doParse(aExpr, 0); printf("%s = %d\n", aExpr, ((int*)aResult)[0]); free(aResult); aExpr = "((( 1 AND 0 AND 0) OR 1) AND ((0 OR 1) AND 1))"; aResult = doParse(aExpr, 0); printf("%s = %d\n", aExpr, ((int*)aResult)[0]); free(aResult); puts("DONE!!!"); return EXIT_SUCCESS; }
这是有趣:-D。
我相信Lex和Yacc仍然是这样简单的解析任务的最佳工具。
前一段,我写了一个完整的C表达式求值的命令行处理器和脚本语言的嵌入式系统上(使用C语法书面即计算的表达式)。 我用这个算法描述为出发点。 你可以直接使用附带的代码,但我不喜欢的实施,写我自己从算法描述。 它需要一些工作,以支持所有的C运算符,函数调用和变量,而是一个明确的解释,因此一个良好的起点,特别是如果你不需要完整这一水平。
其基本原理是,表达式的评估是用于使用栈和“逆波兰表示法”的计算机更容易,因此该算法一个在修复符号表达与优先级和括号的相关联的顺序转换为RPN,然后通过弹出操作数计算它,执行操作,并推动的结果,直到没有操作留下,离开了栈上的一个值。
写一个表达式解析器很容易原则,但需要的工作量会比较大。
这里有一个基本的自顶向下的递归下降表达式解析器我在Java中写道: http://david.tribble.com/src/java/tribble/parse/sql/QueryParser.java http://david.tribble.com/src /java/tribble/parse/sql/ExprLexer.java http://david.tribble.com/src/java/tribble/parse/sql/ExprLexer.java http://david.tribble.com/docs/tribble/parse /sql/package-summary.html
这可能不是你在寻找什么,但它会给你你需要什么的想法。