Refactored rules USE_EXPRESSION and SUPPORT_IF_STATEMENT replacing LinkedList with arrays

This commit is contained in:
Theo Arends 2024-01-23 23:52:18 +01:00
parent d531583721
commit a74200d40d
3 changed files with 98 additions and 44 deletions

View File

@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file.
### Changed ### Changed
- Refactored rules ``Subscribe`` using LList allowing full message size and enabled by default - Refactored rules ``Subscribe`` using LList allowing full message size and enabled by default
- Refactored rules USE_EXPRESSION and SUPPORT_IF_STATEMENT replacing LinkedList with arrays
### Fixed ### Fixed

View File

@ -165,6 +165,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
- ESP32 platform update from 2023.11.01 to 2024.01.01 [#20473](https://github.com/arendst/Tasmota/issues/20473) - ESP32 platform update from 2023.11.01 to 2024.01.01 [#20473](https://github.com/arendst/Tasmota/issues/20473)
- Renamed button "Consoles" to "Tools" - Renamed button "Consoles" to "Tools"
- Refactored rule ``Subscribe`` using LList allowing full message size and enabled by default - Refactored rule ``Subscribe`` using LList allowing full message size and enabled by default
- Refactored rules USE_EXPRESSION and SUPPORT_IF_STATEMENT replacing LinkedList with arrays
- Support syslog updates every sleep or every second if `#define SYSLOG_UPDATE_SECOND` [#20260](https://github.com/arendst/Tasmota/issues/20260) - Support syslog updates every sleep or every second if `#define SYSLOG_UPDATE_SECOND` [#20260](https://github.com/arendst/Tasmota/issues/20260)
- Web file upload response on upload error [#20340](https://github.com/arendst/Tasmota/issues/20340) - Web file upload response on upload error [#20340](https://github.com/arendst/Tasmota/issues/20340)
- Header `Host` is now collected by Webserver [#20446](https://github.com/arendst/Tasmota/issues/20446) - Header `Host` is now collected by Webserver [#20446](https://github.com/arendst/Tasmota/issues/20446)

View File

@ -114,8 +114,6 @@
const char kCompareOperators[] PROGMEM = "=\0>\0<\0|\0==!=>=<=$>$<$|$!$^"; const char kCompareOperators[] PROGMEM = "=\0>\0<\0|\0==!=>=<=$>$<$|$!$^";
#ifdef USE_EXPRESSION #ifdef USE_EXPRESSION
#include <LinkedList.h> // Import LinkedList library
const char kExpressionOperators[] PROGMEM = "+-*/%^\0"; const char kExpressionOperators[] PROGMEM = "+-*/%^\0";
#define EXPRESSION_OPERATOR_ADD 0 #define EXPRESSION_OPERATOR_ADD 0
#define EXPRESSION_OPERATOR_SUBTRACT 1 #define EXPRESSION_OPERATOR_SUBTRACT 1
@ -127,7 +125,6 @@ const char kCompareOperators[] PROGMEM = "=\0>\0<\0|\0==!=>=<=$>$<$|$!$^";
const uint8_t kExpressionOperatorsPriorities[] PROGMEM = {1, 1, 2, 2, 3, 4}; const uint8_t kExpressionOperatorsPriorities[] PROGMEM = {1, 1, 2, 2, 3, 4};
#define MAX_EXPRESSION_OPERATOR_PRIORITY 4 #define MAX_EXPRESSION_OPERATOR_PRIORITY 4
#define LOGIC_OPERATOR_AND 1 #define LOGIC_OPERATOR_AND 1
#define LOGIC_OPERATOR_OR 2 #define LOGIC_OPERATOR_OR 2
@ -1642,53 +1639,92 @@ float calculateTwoValues(float v1, float v2, uint8_t op)
* 2 + 1 * 2 + 1
* 3 / 2 * 3 / 2
*/ */
float evaluateExpression(const char * expression, unsigned int len) float evaluateExpression(const char * expression, unsigned int len) {
{
char expbuf[len + 1]; char expbuf[len + 1];
memcpy(expbuf, expression, len); memcpy(expbuf, expression, len);
expbuf[len] = '\0'; expbuf[len] = '\0';
char * scan_pointer = expbuf; char * scan_pointer = expbuf;
LinkedList<float> object_values; float object_values[21];
LinkedList<int8_t> operators; int8_t operators[20];
int8_t op;
float va; float va;
//Find and add the value of first object //Find and add the value of first object
if (findNextObjectValue(scan_pointer, va)) { if (findNextObjectValue(scan_pointer, va)) {
object_values.add(va); object_values[0] = va;
} else { } else {
return 0; return 0;
} }
while (*scan_pointer)
{ uint32_t operators_size = 0;
uint32_t object_values_size = 1;
int8_t op;
while (*scan_pointer) {
if (findNextOperator(scan_pointer, op) if (findNextOperator(scan_pointer, op)
&& *scan_pointer && *scan_pointer
&& findNextObjectValue(scan_pointer, va)) && findNextObjectValue(scan_pointer, va))
{ {
operators.add(op); operators[operators_size++] = op;
object_values.add(va); object_values[object_values_size++] = va;
} else { } else {
//No operator followed or no more object after this operator, we done. //No operator followed or no more object after this operator, we done.
break; break;
} }
if (operators_size >= 20) {
AddLog(LOG_LEVEL_ERROR, PSTR("RUL: Too many arguments"));
}
} }
//Going to evaluate the whole expression // Going to evaluate the whole expression
//Calculate by order of operator priorities. Looking for all operators with specified priority (from High to Low) // Calculate by order of operator priorities. Looking for all operators with specified priority (from High to Low)
for (int32_t priority = MAX_EXPRESSION_OPERATOR_PRIORITY; priority>0; priority--) { for (int32_t priority = MAX_EXPRESSION_OPERATOR_PRIORITY; priority > 0; priority--) {
int index = 0; int index = 0;
while (index < operators.size()) { while (index < operators_size) {
if (priority == pgm_read_byte(kExpressionOperatorsPriorities + operators.get(index))) { //need to calculate the operator first if (priority == pgm_read_byte(kExpressionOperatorsPriorities + operators[index])) { //need to calculate the operator first
//get current object value and remove the next object with current operator // Get current object value and remove the next object with current operator
va = calculateTwoValues(object_values.get(index), object_values.remove(index + 1), operators.remove(index)); va = calculateTwoValues(object_values[index], object_values[index + 1], operators[index]);
uint32_t i = index;
while (i <= operators_size) {
operators[i++] = operators[i]; // operators.remove(index)
object_values[i] = object_values[i +1]; // object_values.remove(index + 1)
}
object_values_size--;
operators_size--;
/*
uint32_t i = index +1;
while (i <= object_values_size) {
object_values[i++] = object_values[i]; // object_values.remove(index + 1)
}
object_values_size--;
i = index;
while (i <= operators_size) {
operators[i++] = operators[i]; // operators.remove(index)
}
operators_size--;
*/
/*
for (uint32_t i = index +1; i <= object_values_size; i++) {
object_values[i] = object_values[i +1]; // object_values.remove(index + 1)
}
object_values_size--;
for (uint32_t i = index; i <= operators_size; i++) {
operators[i] = operators[i +1]; // operators.remove(index)
}
operators_size--;
*/
//Replace the current value with the result //Replace the current value with the result
object_values.set(index, va); object_values[index] = va;
} else { } else {
index++; index++;
} }
} }
} }
return object_values.get(0); return object_values[0];
} }
#endif // USE_EXPRESSION #endif // USE_EXPRESSION
@ -1873,58 +1909,74 @@ bool findNextLogicObjectValue(char * &pointer, bool &value)
* Return: * Return:
* boolean - the value of logical expression * boolean - the value of logical expression
*/ */
bool evaluateLogicalExpression(const char * expression, int len) bool evaluateLogicalExpression(const char * expression, int len) {
{
//Make a copy first //Make a copy first
char expbuff[len + 1]; char expbuff[len + 1];
memcpy(expbuff, expression, len); memcpy(expbuff, expression, len);
expbuff[len] = '\0'; expbuff[len] = '\0';
//AddLog(LOG_LEVEL_DEBUG, PSTR("EvalLogic: |%s|"), expbuff);
char * pointer = expbuff; char * pointer = expbuff;
LinkedList<bool> values;
LinkedList<int8_t> logicOperators; bool values[21];
int8_t logicOperators[20];
//Find first comparison expression //Find first comparison expression
bool bValue; bool bValue;
if (findNextLogicObjectValue(pointer, bValue)) { if (findNextLogicObjectValue(pointer, bValue)) {
values.add(bValue); values[0] = bValue;
} else { } else {
return false; return false;
} }
uint32_t logicOperators_size = 0;
uint32_t values_size = 1;
int8_t op; int8_t op;
while (*pointer) { while (*pointer) {
if (findNextLogicOperator(pointer, op) if (findNextLogicOperator(pointer, op)
&& (*pointer) && findNextLogicObjectValue(pointer, bValue)) && (*pointer) && findNextLogicObjectValue(pointer, bValue))
{ {
logicOperators.add(op); logicOperators[logicOperators_size++] = op;
values.add(bValue); values[values_size++] = bValue;
} else { } else {
break; break;
} }
if (logicOperators_size >= 20) {
AddLog(LOG_LEVEL_ERROR, PSTR("RUL: Too many arguments"));
} }
//Calculate all "AND" first }
// Calculate all "AND" first
int index = 0; int index = 0;
while (index < logicOperators.size()) { while (index < logicOperators_size) {
if (logicOperators.get(index) == LOGIC_OPERATOR_AND) { if (logicOperators[index] == LOGIC_OPERATOR_AND) {
values.set(index, values.get(index) && values.get(index+1)); values[index] &= values[index +1];
values.remove(index + 1); uint32_t i = index;
logicOperators.remove(index); while (i <= logicOperators_size) {
logicOperators[i++] = logicOperators[i]; // logicOperators.remove(index);
values[i] = values[i +1]; // values.remove(index + 1);
}
values_size--;
logicOperators_size--;
} else { } else {
index++; index++;
} }
} }
//Then, calculate all "OR" // Then, calculate all "OR"
index = 0; index = 0;
while (index < logicOperators.size()) { while (index < logicOperators_size) {
if (logicOperators.get(index) == LOGIC_OPERATOR_OR) { if (logicOperators[index] == LOGIC_OPERATOR_OR) {
values.set(index, values.get(index) || values.get(index+1)); values[index] |= values[index+1];
values.remove(index + 1); uint32_t i = index;
logicOperators.remove(index); while (i <= logicOperators_size) {
logicOperators[i++] = logicOperators[i]; // logicOperators.remove(index);
values[i] = values[i +1]; // values.remove(index + 1);
}
values_size--;
logicOperators_size--;
} else { } else {
index++; index++;
} }
} }
return values.get(0); return values[0];
} }
/********************************************************************************************/ /********************************************************************************************/