shuntingyard as a class library

This commit is contained in:
proddy
2025-09-21 19:16:55 +02:00
parent 61bf2332bb
commit 76c0aa6be8
3 changed files with 97 additions and 196 deletions

View File

@@ -17,37 +17,10 @@
// copy from https://gist.github.com/t-mat/b9f681b7591cdae712f6
// modified MDvP, 06.2024
//
#include <string>
#include <vector>
#include <deque>
#include <math.h>
class Token {
public:
enum class Type : uint8_t {
Unknown,
Number,
String,
Operator,
Compare,
Logic,
Unary,
LeftParen,
RightParen,
};
#include "emsesp.h"
Token(Type type, const std::string & s, int8_t precedence = -1, bool rightAssociative = false)
: type{type}
, str(s)
, precedence{precedence}
, rightAssociative{rightAssociative} {
}
const Type type;
const std::string str;
const int8_t precedence;
const bool rightAssociative;
};
#include "shuntingYard.h"
// find tokens
std::deque<Token> exprToTokens(const std::string & expr) {
@@ -357,7 +330,7 @@ bool isnum(const std::string & s) {
// replace commands like "<device>/<hc>/<cmd>" with its value"
std::string commands(std::string & expr, bool quotes = true) {
std::string commands(std::string & expr, bool quotes) {
auto expr_new = emsesp::Helpers::toLower(expr);
for (uint8_t device = 0; device < emsesp::EMSdevice::DeviceType::UNKNOWN; device++) {
const char * d = emsesp::EMSdevice::device_type_2_device_name(device);
@@ -375,6 +348,7 @@ std::string commands(std::string & expr, bool quotes = true) {
}
expr_new.copy(cmd, l, f);
cmd[l] = '\0';
if (strstr(cmd, "/value") == nullptr) {
strlcat(cmd, "/value", sizeof(cmd) - 6);
}
@@ -445,23 +419,21 @@ std::string calculate(const std::string & expr) {
commands(expr_new);
const auto tokens = exprToTokens(expr_new);
// for debugging only
// for (const auto & t : tokens) {
// emsesp::EMSESP::logger().debug("shunt token: %s(%d)", t.str.c_str(), t.type);
// Serial.printf("shunt token: %s(%d)\n", t.str.c_str(), t.type);
// Serial.println();
// }
if (tokens.empty()) {
return "";
}
auto queue = shuntingYard(tokens);
if (queue.empty()) {
return "";
}
/*
// debug only print tokens
#ifdef EMSESP_STANDALONE
for (const auto & t : queue) {
emsesp::EMSESP::logger().debug("shunt token: %s(%d)", t.str.c_str(), t.type);
}
#endif
*/
std::vector<std::string> stack;
while (!queue.empty()) {

86
src/core/shuntingYard.h Normal file
View File

@@ -0,0 +1,86 @@
// Shunting-yard Algorithm
// https://en.wikipedia.org/wiki/Shunting-yard_algorithm
//
// Implementation notes for unary operators by Austin Taylor
// https://stackoverflow.com/a/5240912
//
// Example:
// https://ideone.com/VocUTq
//
// License:
// This code uses the following materials.
// (1) Wikipedia article [Shunting-yard algorithm](https://en.wikipedia.org/wiki/Shunting-yard_algorithm),
// which is released under the [Creative Commons Attribution-Share-Alike License 3.0](https://creativecommons.org/licenses/by-sa/3.0/).
// (2) [Implementation notes for unary operators in Shunting-Yard algorithm](https://stackoverflow.com/a/5240912) by Austin Taylor
// which is released under the [Creative Commons Attribution-Share-Alike License 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
//
// copy from https://gist.github.com/t-mat/b9f681b7591cdae712f6
// modified MDvP, 06.2024
//
#ifndef EMSESP_SHUNTING_YARD_H_
#define EMSESP_SHUNTING_YARD_H_
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <string>
#include <vector>
#include <deque>
#include <math.h>
class Token {
public:
enum class Type : uint8_t {
Unknown,
Number,
String,
Operator,
Compare,
Logic,
Unary,
LeftParen,
RightParen,
};
Token(Type type, const std::string & s, int8_t precedence = -1, bool rightAssociative = false)
: type{type}
, str(s)
, precedence{precedence}
, rightAssociative{rightAssociative} {
}
const Type type;
const std::string str;
const int8_t precedence;
const bool rightAssociative;
};
// find tokens
std::deque<Token> exprToTokens(const std::string & expr);
// sort tokens to RPN form
std::deque<Token> shuntingYard(const std::deque<Token> & tokens);
// check if string is a number
bool isnum(const std::string & s);
// replace commands like "<device>/<hc>/<cmd>" with its value"
std::string commands(std::string & expr, bool quotes = true);
// checks for logic value
int to_logic(const std::string & s);
// number to string, remove trailing zeros
std::string to_string(double d);
// number to hex string
std::string to_hex(uint32_t i);
// RPN calculator
std::string calculate(const std::string & expr);
// check for multiple instances of <cond> ? <expr1> : <expr2>
std::string compute(const std::string & expr);
#endif