Created
August 13, 2021 09:14
-
-
Save JJL772/5fce9c54321e6c7a82621756419115d6 to your computer and use it in GitHub Desktop.
quick & dirty boolean expression evaluator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Simple logical expression evaluator */ | |
#pragma once | |
#include <ctype.h> | |
#include <stdio.h> | |
#include <memory.h> | |
#define PARAM_MAX (('Z' - 'A')+1) | |
#define OP_OR '|' | |
#define OP_AND '&' | |
#define OP_COM '~' | |
#define OP_NOT '!' /* Functionally the same as complement */ | |
#define OP_XOR '^' | |
#define IS_OP(x) (x==OP_OR||x==OP_AND||x==OP_COM||x==OP_NOT||x==OP_XOR) | |
#define IS_VAR(x) (x <= 'Z' && x >= 'A') | |
#define OP_PRECEDENCE(x) (((x)==OP_OR||(x)==OP_XOR)?0:(x)==OP_AND?1:2) | |
typedef enum { | |
EXPR_OK, | |
EXPR_ERR_BAD_TOKEN, | |
EXPR_ERR_UNMATCHED_CLOSING_PARENTHS, | |
EXPR_ERR_SMALL_BUF, // Output buffer too small | |
} ExprError_t; | |
/* Takes an expression in infix notation and converts it to RPN using the shunting yard algorithm */ | |
ExprError_t expr_parse(const char* expr, char* rpn, size_t rpn_size) { | |
char out_queue[256]; /* Output queue */ | |
char opstack[256]; | |
memset(out_queue,0,sizeof(out_queue)); | |
int queuei = 0; | |
int stacki = 0; | |
const char* s = expr; | |
for(s=expr;s&&*s;s++) { | |
if(isspace(*s)) | |
continue; | |
if(*s == '(') { | |
opstack[stacki++] = *s; | |
continue; | |
} | |
if(IS_OP(*s)) { | |
while(opstack[stacki-1] != '(' && stacki > 0 && OP_PRECEDENCE(opstack[stacki-1]) > OP_PRECEDENCE(*s)) { | |
out_queue[queuei++] = opstack[stacki-1]; | |
stacki--; | |
} | |
opstack[stacki++] = *s; | |
continue; | |
} | |
if(*s==')') { | |
while(opstack[stacki-1] != '(' && stacki > 0) { | |
out_queue[queuei++] = opstack[stacki-1]; | |
stacki--; | |
} | |
if(stacki <= 0 || opstack[stacki-1] != '(') | |
return EXPR_ERR_UNMATCHED_CLOSING_PARENTHS; | |
opstack[stacki-1] = 0; | |
stacki--; | |
continue; | |
} | |
if(IS_VAR(*s)) { | |
out_queue[queuei++] = *s; | |
continue; | |
} | |
return EXPR_ERR_BAD_TOKEN; | |
} | |
while(stacki > 0) { | |
out_queue[queuei++] = opstack[stacki-1]; | |
stacki--; | |
} | |
if(queuei >= rpn_size) | |
return EXPR_ERR_SMALL_BUF; | |
strncpy(rpn, out_queue, queuei); | |
rpn[rpn_size-1] = 0; | |
return EXPR_OK; | |
} | |
/* Evaluates the boolean expression in RPN */ | |
/* varvals is an array of 26 items representing each A-Z variable's value */ | |
bool expr_eval(const char* rpn, bool* varvals) { | |
bool varstack[256]; | |
int vstacki = 0; | |
#define OP_CHECK(n) if(vstacki < n) {asm("int3\n\t");return false;} | |
const char* s; | |
for(s = rpn; s && *s; ++s) { | |
if(IS_VAR(*s)) { | |
varstack[vstacki++] = varvals[*s-'A']; | |
continue; | |
} | |
if(IS_OP(*s)) { | |
bool a,b; | |
switch(*s) { | |
case OP_OR: | |
OP_CHECK(2); | |
a = varstack[vstacki-1]; | |
b = varstack[vstacki-2]; | |
vstacki-=2; | |
varstack[vstacki] = a||b; | |
break; | |
case OP_AND: | |
OP_CHECK(2); | |
a = varstack[vstacki-1]; | |
b = varstack[vstacki-2]; | |
vstacki-=2; | |
varstack[vstacki] = a&&b; | |
break; | |
case OP_COM: | |
case OP_NOT: | |
OP_CHECK(1); | |
vstacki-=1; | |
varstack[vstacki] = !varstack[vstacki]; | |
break; | |
case OP_XOR: | |
OP_CHECK(2); | |
a = varstack[vstacki-1]; | |
b = varstack[vstacki-2]; | |
vstacki-=2; | |
varstack[vstacki] = a^b; | |
break; | |
default: | |
return false; | |
} | |
} | |
} | |
#undef OP_CHECK | |
return varstack[0]; // Should hold the result | |
} | |
#undef IS_OP | |
#undef IS_VAR | |
#undef OP_PRECEDENCE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment