好吧,我想在文本文件中有一个这样的字符串:
((( 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) )。
答案 0 :(得分:7)
您可以在程序中嵌入lua,然后调用它的解释器来评估表达式。
答案 1 :(得分:7)
我试图为这个bool表达式评估问题编写最紧凑的C代码。这是我的最终代码:
编辑:已删除
这是增加的否定处理:
编辑:添加测试代码
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 );
}
答案 2 :(得分:4)
对于像这样的简单表达式来说,滚动自己的recursive descent parser很容易。
答案 3 :(得分:4)
我有类似的程序实现递归下降解析器,所以我刷它,就在这里。
#include <stdio.h>
#include <stdlib.h>
int doOR(int pOprd1, int pOprd2) {
if (pOprd1 == -1) return pOprd2;
return pOprd1 || pOprd2;
}
int doAND(int pOprd1, int pOprd2) {
if (pOprd1 == -1) return pOprd2;
return pOprd1 && pOprd2;
}
int doProcess(char pOpert, int pOprd1, int pOprd2) {
if (pOpert == '0') return pOprd2;
if (pOpert == 'O') return doOR (pOprd1, pOprd2);
if (pOpert == 'A') return doAND(pOprd1, pOprd2);
puts("Unknown Operator!!!");
exit(-1);
}
int* doParse(char pStr, int pStart) {
char C;
int i = pStart;
int Value = -1;
char Operator = '0';
for(; (C = pStr[i]) != 0; i++) {
if (C == '0') { Value = doProcess(Operator, Value, 0); continue; }
if (C == '1') { Value = doProcess(Operator, Value, 1); continue; }
if (C == ' ') continue;
if (C == ')') {
int aReturn;
aReturn = malloc(2*sizeof aReturn);
aReturn[0] = Value;
aReturn[1] = i + 1;
return 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;
}
这是一个测试代码:
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。
答案 4 :(得分:4)
@noɥʇʎԀʎzɐɹƆ 正在寻找一个规范的解析器和评估器,它可以构建在 x86 上,并为任何布尔表达式生成 x86 asm JIT 评估器。
这是一个 ANSI C99 基本解析器和评估器,它使用 parse_tree
构建表达式树并使用 eval_expr
评估解析树。这避免了大多数常用的指针运算,应该很容易翻译成多种语言。
错误管理设置为基本最小值(缺少或意外的表达式,错误的表达式如 NOT 1 NOT 0)。它不应该在解析时出现错误表达式的情况下泄漏内存,但并未真正以这种方式进行过测试。
eval_leaf
可以用一种 libc strtol()
替换,但这里似乎最好做一个由偏移量分隔的基本 int 解析以避免字符串分配,因为我们通常处理简单的 int .
compile_expr
方法为表达式生成 x86 asm 评估器,exec_expr_JIT
方法执行生成的 x86 asm 评估器。 exec_expr_JIT
实际上使用 mmap 和 MapViewOfFile,它们仅适用于 Linux/BSD/MacOS 和 Windows。更通用的方法是学习。
EDIT:添加按位非运算符 (BNOT) 作为表达式中的 ~
。
要测试它,只需使用 ANSI C99 编译器构建它并使用预期的表达式启动它以解析和评估作为第一个参数:
$ cc -o parser parser.c
$ ./parser '(NOT0AND(1OR(1 AND 0))AND(1OR(0OR0)))AND1ANDNOT!~0'
<<<<[NOT]0>[AND]<1[OR]<1 [AND] 0>>>[AND]<1[OR]<0[OR]0>>>[AND]1>[AND]<[NOT]<[NOT]<[BNOT]0>>>
=> 1
Compiled: 88 [B8 00 00 00 00 F7 D0 25 01 00 00 00 50 B8 01 00 00 00 50 B8 01 00 00 00 25 00 00 00 00 59 09 C1 59 21 C1 50 B8 01 00 00 00 50 B8 00 00 00 00 0D 00 00 00 00 59 09 C1 59 21 C1 25 01 00 00 00 50 B8 00 00 00 00 F7 D0 F7 D0 25 01 00 00 00 F7 D0 25 01 00 00 00 59 21 C1]
Res JIT : 1
首先用<leaf>
和[operand]
以扁平树的形式显示解析后的表达式,然后用 => <result>
显示其计算结果。接下来,它将显示解析表达式的评估器构建的 x86 asm 代码及其大小(以字节为单位),然后是该评估器的执行结果。
解析器和评估器源:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <stdint.h>
#ifdef _MSC_VER
#include <windows.h>
#include <memoryapi.h>
#else
#include <sys/mman.h>
#endif
enum e_operand { NONE, AND, OR, NOT, BNOT };
struct s_expr {
struct s_expr_leaf {
char* value;
int offset;
struct s_expr* expr;
} *left;
enum e_operand operand;
struct s_expr_leaf* right;
};
struct s_expr* build_expr() {
struct s_expr* lExpr = (struct s_expr*)malloc(sizeof(struct s_expr));
if (lExpr == NULL) return(NULL);
lExpr->left = NULL;
lExpr->operand = NONE;
lExpr->right = NULL;
return(lExpr);
}
struct s_expr_leaf* build_leaf(struct s_expr* pExpr) {
struct s_expr_leaf* lLeaf = (struct s_expr_leaf*)malloc(sizeof(struct s_expr_leaf));
if (lLeaf == NULL) return(NULL);
lLeaf->value = NULL;
lLeaf->offset = 0;
lLeaf->expr = pExpr;
return(lLeaf);
}
struct s_expr* left_expr(struct s_expr** pExpr) {
struct s_expr* lExprParent = build_expr();
if (lExprParent == NULL) {
perror("Can't allocate enough memory...");
return(NULL);
}
lExprParent->left = build_leaf(*pExpr);
if (lExprParent->left == NULL) {
perror("Can't allocate enough memory...");
free(lExprParent);
return(NULL);
}
*(pExpr) = lExprParent;
return lExprParent;
}
int free_expr(struct s_expr*);
struct s_expr* parse_tree(char** pExpr) {
if (pExpr == NULL || *pExpr == NULL) return(NULL);
struct s_expr* lExpr = build_expr();
if (lExpr == NULL) {
perror("Can't allocate enough memory...");
return(NULL);
}
struct s_expr_leaf** lSide = &lExpr->left;
while (**pExpr != 0) {
switch (**pExpr & 0xDF) {
case 8: // (
(*pExpr)++;
if (*lSide == NULL) {
*lSide = build_leaf(NULL);
}
if (*lSide != NULL) (*lSide)->expr = parse_tree(pExpr);
if (*lSide == NULL || (*lSide)->expr == NULL) {
perror("Can't allocate enough memory...");
free_expr(lExpr);
return(NULL);
}
break;
case 9: // )
return(lExpr);
case 'N': // NOT?
case 1:
if (**pExpr == '!' || (((*pExpr)[1] & 0xDF) == 'O' && ((*pExpr)[2] & 0xDF) == 'T')) {
if (lExpr->operand != NONE) {
if (lExpr->right != NULL) {
printf("Wrong expression\n");
free_expr(lExpr);
return(NULL);
}
lExpr->right = build_leaf(parse_tree(pExpr));
if (lExpr->right == NULL || lExpr->right->expr == NULL) {
perror("Can't allocate enough memory...");
free_expr(lExpr);
return(NULL);
}
return(lExpr);
}
lExpr->operand = NOT;
if (**pExpr != '!') (*pExpr) += 2;
lSide = &lExpr->right;
}
break;
case '^': // Bitwise NOT ?
if (**pExpr == '~') {
if (lExpr->operand != NONE) {
if (lExpr->right != NULL) {
printf("Wrong expression\n");
free_expr(lExpr);
return(NULL);
}
lExpr->right = build_leaf(parse_tree(pExpr));
if (lExpr->right == NULL || lExpr->right->expr == NULL) {
perror("Can't allocate enough memory...");
free_expr(lExpr);
return(NULL);
}
return(lExpr);
}
lExpr->operand = BNOT;
lSide = &lExpr->right;
}
break;
case 'A': // AND?
if (((*pExpr)[1] & 0xDF) == 'N' && ((*pExpr)[2] & 0xDF) == 'D') {
if (lExpr->operand != NONE) {
if (left_expr(&lExpr) == NULL) {
free_expr(lExpr);
return(NULL);
}
}
lExpr->operand = AND;
(*pExpr) += 2;
lSide = &lExpr->right;
}
break;
case 'O': // OR?
if (((*pExpr)[1] & 0xDF) == 'R') {
if (lExpr->operand != NONE) {
if (left_expr(&lExpr) == NULL) {
free_expr(lExpr);
return(NULL);
}
}
lExpr->operand = OR;
(*pExpr)++;
lSide = &lExpr->right;
}
break;
default:
if (*lSide == NULL) {
*lSide = build_leaf(NULL);
if (*lSide == NULL) {
perror("Can't allocate enough memory...");
free_expr(lExpr);
return(NULL);
}
(*lSide)->value = *pExpr;
}
if ((*lSide)->value == NULL) (*lSide)->value = *pExpr;
(*lSide)->offset++;
};
(*pExpr)++;
};
return(lExpr);
}
int free_expr(struct s_expr* pExpr) {
int lFlag = 0;
if (pExpr == NULL) return(0);
if (pExpr->left != NULL) {
lFlag = free_expr(pExpr->left->expr);
free(pExpr->left);
}
if (pExpr->right != NULL) {
lFlag = free_expr(pExpr->right->expr);
free(pExpr->right);
}
free(pExpr);
return(lFlag);
}
int display_expr(struct s_expr* pExpr) {
if (pExpr == NULL) return 0;
if (pExpr->left != NULL) {
if (pExpr->left->expr != NULL) {
printf("<");
display_expr(pExpr->left->expr);
printf(">");
} else {
if (pExpr->left->value != NULL) printf("%.*s", pExpr->left->offset, pExpr->left->value);
}
}
switch (pExpr->operand) {
case NONE:
break;
case AND:
printf("[AND]");
break;
case OR:
printf("[OR]");
break;
case NOT:
printf("[NOT]");
break;
case BNOT:
printf("[BNOT]");
break;
};
if (pExpr->right != NULL) {
if (pExpr->right->expr != NULL) {
printf("<");
display_expr(pExpr->right->expr);
printf(">");
} else {
if (pExpr->right->value != NULL) printf("%.*s", pExpr->right->offset, pExpr->right->value);
}
}
return(0);
}
int eval_leaf(struct s_expr_leaf* pValue, int* pRes) {
char* lValue;
int lLimit = 0;
int lStart = -1;
int lSign = 1;
if (pRes == NULL) return(1);
if (pValue == NULL) return(1);
lValue = pValue->value;
lLimit = pValue->offset;
if (lValue == NULL) return(1);
*pRes = 0;
while (lLimit > 0 && *lValue == ' ') { lValue++; lLimit--; }
if (lLimit > 0 && (*lValue == '-' || *lValue == '+')) {
if (*lValue == '-') lSign = -1;
lLimit--;
lValue++;
}
while (lLimit > 0 && *lValue != 0) {
if (*lValue >= 0x30 && *lValue <= 0x39) {
if (lStart == -1) lStart = lLimit;
} else {
break;
}
lLimit--;
lValue++;
}
if (lStart > 0) {
lStart -= lLimit;
lValue--;
lLimit = 1;
while (lStart > 0) {
*pRes += ((*lValue & 0xF) * lLimit);
lLimit *= 10;
lStart--;
lValue--;
};
} else {
printf("Expr or value missing ...\n");
return(2);
}
*pRes *= lSign;
return(0);
}
int eval_expr(struct s_expr* pExpr, int* pRes) {
int lResLeft = 0;
int lResRight = 0;
enum e_operand lOperand = NONE;
if (pRes == NULL) return(1);
*pRes = 0;
if (pExpr == NULL) return(1);
if (pExpr->left != NULL) {
if (pExpr->left->expr != NULL) {
if (pExpr->left->value != NULL) {
printf("Unexpected left value... %.*s\n", pExpr->left->offset, pExpr->left->value);
return(2);
}
switch (eval_expr(pExpr->left->expr, &lResLeft)) {
case 2:
display_expr(pExpr); printf("\n");
return(1);
case 1:
return(1);
};
} else {
if (pExpr->left->value != NULL) {
switch (eval_leaf(pExpr->left, &lResLeft)) {
case 2:
display_expr(pExpr); printf("\n");
return(1);
case 1:
return(1);
};
}
}
}
if (pExpr->right != NULL) {
if (pExpr->right->expr != NULL) {
if (pExpr->right->value != NULL) {
printf("Unexpected right value... %.*s\n", pExpr->right->offset, pExpr->right->value);
return(2);
}
switch (eval_expr(pExpr->right->expr, &lResRight)) {
case 2:
display_expr(pExpr); printf("\n");
return(1);
case 1:
return(1);
};
} else {
if (pExpr->right->value != NULL) {
switch (eval_leaf(pExpr->right, &lResRight)) {
case 2:
display_expr(pExpr); printf("\n");
return(1);
case 1:
return(1);
};
}
}
}
switch (pExpr->operand) {
case NONE:
if (pExpr->left == NULL) {
printf("Expr or value missing ...\n");
return(2);
}
*pRes = lResLeft;
break;
case AND:
if (pExpr->left == NULL || pExpr->right == NULL) {
printf("Expr or value missing ...\n");
return(2);
}
*pRes = (lResLeft & lResRight);
break;
case OR:
if (pExpr->left == NULL || pExpr->right == NULL) {
printf("Expr or value missing ...\n");
return(2);
}
*pRes = (lResLeft | lResRight);
break;
case NOT:
if (pExpr->right == NULL) {
printf("Expr or value missing ...\n");
return(2);
}
*pRes = !lResRight;
break;
case BNOT:
if (pExpr->right == NULL) {
printf("Expr or value missing ...\n");
return(2);
}
*pRes = ~lResRight;
break;
};
return(0);
}
// Expr compilation
struct s_expr_JIT {
unsigned char* JIT;
int size;
int nbargs;
};
struct s_expr_JIT* build_expr_JIT() {
struct s_expr_JIT* lExprJIT = (struct s_expr_JIT*)malloc(sizeof(struct s_expr_JIT));
if (lExprJIT == NULL) {
perror("Can't allocate enough memory...");
return(NULL);
}
lExprJIT->JIT = NULL;
lExprJIT->size = 0;
lExprJIT->nbargs = 0;
return(lExprJIT);
}
int free_expr_JIT(struct s_expr_JIT* pExpr) {
if (pExpr == NULL) return(1);
if (pExpr->JIT != NULL) free(pExpr->JIT);
free(pExpr);
return(0);
}
int set_expr_JIT(struct s_expr_JIT* pExpr, unsigned char* pOpCodes, int pNbOpCodes, int* pValue, unsigned char* pOpCodesNext, int pNbOpCodesNext) {
unsigned char* lOffset;
int lSizeref;
if (pExpr == NULL) return(1);
if (pExpr->JIT != NULL) {
lSizeref = pExpr->size;
pExpr->size += pNbOpCodes;
pExpr->size += pNbOpCodesNext;
if (pValue != NULL) pExpr->size += sizeof(int32_t);
lOffset = (unsigned char*)realloc(pExpr->JIT, pExpr->size);
if (lOffset == NULL) {
perror("Can't allocate enough memory...");
return(1);
}
pExpr->JIT = lOffset;
lOffset = &pExpr->JIT[lSizeref];
} else {
pExpr->size = pNbOpCodes;
pExpr->size += pNbOpCodesNext;
if (pValue != NULL) pExpr->size += sizeof(int32_t);
pExpr->JIT = (unsigned char*)malloc(pExpr->size);
if (pExpr->JIT == NULL) {
perror("Can't allocate enough memory...");
return(1);
}
lOffset = pExpr->JIT;
}
if (pOpCodes != NULL) {
if (memcpy(lOffset, pOpCodes, pNbOpCodes) == NULL) return(1);
lOffset += pNbOpCodes;
}
if (pValue != NULL) {
*((int32_t*)lOffset) = (int32_t)*pValue; // Keep endianness
lOffset += sizeof(int32_t);
}
if (pOpCodesNext != NULL) {
if (memcpy(lOffset, pOpCodesNext, pNbOpCodesNext) == NULL) return(1);
lOffset += pNbOpCodesNext;
}
return(0);
}
int merge_expr_JIT(struct s_expr_JIT* pExpr, unsigned char* pOpCodes, int pNbOpCodes, struct s_expr_JIT* pSrc, unsigned char* pOpCodesMerge, int pNbOpCodesMerge) {
unsigned char* lOffset;
int lSizeref;
if (pExpr == NULL) return(1);
if (pExpr->JIT != NULL) {
lSizeref = pExpr->size;
pExpr->size += pNbOpCodes;
pExpr->size += pNbOpCodesMerge;
if (pSrc != NULL) pExpr->size += pSrc->size;
lOffset = (unsigned char*)realloc(pExpr->JIT, pExpr->size);
if (lOffset == NULL) {
perror("Can't allocate enough memory...");
return(1);
}
pExpr->JIT = lOffset;
lOffset = &pExpr->JIT[lSizeref];
} else {
pExpr->size = pNbOpCodes;
pExpr->size += pNbOpCodesMerge;
if (pSrc != NULL) pExpr->size += pSrc->size;
pExpr->JIT = (unsigned char*)malloc(pExpr->size);
if (pExpr->JIT == NULL) {
perror("Can't allocate enough memory...");
return(1);
}
lOffset = pExpr->JIT;
}
if (pOpCodes != NULL) {
if (memcpy(lOffset, pOpCodes, pNbOpCodes) == NULL) return(1);
lOffset += pNbOpCodes;
}
if (pSrc != NULL) {
if (memcpy(lOffset, pSrc->JIT, pSrc->size) == NULL) return(1);
lOffset += pSrc->size;
}
if (pOpCodesMerge != NULL) {
if (memcpy(lOffset, pOpCodesMerge, pNbOpCodesMerge) == NULL) return(1);
lOffset += pNbOpCodesMerge;
}
return(0);
}
int compile_expr(struct s_expr* pExpr, struct s_expr_JIT** pRes) {
int lResLeftValue = 0;
int lResRightValue = 0;
if (pExpr == NULL) return(1);
if (pRes == NULL) return(1);
struct s_expr_JIT* lResLeft = NULL;
struct s_expr_JIT* lResRight = NULL;
enum e_operand lOperand = NONE;
*pRes = build_expr_JIT();
if (*pRes == NULL) {
return(1);
}
if (pExpr->left != NULL) {
if (pExpr->left->expr != NULL) {
if (pExpr->left->value != NULL) {
printf("Unexpected left value... %.*s\n", pExpr->left->offset, pExpr->left->value);
free_expr_JIT(*pRes);
return(2);
}
switch (compile_expr(pExpr->left->expr, &lResLeft)) {
case 2:
display_expr(pExpr); printf("\n");
free_expr_JIT(*pRes);
return(1);
case 1:
free_expr_JIT(*pRes);
return(1);
};
} else {
if (pExpr->left->value != NULL) {
switch (eval_leaf(pExpr->left, &lResLeftValue)) {
case 2:
display_expr(pExpr); printf("\n");
free_expr_JIT(*pRes);
return(1);
case 1:
free_expr_JIT(*pRes);
return(1);
};
}
}
}
if (pExpr->right != NULL) {
if (pExpr->right->expr != NULL) {
if (pExpr->right->value != NULL) {
printf("Unexpected right value... %.*s\n", pExpr->right->offset, pExpr->right->value);
free_expr_JIT(lResLeft); free_expr_JIT(*pRes);
return(2);
}
switch (compile_expr(pExpr->right->expr, &lResRight)) {
case 2:
display_expr(pExpr); printf("\n");
free_expr_JIT(lResLeft); free_expr_JIT(*pRes);
return(1);
case 1:
free_expr_JIT(lResLeft); free_expr_JIT(*pRes);
return(1);
};
} else {
if (pExpr->right->value != NULL) {
switch (eval_leaf(pExpr->right, &lResRightValue)) {
case 2:
display_expr(pExpr); printf("\n");
free_expr_JIT(lResLeft); free_expr_JIT(*pRes);
return(1);
case 1:
free_expr_JIT(lResLeft); free_expr_JIT(*pRes);
return(1);
};
}
}
}
switch (pExpr->operand) {
case NONE:
if (pExpr->left == NULL) {
printf("Expr or value missing ...\n");
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(2);
}
if (lResLeft != NULL) {
if (merge_expr_JIT(*pRes, NULL, 0, lResLeft, NULL, 0) != 0) {
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(1);
}
} else {
if (set_expr_JIT(*pRes, (unsigned char[]) { 0xB8 }, 1, & lResLeftValue, NULL, 0) != 0) { // MOVL <int32 value>, %EAX
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(1);
}
}
break;
case AND:
if (pExpr->left == NULL || pExpr->right == NULL) {
printf("Expr or value missing ...\n");
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(2);
}
if (lResLeft != NULL) {
if (merge_expr_JIT(*pRes, NULL, 0, lResLeft, NULL, 0) != 0) {
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(1);
}
} else {
if (set_expr_JIT(*pRes, (unsigned char[]) { 0xB8 }, 1, & lResLeftValue, NULL, 0) != 0) { // MOVL <int32 value>, %EAX
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(1);
}
}
if (lResRight != NULL) { // 0x91 XCHG %EAX,%ECX
if (merge_expr_JIT(*pRes, (unsigned char[]) { 0x50 }, 1, lResRight, (unsigned char[]) { 0x59, 0x21, 0xC1 }, 3) != 0) { // PUSH %EAX POP %ECX AND %EAX,%ECX
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(1);
}
} else {
if (set_expr_JIT(*pRes, (unsigned char[]) { 0x25 }, 1, & lResRightValue, NULL, 0) != 0) { // AND %EAX, <int32 value>
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(1);
}
}
break;
case OR:
if (pExpr->left == NULL || pExpr->right == NULL) {
printf("Expr or value missing ...\n");
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(2);
}
if (lResLeft != NULL) {
if (merge_expr_JIT(*pRes, NULL, 0, lResLeft, NULL, 0) != 0) {
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(1);
}
} else {
if (set_expr_JIT(*pRes, (unsigned char[]) { 0xB8 }, 1, & lResLeftValue, NULL, 0) != 0) { // MOVL <int32 value>, %EAX
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(1);
}
}
if (lResRight != NULL) { // 0x91 XCHG %EAX,%ECX
if (merge_expr_JIT(*pRes, (unsigned char[]) { 0x50 }, 1, lResRight, (unsigned char[]) { 0x59, 0x09, 0xC1 }, 3) != 0) { // PUSH %EAX POP %ECX OR %EAX,%ECX
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(1);
}
} else {
if (set_expr_JIT(*pRes, (unsigned char[]) { 0x0D }, 1, & lResRightValue, NULL, 0) != 0) { // OR %EAX, <int32 value>
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(1);
}
}
break;
case NOT:
if (pExpr->right == NULL) {
printf("Expr or value missing ...\n");
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(2);
}
if (lResRight != NULL) {
if (merge_expr_JIT(*pRes, NULL, 0, lResRight, (unsigned char[]) { 0xF7, 0xD0, 0x25, 0x01, 0x00, 0x00, 0x00 }, 7) != 0) { // NOT %EAX AND %EAX,1
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(1);
}
} else {
if (set_expr_JIT(*pRes, (unsigned char[]) { 0xB8 }, 1, & lResRightValue, (unsigned char[]) { 0xF7, 0xD0, 0x25, 0x01, 0x00, 0x00, 0x00 }, 7) != 0) { // MOV %EAX, <int32 value> NOT %EAX
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(1);
}
}
break;
case BNOT:
if (pExpr->right == NULL) {
printf("Expr or value missing ...\n");
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(2);
}
if (lResRight != NULL) {
if (merge_expr_JIT(*pRes, NULL, 0, lResRight, (unsigned char[]) { 0xF7, 0xD0 }, 2) != 0) { // NOT %EAX
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(1);
}
} else {
if (set_expr_JIT(*pRes, (unsigned char[]) { 0xB8 }, 1, & lResRightValue, (unsigned char[]) { 0xF7, 0xD0 }, 2) != 0) { // MOV %EAX, <int32 value> NOT %EAX
free_expr_JIT(lResLeft); free_expr_JIT(lResRight); free_expr_JIT(*pRes);
return(1);
}
}
break;
};
if (lResLeft != NULL) free_expr_JIT(lResLeft);
if (lResRight != NULL) free_expr_JIT(lResRight);
return(0);
}
int dump_expr_JIT(struct s_expr_JIT* pExpr) {
unsigned char* lOffset;
int lSize;
if (pExpr != NULL) {
lOffset = pExpr->JIT;
lSize = pExpr->size;
while (lSize > 0) {
printf("%02X", lOffset[0]);
lOffset++;
lSize--;
if (lSize > 0) printf(" ");
}
}
return(0);
}
int exec_expr_JIT(struct s_expr_JIT* pExpr, int* pRes) {
unsigned char* lOffset;
int (*lJit)();
if (pRes == NULL) return(1);
if (pExpr != NULL) {
#ifdef _MSC_VER
HANDLE lHandle = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE | SEC_COMMIT, 0, pExpr->size + 10, NULL);
if (lHandle == NULL) {
perror("Mapping failed...");
return 1;
}
lOffset = (unsigned char*)MapViewOfFile(lHandle, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, pExpr->size + 10);
if (lOffset == NULL) {
perror("Mapping failed...");
return 1;
}
#else
lOffset = (unsigned char*)mmap(NULL, pExpr->size + 10, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
if (lOffset == MAP_FAILED) {
perror("Mapping failed...");
return 1;
}
#endif
lOffset[0] = 0x55; // PUSH %EBP
lOffset[1] = 0x48; // MOV %ESP, %EBP
lOffset[2] = 0x89;
lOffset[3] = 0xE5;
lOffset[4] = 0x9C; // PUSHFD
lOffset[5] = 0x51; // PUSH %ECX
if (memcpy(&lOffset[6], pExpr->JIT, pExpr->size) == NULL) {
#ifdef _MSC_VER
if (!UnmapViewOfFile(lOffset)) {
perror("Unmapping failed...");
return 1;
}
CloseHandle(lHandle);
#else
if (munmap(lOffset, pExpr->size + 10) != 0) {
perror("Unmapping failed...");
return 1;
}
#endif
return(1);
}
lOffset[pExpr->size + 6] = 0x59; // POP %ECX
lOffset[pExpr->size + 7] = 0x9D; // POPF
lOffset[pExpr->size + 8] = 0xC9; // LEAVE
lOffset[pExpr->size + 9] = 0xC3; // RETF
lJit = (int (*)())lOffset;
*pRes = lJit();
#ifdef _MSC_VER
if (!UnmapViewOfFile(lOffset)) {
perror("Unmapping failed...");
return 1;
}
CloseHandle(lHandle);
#else
if (munmap(lOffset, pExpr->size + 10) != 0) {
perror("Unmapping failed...");
return 1;
}
#endif
}
return(0);
}
int parse(char* pExpr, int* pRes) {
// Decomposing pExpr in tree form
struct s_expr* lRoot = parse_tree(&pExpr);
int lRes = 0;
if (lRoot == NULL) return(1);
display_expr(lRoot);
printf("\n");
if (eval_expr(lRoot, &lRes) == 0) {
printf(" => %d\n", lRes);
} else {
printf(" Error in expr...\n");
}
struct s_expr_JIT* lCompile;
if (compile_expr(lRoot, &lCompile) == 0) {
printf("Compiled: %d [", lCompile->size);
dump_expr_JIT(lCompile);
printf("]\n");
if (exec_expr_JIT(lCompile, &lRes) == 0) {
printf("Res JIT : %d\n", lRes);
} else {
printf("Failed to exec JIT..\n");
}
free_expr_JIT(lCompile);
}
free_expr(lRoot);
return(0);
}
int main(int nbargs, char* args[]) {
int lRes = 0;
if (nbargs > 0) parse(args[1], &lRes);
return(0);
}
答案 5 :(得分:2)
作为 this answer 的附件,这里是解析器的 C++ 版本,它使用 JIT asm 库 (asmjit) 来增强可移植性。归功于@Kamiccolo 的 JIT 库想法。此代码需要 C11 C++ 编译器和 asmjit 库。
使用 GCC/G++-8 和 VS2019 测试(构建编译并运行)(代码和 asmjit 库的 x86 构建)。
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <iostream>
#include <asmjit/x86.h>
using namespace std;
//
// namespace for the expression parser
//
namespace parser {
enum e_operand { NONE, AND, OR, NOT, BNOT };
//
// expression class
//
class expression {
public:
//
// leaf class
//
class expression_leaf {
public:
char* value;
int offset;
expression* expr;
expression_leaf(expression* pExpr) {
this->value = NULL;
this->offset = 0;
this->expr = pExpr;
}
int eval_leaf(int* pRes) {
char* lValue;
int lLimit = 0;
int lStart = -1;
int lSign = 1;
if (pRes == NULL) return(1);
lValue = this->value;
lLimit = this->offset;
if (lValue == NULL) return(1);
*pRes = 0;
while (lLimit > 0 && *lValue == ' ') { lValue++; lLimit--; }
if (lLimit > 0 && (*lValue == '-' || *lValue == '+')) {
if (*lValue == '-') lSign = -1;
lLimit--;
lValue++;
}
while (lLimit > 0 && *lValue != 0) {
if (*lValue >= 0x30 && *lValue <= 0x39) {
if (lStart == -1) lStart = lLimit;
} else {
break;
}
lLimit--;
lValue++;
}
if (lStart > 0) {
lStart -= lLimit;
lValue--;
lLimit = 1;
while (lStart > 0) {
*pRes += ((*lValue & 0xF) * lLimit);
lLimit *= 10;
lStart--;
lValue--;
};
} else {
cerr << "eval_leaf: Expr or value missing ...\n";
return(2);
}
*pRes *= lSign;
return(0);
}
};
private:
expression_leaf* left;
enum e_operand operand;
expression_leaf* right;
public:
//
// Main constructor
//
expression() {
this->left = (expression_leaf*)NULL;
this->operand = NONE;
this->right = (expression_leaf*)NULL;
}
//
// expression fabrics
//
static expression* build_expression(char* pExpr) {
// Decomposing pExpr in tree form
return(expression::parse_tree(&pExpr));
}
static expression* left_expr(expression** pExpr) {
expression* lExprParent = new expression();
if (lExprParent == NULL) {
perror("Can't allocate enough memory...");
return(NULL);
}
lExprParent->left = new expression_leaf(*pExpr);
if (lExprParent->left == NULL) {
perror("Can't allocate enough memory...");
return(NULL);
}
*(pExpr) = lExprParent;
return lExprParent;
}
static expression* parse_tree(char** pExpr) {
if (pExpr == NULL || *pExpr == NULL) return(NULL);
expression* lExpr = new expression();
if (lExpr == NULL) {
perror("Can't allocate enough memory...");
return(NULL);
}
expression_leaf** lSide = &lExpr->left;
while (**pExpr != 0) {
switch (**pExpr & 0xDF) {
case 8: // (
(*pExpr)++;
if (*lSide == NULL) {
*lSide = new expression_leaf(NULL);
}
if (*lSide != NULL) (*lSide)->expr = parse_tree(pExpr);
if (*lSide == NULL || (*lSide)->expr == NULL) {
perror("Can't allocate enough memory...");
return(NULL);
}
break;
case 9: // )
return(lExpr);
case 'N': // NOT?
case 1:
if (**pExpr == '!' || (((*pExpr)[1] & 0xDF) == 'O' && ((*pExpr)[2] & 0xDF) == 'T')) {
if (lExpr->operand != NONE) {
if (lExpr->right != NULL) {
cerr << "parse_tree: Wrong expression\n";
return(NULL);
}
lExpr->right = new expression_leaf(lExpr->parse_tree(pExpr));
if (lExpr->right == NULL || lExpr->right->expr == NULL) {
perror("Can't allocate enough memory...");
return(NULL);
}
return(lExpr);
}
lExpr->operand = NOT;
if (**pExpr != '!') (*pExpr) += 2;
lSide = &lExpr->right;
}
break;
case '^': // Bitwise NOT ?
if ((*pExpr)[0] == '~') {
if (lExpr->operand != NONE) {
if (lExpr->right != NULL) {
cerr << "parse_tree: Wrong expression\n";
return(NULL);
}
lExpr->right = new expression_leaf(lExpr->parse_tree(pExpr));
if (lExpr->right == NULL || lExpr->right->expr == NULL) {
perror("Can't allocate enough memory...");
return(NULL);
}
return(lExpr);
}
lExpr->operand = BNOT;
lSide = &lExpr->right;
}
break;
case 'A': // AND?
if (((*pExpr)[1] & 0xDF) == 'N' && ((*pExpr)[2] & 0xDF) == 'D') {
if (lExpr->operand != NONE) {
if (lExpr->left_expr(&lExpr) == NULL) {
return(NULL);
}
}
lExpr->operand = AND;
(*pExpr) += 2;
lSide = &lExpr->right;
}
break;
case 'O': // OR?
if (((*pExpr)[1] & 0xDF) == 'R') {
if (lExpr->operand != NONE) {
if (lExpr->left_expr(&lExpr) == NULL) {
return(NULL);
}
}
lExpr->operand = OR;
(*pExpr)++;
lSide = &lExpr->right;
}
break;
default:
if (*lSide == NULL) {
*lSide = new expression_leaf(NULL);
if (*lSide == NULL) {
perror("Can't allocate enough memory...");
return(NULL);
}
(*lSide)->value = *pExpr;
}
if ((*lSide)->value == NULL) (*lSide)->value = *pExpr;
(*lSide)->offset++;
};
(*pExpr)++;
};
return(lExpr);
}
//
// expression methods
//
int display_expr() {
if (this->left != NULL) {
if (this->left->expr != NULL) {
cout << "<";
this->left->expr->display_expr();
cout << ">";
} else {
if (this->left->value != NULL) printf("%.*s", this->left->offset, this->left->value);
}
}
switch (this->operand) {
case NONE:
break;
case AND:
cout << "[AND]";
break;
case OR:
cout << "[OR]";
break;
case NOT:
cout << "[NOT]";
break;
case BNOT:
cout << "[BNOT]";
break;
};
if (this->right != NULL) {
if (this->right->expr != NULL) {
cout << "<";
this->right->expr->display_expr();
cout << ">";
} else {
if (this->right->value != NULL) printf("%.*s", this->right->offset, this->right->value);
}
}
return(0);
}
int eval_expr(int* pRes) {
int lResLeft = 0;
int lResRight = 0;
enum e_operand lOperand = NONE;
if (pRes == NULL) return(1);
*pRes = 0;
if (this->left != NULL) {
if (this->left->expr != NULL) {
if (this->left->value != NULL) {
fprintf(stderr, "eval_expr: Unexpected left value... %.*s\n", this->left->offset, this->left->value);
return(2);
}
switch (this->left->expr->eval_expr(&lResLeft)) {
case 2:
this->display_expr(); cout << "\n";
return(1);
case 1:
return(1);
};
} else {
if (this->left->value != NULL) {
switch (this->left->eval_leaf(&lResLeft)) {
case 2:
this->display_expr(); cout << "\n";
return(1);
case 1:
return(1);
};
}
}
}
if (this->right != NULL) {
if (this->right->expr != NULL) {
if (this->right->value != NULL) {
fprintf(stderr, "eval_expr: Unexpected right value... %.*s\n", this->right->offset, this->right->value);
return(2);
}
switch (this->right->expr->eval_expr(&lResRight)) {
case 2:
this->display_expr(); cout << "\n";
return(1);
case 1:
return(1);
};
} else {
if (this->right->value != NULL) {
switch (this->right->eval_leaf(&lResRight)) {
case 2:
this->display_expr(); cout << "\n";
return(1);
case 1:
return(1);
};
}
}
}
switch (this->operand) {
case NONE:
if (this->left == NULL) {
cerr << "eval_expr: Expr or value missing ...\n";
return(2);
}
*pRes = lResLeft;
break;
case AND:
if (this->left == NULL || this->right == NULL) {
cerr << "eval_expr: AND operator, Expr or value missing ...\n";
return(2);
}
*pRes = (lResLeft & lResRight);
break;
case OR:
if (this->left == NULL || this->right == NULL) {
cerr << "eval_expr: OR operator, Expr or value missing ...\n";
return(2);
}
*pRes = (lResLeft | lResRight);
break;
case NOT:
if (this->right == NULL) {
cerr << "eval_expr: NOT operator, Expr or value missing ...\n";
return(2);
}
*pRes = !lResRight;
break;
case BNOT:
if (this->right == NULL) {
cerr << "eval_expr: BNOT operator, Expr or value missing ...\n";
return(2);
}
*pRes = ~lResRight;
break;
};
return(0);
}
///////////////// JIT ///////////////////////////
int compile_expr(asmjit::CodeHolder* pCode, asmjit::x86::Assembler* pAssembly) {
if (pCode == NULL) return(1);
if (pAssembly == NULL) return(1);
int lResLeftValue = 0;
int lResRightValue = 0;
int lResLeft = 0;
int lResRight = 0;
enum e_operand lOperand = NONE;
if (this->left != NULL) {
if (this->left->expr != NULL) {
if (this->left->value != NULL) {
fprintf(stderr, "compile_expr: Unexpected left value... %.*s\n", this->left->offset, this->left->value);
return(2);
}
lResLeft = 1;
} else {
if (this->left->value != NULL) {
switch (this->left->eval_leaf(&lResLeftValue)) {
case 2:
this->display_expr(); cout << "\n";
return(1);
case 1:
return(1);
};
}
}
}
if (this->right != NULL) {
if (this->right->expr != NULL) {
if (this->right->value != NULL) {
fprintf(stderr, "compile_expr: Unexpected right value... %.*s\n", this->right->offset, this->right->value);
return(2);
}
lResRight = 1;
} else {
if (this->right->value != NULL) {
switch (this->right->eval_leaf(&lResRightValue)) {
case 2:
this->display_expr(); cout << "\n";
return(1);
case 1:
return(1);
};
}
}
}
switch (this->operand) {
case NONE:
if (this->left == NULL) {
cerr << "compile_expr: Expr or value missing ...\n";
return(2);
}
if (lResLeft == 1) {
switch (this->left->expr->compile_expr(pCode, pAssembly)) {
case 2:
this->display_expr(); cout << "\n";
return(1);
case 1:
return(1);
};
} else {
pAssembly->mov(asmjit::x86::eax, (int32_t)lResLeftValue);
}
break;
case AND:
if (this->left == NULL || this->right == NULL) {
cerr << "compile_expr: AND operator, Expr or value missing ...\n";
return(2);
}
if (lResLeft == 1) {
switch (this->left->expr->compile_expr(pCode, pAssembly)) {
case 2:
this->display_expr(); cout << "\n";
return(1);
case 1:
return(1);
};
} else {
pAssembly->mov(asmjit::x86::eax, (int32_t)lResLeftValue);
}
if (lResRight == 1) {
pAssembly->push(asmjit::x86::eax);
switch (this->right->expr->compile_expr(pCode, pAssembly)) {
case 2:
this->display_expr(); cout << "\n";
return(1);
case 1:
return(1);
};
pAssembly->pop(asmjit::x86::ecx);
pAssembly->and_(asmjit::x86::eax, asmjit::x86::ecx);
} else {
pAssembly->and_(asmjit::x86::eax, (int32_t)lResRightValue);
}
break;
case OR:
if (this->left == NULL || this->right == NULL) {
cerr << "compile_expr: OR operator, Expr or value missing ...\n";
return(2);
}
if (lResLeft == 1) {
switch (this->left->expr->compile_expr(pCode, pAssembly)) {
case 2:
this->display_expr(); cout << "\n";
return(1);
case 1:
return(1);
};
} else {
pAssembly->mov(asmjit::x86::eax, (int32_t)lResLeftValue);
}
if (lResRight == 1) {
pAssembly->push(asmjit::x86::eax);
switch (this->right->expr->compile_expr(pCode, pAssembly)) {
case 2:
this->display_expr(); cout << "\n";
return(1);
case 1:
return(1);
};
pAssembly->pop(asmjit::x86::ecx);
pAssembly->or_(asmjit::x86::eax, asmjit::x86::ecx);
} else {
pAssembly->or_(asmjit::x86::eax, (int32_t)lResRightValue);
}
break;
case NOT:
if (this->right == NULL) {
cerr << "compile_expr: NOT operator, Expr or value missing ...\n";
return(2);
}
if (lResRight == 1) {
switch (this->right->expr->compile_expr(pCode, pAssembly)) {
case 2:
this->display_expr(); cout << "\n";
return(1);
case 1:
return(1);
};
pAssembly->not_(asmjit::x86::eax);
pAssembly->and_(asmjit::x86::eax, (int32_t)1);
} else {
pAssembly->mov(asmjit::x86::eax, (int32_t)lResRightValue);
pAssembly->not_(asmjit::x86::eax);
pAssembly->and_(asmjit::x86::eax, (int32_t)1);
}
break;
case BNOT:
if (this->right == NULL) {
cerr << "compile_expr: BNOT operator, Expr or value missing ...\n";
return(2);
}
if (lResRight == 1) {
switch (this->right->expr->compile_expr(pCode, pAssembly)) {
case 2:
this->display_expr(); cout << "\n";
return(1);
case 1:
return(1);
};
pAssembly->not_(asmjit::x86::eax);
} else {
pAssembly->mov(asmjit::x86::eax, (int32_t)lResRightValue);
pAssembly->not_(asmjit::x86::eax);
}
break;
};
return(0);
}
int compile_expr_start(asmjit::JitRuntime* pRunTime, asmjit::CodeHolder* pCode, int (**pCompiled_function)(void)) {
if (pRunTime == NULL) return(1);
asmjit::x86::Assembler lAssembly(pCode);
lAssembly.push(asmjit::x86::ebp); // Prolog
lAssembly.mov(asmjit::x86::ebp, asmjit::x86::esp);
lAssembly.pushfd();
lAssembly.push(asmjit::x86::ecx);
if (this->compile_expr(pCode, &lAssembly) != 0) {
return(1);
}
lAssembly.pop(asmjit::x86::ecx);
lAssembly.popfd();
lAssembly.pop(asmjit::x86::ebp); // Epilog
lAssembly.ret();
asmjit::Error lErr = pRunTime->add(pCompiled_function, pCode);
if (lErr) return(1);
return(0);
}
int dump_expr(asmjit::CodeHolder* pCode, int (*pCompiled_function)(void)) {
if (pCode == NULL) return(1);
unsigned char* lOffset;
unsigned long lSize;
if (pCompiled_function != NULL) {
lOffset = (unsigned char*)pCompiled_function;
lSize = (unsigned long)pCode->codeSize();
while (lSize > 0) {
printf("%02X", lOffset[0]);
lOffset++;
lSize--;
if (lSize > 0) cout << " ";
}
}
return(0);
}
int exec_expr(int (*pCompiled_function)(void), int* pRes) {
if (pCompiled_function == NULL) return(1);
if (pRes == NULL) return(1);
*pRes = pCompiled_function();
return(0);
}
};
}
using namespace parser;
int main(int nbargs, char* args[]) {
expression* lExpression;
int lRes;
if (nbargs > 0) {
lExpression = expression::build_expression(args[1]);
lExpression->display_expr();
cout << "\n";
if (lExpression->eval_expr(&lRes) == 0) {
cout << " => " << lRes << "\n";
} else {
cerr << " Error in expr...\n";
}
// JIT
int (*compiled_function)(void) = NULL;
asmjit::JitRuntime* lRunTime = new asmjit::JitRuntime();
if (lRunTime == NULL) return(1);
asmjit::CodeHolder lCode;
lCode.init(lRunTime->environment());
if (lExpression->compile_expr_start(lRunTime, &lCode, &compiled_function) == 0) {
cout << "Compiled: " << lCode.codeSize() << " [";
lExpression->dump_expr(&lCode, compiled_function);
cout << "]\n";
if (lExpression->exec_expr(compiled_function, &lRes) == 0) {
cout << "Res JIT : " << lRes << "\n";
} else {
cerr << "Failed to exec JIT..\n";
}
lRunTime->release(compiled_function);
} else {
cerr << "Failed to build JIT..\n";
}
}
return(0);
}
答案 6 :(得分:1)
我相信Lex and Yacc仍然是这类简单解析任务的最佳工具。
答案 7 :(得分:1)
不久前,我在嵌入式系统上为命令行处理器和脚本语言编写了一个完整的C表达式求值程序(即使用C语法编写的求值表达式)。我使用this算法描述作为起点。您可以直接使用附带的代码,但我不喜欢实现,并从算法描述中编写了自己的代码。它需要一些工作来支持所有C运算符,函数调用和变量,但这是一个明确的解释,因此是一个很好的起点,特别是如果你不需要那种完整性。
基本原则是对于使用堆栈和“反向波兰表示法”的计算机,表达式评估更容易,因此算法将具有相关优先顺序和圆括号的in-fix表示法表达式转换为RPN,然后通过弹出操作数,执行操作和推送结果,直到没有剩余操作并且堆栈上还剩下一个值。
答案 8 :(得分:0)
原则上编写表达式解析器很容易,但需要花费相当多的精力。
这是我用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
这可能不是您正在寻找的,但它会让您了解您的需求。