@noɥʇʎԀʎzɐɹƆ is looking for a canonical parser and evaluator that can be build on a x86 and that generate x86 asm JIT evaluator for any boolean expression.
Here is a ANSI C99 basic parser and evaluator that build an expression tree with parse_tree
and evaluate the parsed tree with eval_expr
. This one avoid most of the usual pointer arithmetic and should be easily translated in many langages.
Error management is set to the basic minimum (missing or unexpected expression, wrong expr like NOT 1 NOT 0). It should not leak memory in case of wrong expression at parse, but not really tested in that way.
The eval_leaf
could be replaced with one kind of libc strtol()
, but it seems here better to do a basic int parsing delimited by an offset to avoid string allocations, as we deal with simple int normally.
The compile_expr
method generates an x86 asm evaluator for the expression and the exec_expr_JIT
method executes the resulting x86 asm evaluator. The exec_expr_JIT
actually uses mmap and MapViewOfFile which is Linux/BSD/MacOS and Windows only. A more generic way is in study.
EDIT: Added bitwise NOT operator (BNOT) as the ~
in expression.
To test it, simply build it with an ANSI C99 compiler and launch it with the expected expression to parse and evaluate as first argument :
$ 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
It will first display the parsed expression in flat tree form with <leaf>
and [operand]
, and then the result of its evaluation with => <result>
. Next, it will display the x86 asm codeof the evaluator build for the parsed expression with its size in bytes, followed by the result of the execution of this evaluator.
The parser and evaluator source :
#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);
}
X OR Y AND Z
allowed? – Pemba