2022-04-03 16:43:04 +01:00
|
|
|
#ifndef ZYLANN_EXPRESSION_PARSER_H
|
|
|
|
#define ZYLANN_EXPRESSION_PARSER_H
|
|
|
|
|
|
|
|
#include "fixed_array.h"
|
2022-04-06 22:00:32 +01:00
|
|
|
#include "memory.h"
|
2022-04-03 16:43:04 +01:00
|
|
|
#include "span.h"
|
|
|
|
#include <string_view>
|
|
|
|
|
|
|
|
namespace zylann {
|
|
|
|
namespace ExpressionParser {
|
|
|
|
|
|
|
|
struct Node {
|
|
|
|
enum Type { //
|
|
|
|
NUMBER,
|
|
|
|
VARIABLE,
|
|
|
|
OPERATOR,
|
|
|
|
FUNCTION,
|
|
|
|
TYPE_COUNT,
|
|
|
|
INVALID
|
|
|
|
};
|
|
|
|
|
|
|
|
Type type = INVALID;
|
|
|
|
|
|
|
|
virtual ~Node() {}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct NumberNode : Node {
|
|
|
|
float value;
|
|
|
|
|
|
|
|
NumberNode(float p_value) : value(p_value) {
|
|
|
|
type = Node::NUMBER;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct VariableNode : Node {
|
|
|
|
std::string_view name;
|
|
|
|
|
|
|
|
VariableNode(std::string_view p_name) : name(p_name) {
|
|
|
|
type = Node::VARIABLE;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct OperatorNode : Node {
|
|
|
|
enum Operation { //
|
|
|
|
ADD,
|
|
|
|
SUBTRACT,
|
|
|
|
MULTIPLY,
|
|
|
|
DIVIDE,
|
|
|
|
POWER,
|
|
|
|
OP_COUNT
|
|
|
|
};
|
|
|
|
|
|
|
|
Operation op;
|
2022-04-06 22:00:32 +01:00
|
|
|
UniquePtr<Node> n0;
|
|
|
|
UniquePtr<Node> n1;
|
2022-04-03 16:43:04 +01:00
|
|
|
|
2022-04-06 22:00:32 +01:00
|
|
|
OperatorNode(Operation p_op, UniquePtr<Node> a, UniquePtr<Node> b) : op(p_op), n0(std::move(a)), n1(std::move(b)) {
|
2022-04-03 16:43:04 +01:00
|
|
|
type = OPERATOR;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct FunctionNode : Node {
|
|
|
|
unsigned int function_id;
|
2022-04-06 22:00:32 +01:00
|
|
|
FixedArray<UniquePtr<Node>, 4> args;
|
2022-04-03 16:43:04 +01:00
|
|
|
|
|
|
|
FunctionNode() {
|
|
|
|
type = Node::FUNCTION;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
enum ErrorID { //
|
|
|
|
ERROR_NONE,
|
|
|
|
ERROR_INVALID,
|
|
|
|
ERROR_UNEXPECTED_END,
|
|
|
|
ERROR_INVALID_NUMBER,
|
|
|
|
ERROR_INVALID_TOKEN,
|
|
|
|
ERROR_UNEXPECTED_TOKEN,
|
|
|
|
ERROR_UNKNOWN_FUNCTION,
|
2022-04-06 01:00:06 +01:00
|
|
|
ERROR_EXPECTED_ARGUMENT,
|
|
|
|
ERROR_TOO_FEW_ARGUMENTS,
|
2022-04-06 00:08:58 +01:00
|
|
|
ERROR_TOO_MANY_ARGUMENTS,
|
2022-04-03 16:43:04 +01:00
|
|
|
ERROR_UNCLOSED_PARENTHESIS,
|
|
|
|
ERROR_MISSING_OPERAND_ARGUMENTS,
|
|
|
|
ERROR_MULTIPLE_OPERANDS,
|
|
|
|
ERROR_COUNT
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Error {
|
|
|
|
ErrorID id = ERROR_NONE;
|
|
|
|
std::string_view symbol;
|
|
|
|
unsigned int position = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Result {
|
2022-04-06 22:00:32 +01:00
|
|
|
UniquePtr<Node> root;
|
2022-04-03 16:43:04 +01:00
|
|
|
Error error;
|
|
|
|
};
|
|
|
|
|
2022-04-06 01:13:38 +01:00
|
|
|
typedef float (*FunctionCallback)(Span<const float>);
|
|
|
|
|
2022-04-03 16:43:04 +01:00
|
|
|
struct Function {
|
|
|
|
std::string_view name;
|
|
|
|
unsigned int argument_count = 0;
|
|
|
|
unsigned int id = 0;
|
2022-04-06 01:13:38 +01:00
|
|
|
FunctionCallback func = nullptr;
|
2022-04-03 16:43:04 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
// TODO `text` should be `const`
|
|
|
|
Result parse(std::string_view text, Span<const Function> functions);
|
|
|
|
bool is_tree_equal(const Node &root_a, const Node &root_b, Span<const Function> functions);
|
|
|
|
std::string tree_to_string(const Node &node, Span<const Function> functions);
|
|
|
|
std::string to_string(const Error error);
|
|
|
|
void find_variables(const Node &node, std::vector<std::string_view> &variables);
|
|
|
|
|
|
|
|
// TODO Just use indices in the span? Or pointers?
|
|
|
|
inline const Function *find_function_by_id(unsigned int id, Span<const Function> functions) {
|
|
|
|
for (unsigned int i = 0; i < functions.size(); ++i) {
|
|
|
|
const Function &f = functions[i];
|
|
|
|
if (f.id == id) {
|
|
|
|
return &f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace ExpressionParser
|
|
|
|
} // namespace zylann
|
|
|
|
|
|
|
|
#endif // ZYLANN_EXPRESSION_PARSER_H
|