diff options
| author | Amaury Pouly <amaury.pouly@gmail.com> | 2014-12-14 11:53:55 +0100 |
|---|---|---|
| committer | Amaury Pouly <amaury.pouly@gmail.com> | 2015-09-11 16:40:19 +0200 |
| commit | 1cada1f8339d6b5f8506277f80e62aaef77ab774 (patch) | |
| tree | 8477120e97832d659d2ffc471a8bfde73ad4c36e /utils/regtools/lib/formula.cpp | |
| parent | c8d3638b9ebc24e4766714da1c9f961e350799c6 (diff) | |
| download | rockbox-1cada1f8339d6b5f8506277f80e62aaef77ab774.zip rockbox-1cada1f8339d6b5f8506277f80e62aaef77ab774.tar.gz rockbox-1cada1f8339d6b5f8506277f80e62aaef77ab774.tar.bz2 rockbox-1cada1f8339d6b5f8506277f80e62aaef77ab774.tar.xz | |
soc_desc: new version of the desc file format
Fix qeditor to use the old soc_desc_v1.
Port hwstub_shell to the new description format.
Change-Id: I9fefbff534bfaa5c3603bb3dd8307a2b76e88cfc
Diffstat (limited to 'utils/regtools/lib/formula.cpp')
| -rw-r--r-- | utils/regtools/lib/formula.cpp | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/utils/regtools/lib/formula.cpp b/utils/regtools/lib/formula.cpp new file mode 100644 index 0000000..1a6b16c --- /dev/null +++ b/utils/regtools/lib/formula.cpp @@ -0,0 +1,214 @@ +#include "soc_desc.hpp" +#include <cstdarg> +#include <cstdio> + +using namespace soc_desc; + +namespace soc_desc +{ + +namespace +{ + +struct formula_evaluator +{ + std::string formula; + size_t pos; + error_context_t& ctx; + std::string m_loc; + + bool err(const char *fmt, ...) + { + char buffer[256]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer,sizeof(buffer), fmt, args); + va_end(args); + ctx.add(error_t(error_t::FATAL, m_loc, buffer)); + return false; + } + + formula_evaluator(const std::string& s, error_context_t& ctx):pos(0),ctx(ctx) + { + for(size_t i = 0; i < s.size(); i++) + if(!isspace(s[i])) + formula.push_back(s[i]); + } + + void set_location(const std::string& loc) + { + m_loc = loc; + } + + void adv() + { + pos++; + } + + char cur() + { + return end() ? 0 : formula[pos]; + } + + bool end() + { + return pos >= formula.size(); + } + + bool parse_digit(char c, int basis, soc_word_t& res) + { + c = tolower(c); + if(isdigit(c)) + { + res = c - '0'; + return true; + } + if(basis == 16 && isxdigit(c)) + { + res = c + 10 - 'a'; + return true; + } + return false; + } + + bool parse_signed(soc_word_t& res) + { + char op = cur(); + if(op == '+' || op == '-') + { + adv(); + if(!parse_signed(res)) + return false; + if(op == '-') + res *= -1; + return true; + } + else if(op == '(') + { + adv(); + if(!parse_expression(res)) + return false; + if(cur() != ')') + return err("expected ')', got '%c'", cur()); + adv(); + return true; + } + else if(isdigit(op)) + { + res = op - '0'; + adv(); + int basis = 10; + if(op == '0' && cur() == 'x') + { + basis = 16; + adv(); + } + soc_word_t digit = 0; + while(parse_digit(cur(), basis, digit)) + { + res = res * basis + digit; + adv(); + } + return true; + } + else if(isalpha(op) || op == '_') + { + std::string name; + while(isalnum(cur()) || cur() == '_') + { + name.push_back(cur()); + adv(); + } + return get_variable(name, res); + } + else + return err("express signed expression, got '%c'", op); + } + + bool parse_term(soc_word_t& res) + { + if(!parse_signed(res)) + return false; + while(cur() == '*' || cur() == '/' || cur() == '%') + { + char op = cur(); + adv(); + soc_word_t tmp; + if(!parse_signed(tmp)) + return false; + if(op == '*') + res *= tmp; + else if(tmp != 0) + res = op == '/' ? res / tmp : res % tmp; + else + return err("division by 0"); + } + return true; + } + + bool parse_expression(soc_word_t& res) + { + if(!parse_term(res)) + return false; + while(!end() && (cur() == '+' || cur() == '-')) + { + char op = cur(); + adv(); + soc_word_t tmp; + if(!parse_term(tmp)) + return false; + if(op == '+') + res += tmp; + else + res -= tmp; + } + return true; + } + + bool parse(soc_word_t& res) + { + bool ok = parse_expression(res); + if(ok && !end()) + err("unexpected character '%c'", cur()); + return ok && end(); + } + + virtual bool get_variable(std::string name, soc_word_t& res) + { + return err("unknown variable '%s'", name.c_str()); + } +}; + +struct my_evaluator : public formula_evaluator +{ + const std::map< std::string, soc_word_t>& var; + + my_evaluator(const std::string& formula, const std::map< std::string, soc_word_t>& _var, + error_context_t& ctx) + :formula_evaluator(formula, ctx), var(_var) {} + + virtual bool get_variable(std::string name, soc_word_t& res) + { + std::map< std::string, soc_word_t>::const_iterator it = var.find(name); + if(it == var.end()) + return formula_evaluator::get_variable(name, res); + else + { + res = it->second; + return true; + } + } +}; + +} + +bool evaluate_formula(const std::string& formula, + const std::map< std::string, soc_word_t>& var, soc_word_t& result, + const std::string& loc, error_context_t& error) +{ + my_evaluator e(formula, var, error); + e.set_location(loc); + return e.parse(result); +} + +} // soc_desc |