fome-fw/firmware/controllers/core/logic_expression.cpp

302 lines
6.3 KiB
C++
Raw Normal View History

2014-10-03 12:05:03 -07:00
/**
* @file logic_expression.cpp
2014-10-09 00:02:51 -07:00
* @brief Logical expressions handling logic
*
* Here we parse and evaluate logical expressions in
* http://en.wikipedia.org/wiki/Reverse_Polish_notation
*
* Once the expressions are parsed on startup (that's a heavy operation),
* evaluating those is relatively efficient.
*
2014-10-03 12:05:03 -07:00
*
* @date Oct 3, 2014
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#include "main.h"
#include "logic_expression.h"
2014-10-05 11:03:00 -07:00
#include "le_functions.h"
2014-10-03 12:05:03 -07:00
2014-10-04 15:03:07 -07:00
LENameOrdinalPair * LE_FIRST = NULL;
/**
* the main point of these static fields is that their constructor would register
* them in the magic list of operator name/ordinal pairs
*/
static LENameOrdinalPair leAnd(LE_OPERATOR_AND, "and");
static LENameOrdinalPair leOr(LE_OPERATOR_OR, "or");
2014-11-17 12:03:37 -08:00
static LENameOrdinalPair leNot(LE_OPERATOR_NOT, "not");
2014-10-04 15:03:07 -07:00
static LENameOrdinalPair leMore(LE_OPERATOR_MORE, ">");
static LENameOrdinalPair leMoreOrEqual(LE_OPERATOR_MORE_OR_EQUAL, ">=");
2014-11-17 12:03:37 -08:00
static LENameOrdinalPair leLess(LE_OPERATOR_LESS, "<");
static LENameOrdinalPair leLessOrEquals(LE_OPERATOR_LESS_OR_EQUAL, "<=");
2014-10-05 07:03:00 -07:00
2014-11-18 11:03:28 -08:00
#define LE_EVAL_POOL_SIZE 32
static LECalculator evalCalc;
static LEElement evalPoolElements[LE_EVAL_POOL_SIZE];
static LEElementPool evalPool(evalPoolElements, LE_EVAL_POOL_SIZE);
2014-10-04 15:03:07 -07:00
LENameOrdinalPair::LENameOrdinalPair(le_action_e action, const char *name) {
this->action = action;
this->name = name;
2014-10-05 07:03:00 -07:00
this->next = LE_FIRST;
2014-10-04 15:03:07 -07:00
LE_FIRST = this;
}
2014-10-03 12:05:03 -07:00
LEElement::LEElement() {
action = LE_UNDEFINED;
next = NULL;
}
//void LEElement::init(le_action_e action, int iValue) {
// this->action = action;
// this->iValue = iValue;
//}
void LEElement::init(le_action_e action) {
this->action = action;
}
void LEElement::init(le_action_e action, float fValue) {
this->action = action;
this->fValue = fValue;
}
LECalculator::LECalculator() {
2014-10-03 15:03:01 -07:00
reset();
}
void LECalculator::reset() {
2014-10-03 12:05:03 -07:00
first = NULL;
2014-10-03 15:03:01 -07:00
stack.reset();
2014-10-03 12:05:03 -07:00
}
2014-10-06 02:03:01 -07:00
void LECalculator::reset(LEElement *element) {
first = NULL;
stack.reset();
add(element);
}
void LECalculator::add(LEElement *element) {
if (first == NULL) {
first = element;
} else {
LEElement *last = first;
while (last->next != NULL) {
last = last->next;
}
last->next = element;
}
}
2014-10-03 14:03:00 -07:00
static bool float2bool(float v) {
return v != 0;
}
2014-10-03 12:05:03 -07:00
2014-10-07 08:04:35 -07:00
float LECalculator::pop(le_action_e action) {
if (stack.size() == 0) {
firmwareError("empty stack for %d", action);
return NAN;
}
return stack.pop();
}
2014-10-06 05:03:03 -07:00
void LECalculator::doJob(Engine *engine, LEElement *element) {
2014-10-03 14:03:00 -07:00
switch (element->action) {
2014-10-03 12:05:03 -07:00
2014-10-03 14:03:00 -07:00
case LE_NUMERIC_VALUE:
2014-10-03 12:05:03 -07:00
stack.push(element->fValue);
2014-10-03 14:03:00 -07:00
break;
case LE_OPERATOR_AND: {
2014-10-07 08:04:35 -07:00
float v1 = pop(LE_OPERATOR_AND);
float v2 = pop(LE_OPERATOR_AND);
2014-10-03 14:03:00 -07:00
stack.push(float2bool(v1) && float2bool(v2));
}
break;
case LE_OPERATOR_OR: {
2014-10-07 08:04:35 -07:00
float v1 = pop(LE_OPERATOR_OR);
float v2 = pop(LE_OPERATOR_OR);
2014-10-03 14:03:00 -07:00
stack.push(float2bool(v1) || float2bool(v2));
}
break;
case LE_OPERATOR_LESS: {
2014-10-05 07:03:00 -07:00
// elements on stack are in reverse order
2014-10-07 08:04:35 -07:00
float v2 = pop(LE_OPERATOR_LESS);
float v1 = pop(LE_OPERATOR_LESS);
2014-10-03 14:03:00 -07:00
stack.push(v1 < v2);
}
break;
2014-10-05 07:03:00 -07:00
case LE_OPERATOR_NOT: {
2014-10-07 08:04:35 -07:00
float v = pop(LE_OPERATOR_NOT);
2014-10-05 07:03:00 -07:00
stack.push(!float2bool(v));
}
break;
2014-10-03 14:03:00 -07:00
case LE_OPERATOR_MORE: {
2014-10-05 07:03:00 -07:00
// elements on stack are in reverse order
2014-10-07 08:04:35 -07:00
float v2 = pop(LE_OPERATOR_MORE);
float v1 = pop(LE_OPERATOR_MORE);
2014-10-03 14:03:00 -07:00
stack.push(v1 > v2);
}
break;
case LE_OPERATOR_LESS_OR_EQUAL: {
2014-10-05 07:03:00 -07:00
// elements on stack are in reverse order
2014-10-07 08:04:35 -07:00
float v2 = pop(LE_OPERATOR_LESS_OR_EQUAL);
float v1 = pop(LE_OPERATOR_LESS_OR_EQUAL);
2014-10-03 12:05:03 -07:00
2014-10-03 14:03:00 -07:00
stack.push(v1 <= v2);
}
break;
case LE_OPERATOR_MORE_OR_EQUAL: {
2014-10-05 07:03:00 -07:00
// elements on stack are in reverse order
2014-10-07 08:04:35 -07:00
float v2 = pop(LE_OPERATOR_MORE_OR_EQUAL);
float v1 = pop(LE_OPERATOR_MORE_OR_EQUAL);
2014-10-03 14:03:00 -07:00
stack.push(v1 >= v2);
}
break;
2014-10-05 07:03:00 -07:00
case LE_UNDEFINED:
firmwareError("Undefined not expected here");
break;
2014-10-03 14:03:00 -07:00
default:
2014-10-09 00:02:51 -07:00
stack.push(getLEValue(engine, element->action));
2014-10-03 14:03:00 -07:00
}
}
2014-10-03 12:05:03 -07:00
2014-10-18 04:03:25 -07:00
float LECalculator::getValue2(LEElement *element, Engine *engine) {
reset(element);
return getValue(engine);
}
2014-10-06 05:03:03 -07:00
float LECalculator::getValue(Engine *engine) {
2014-10-03 14:03:00 -07:00
LEElement *element = first;
stack.reset();
while (element != NULL) {
2014-10-06 05:03:03 -07:00
doJob(engine, element);
2014-10-03 12:05:03 -07:00
element = element->next;
}
2014-10-07 08:04:35 -07:00
efiAssert(stack.size() == 1, "One value expected on stack", NAN);
2014-10-03 12:05:03 -07:00
return stack.pop();
}
2014-11-17 13:03:20 -08:00
LEElementPool::LEElementPool(LEElement *pool, int size) {
this->pool = pool;
2014-11-17 12:03:37 -08:00
this->size = size;
2014-10-03 15:03:01 -07:00
reset();
}
void LEElementPool::reset() {
index = 0;
}
LEElement *LEElementPool::next() {
2014-11-17 13:03:20 -08:00
if (index == size - 1) {
2014-11-18 12:03:13 -08:00
// todo: this should not be a fatal error, just an error
2014-10-06 02:03:01 -07:00
firmwareError("LE_ELEMENT_POOL_SIZE overflow");
return NULL;
}
2014-10-03 15:03:01 -07:00
return &pool[index++];
}
2014-10-04 08:03:38 -07:00
2014-10-04 11:02:53 -07:00
bool isNumeric(const char* line) {
return line[0] >= '0' && line[0] <= '9';
}
2014-11-17 12:03:37 -08:00
const char *getNextToken(const char *line, char *buffer) {
2014-10-04 08:03:38 -07:00
while (line[0] != 0 && line[0] == ' ') {
line++;
}
if (line[0] == 0) {
return NULL;
}
int tokenLen = indexOf(line, ' ');
if (tokenLen == -1) {
// no space - the whole remaining line is the token
strcpy(buffer, line);
return line + strlen(buffer);
}
strncpy(buffer, line, tokenLen);
buffer[tokenLen] = 0;
line += tokenLen;
return line;
}
2014-10-04 11:02:53 -07:00
le_action_e parseAction(const char * line) {
2014-10-04 15:03:07 -07:00
LENameOrdinalPair *pair = LE_FIRST;
while (pair != NULL) {
if (strEqualCaseInsensitive(pair->name, line)) {
2014-10-05 07:03:00 -07:00
return pair->action;
2014-10-04 15:03:07 -07:00
}
pair = pair->next;
2014-10-04 11:02:53 -07:00
}
return LE_UNDEFINED;
}
static char parsingBuffer[64];
2014-11-18 13:03:12 -08:00
LEElement *LEElementPool::parseExpression(const char * line) {
2014-10-04 11:02:53 -07:00
LEElement *first = NULL;
LEElement *last = NULL;
while (true) {
2014-11-17 12:03:37 -08:00
line = getNextToken(line, parsingBuffer);
2014-10-04 11:02:53 -07:00
if (line == NULL) {
/**
* No more tokens in this line
*/
return first;
}
2014-11-18 13:03:12 -08:00
LEElement *n = next();
2014-10-04 11:02:53 -07:00
if (isNumeric(parsingBuffer)) {
n->init(LE_NUMERIC_VALUE, atoff(parsingBuffer));
} else {
le_action_e action = parseAction(parsingBuffer);
2014-10-05 07:03:00 -07:00
if (action == LE_UNDEFINED) {
/**
* Cannot recognize token
*/
warning((obd_code_e) 0, "unrecognized [%s]", parsingBuffer);
return NULL;
}
2014-10-04 11:02:53 -07:00
n->init(action);
}
if (first == NULL) {
first = n;
last = n;
} else {
last->next = n;
last = last->next;
}
}
return first;
}
2014-11-18 12:03:13 -08:00
#if (EFI_PROD_CODE || EFI_SIMULATOR)
static void eval(char *line, Engine *engine) {
2014-11-18 13:03:12 -08:00
evalPool.reset();
evalPool.parseExpression(line);
2014-11-18 12:03:13 -08:00
}
void initEval(Engine *engine) {
2014-11-18 13:03:12 -08:00
addConsoleActionSP("eval", (VoidCharPtrVoidPtr)eval, engine);
2014-11-18 12:03:13 -08:00
}
#endif