A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 214 lines 4.9 kB view raw
1#include "soc_desc.hpp" 2#include <cstdarg> 3#include <cstdio> 4 5using namespace soc_desc; 6 7namespace soc_desc 8{ 9 10namespace 11{ 12 13struct formula_evaluator 14{ 15 std::string formula; 16 size_t pos; 17 error_context_t& ctx; 18 std::string m_loc; 19 20 bool err(const char *fmt, ...) 21 { 22 char buffer[256]; 23 va_list args; 24 va_start(args, fmt); 25 vsnprintf(buffer,sizeof(buffer), fmt, args); 26 va_end(args); 27 ctx.add(err_t(err_t::FATAL, m_loc, buffer)); 28 return false; 29 } 30 31 formula_evaluator(const std::string& s, error_context_t& ctx):pos(0),ctx(ctx) 32 { 33 for(size_t i = 0; i < s.size(); i++) 34 if(!isspace(s[i])) 35 formula.push_back(s[i]); 36 } 37 38 void set_location(const std::string& loc) 39 { 40 m_loc = loc; 41 } 42 43 void adv() 44 { 45 pos++; 46 } 47 48 char cur() 49 { 50 return end() ? 0 : formula[pos]; 51 } 52 53 bool end() 54 { 55 return pos >= formula.size(); 56 } 57 58 bool parse_digit(char c, int basis, soc_word_t& res) 59 { 60 c = tolower(c); 61 if(isdigit(c)) 62 { 63 res = c - '0'; 64 return true; 65 } 66 if(basis == 16 && isxdigit(c)) 67 { 68 res = c + 10 - 'a'; 69 return true; 70 } 71 return false; 72 } 73 74 bool parse_signed(soc_word_t& res) 75 { 76 char op = cur(); 77 if(op == '+' || op == '-') 78 { 79 adv(); 80 if(!parse_signed(res)) 81 return false; 82 if(op == '-') 83 res *= -1; 84 return true; 85 } 86 else if(op == '(') 87 { 88 adv(); 89 if(!parse_expression(res)) 90 return false; 91 if(cur() != ')') 92 return err("expected ')', got '%c'", cur()); 93 adv(); 94 return true; 95 } 96 else if(isdigit(op)) 97 { 98 res = op - '0'; 99 adv(); 100 int basis = 10; 101 if(op == '0' && cur() == 'x') 102 { 103 basis = 16; 104 adv(); 105 } 106 soc_word_t digit = 0; 107 while(parse_digit(cur(), basis, digit)) 108 { 109 res = res * basis + digit; 110 adv(); 111 } 112 return true; 113 } 114 else if(isalpha(op) || op == '_') 115 { 116 std::string name; 117 while(isalnum(cur()) || cur() == '_') 118 { 119 name.push_back(cur()); 120 adv(); 121 } 122 return get_variable(name, res); 123 } 124 else 125 return err("express signed expression, got '%c'", op); 126 } 127 128 bool parse_term(soc_word_t& res) 129 { 130 if(!parse_signed(res)) 131 return false; 132 while(cur() == '*' || cur() == '/' || cur() == '%') 133 { 134 char op = cur(); 135 adv(); 136 soc_word_t tmp; 137 if(!parse_signed(tmp)) 138 return false; 139 if(op == '*') 140 res *= tmp; 141 else if(tmp != 0) 142 res = op == '/' ? res / tmp : res % tmp; 143 else 144 return err("division by 0"); 145 } 146 return true; 147 } 148 149 bool parse_expression(soc_word_t& res) 150 { 151 if(!parse_term(res)) 152 return false; 153 while(!end() && (cur() == '+' || cur() == '-')) 154 { 155 char op = cur(); 156 adv(); 157 soc_word_t tmp; 158 if(!parse_term(tmp)) 159 return false; 160 if(op == '+') 161 res += tmp; 162 else 163 res -= tmp; 164 } 165 return true; 166 } 167 168 bool parse(soc_word_t& res) 169 { 170 bool ok = parse_expression(res); 171 if(ok && !end()) 172 err("unexpected character '%c'", cur()); 173 return ok && end(); 174 } 175 176 virtual bool get_variable(std::string name, soc_word_t& res) 177 { 178 return err("unknown variable '%s'", name.c_str()); 179 } 180}; 181 182struct my_evaluator : public formula_evaluator 183{ 184 const std::map< std::string, soc_word_t>& var; 185 186 my_evaluator(const std::string& formula, const std::map< std::string, soc_word_t>& _var, 187 error_context_t& ctx) 188 :formula_evaluator(formula, ctx), var(_var) {} 189 190 virtual bool get_variable(std::string name, soc_word_t& res) 191 { 192 std::map< std::string, soc_word_t>::const_iterator it = var.find(name); 193 if(it == var.end()) 194 return formula_evaluator::get_variable(name, res); 195 else 196 { 197 res = it->second; 198 return true; 199 } 200 } 201}; 202 203} 204 205bool evaluate_formula(const std::string& formula, 206 const std::map< std::string, soc_word_t>& var, soc_word_t& result, 207 const std::string& loc, error_context_t& error) 208{ 209 my_evaluator e(formula, var, error); 210 e.set_location(loc); 211 return e.parse(result); 212} 213 214} // soc_desc