Skip to content

Instantly share code, notes, and snippets.

@JJL772
Created August 13, 2021 09:14
Show Gist options
  • Save JJL772/5fce9c54321e6c7a82621756419115d6 to your computer and use it in GitHub Desktop.
Save JJL772/5fce9c54321e6c7a82621756419115d6 to your computer and use it in GitHub Desktop.
quick & dirty boolean expression evaluator
/* 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