summaryrefslogtreecommitdiff
path: root/utils/regtools/lib/formula.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/regtools/lib/formula.cpp')
-rw-r--r--utils/regtools/lib/formula.cpp214
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 0000000000..1a6b16c773
--- /dev/null
+++ b/utils/regtools/lib/formula.cpp
@@ -0,0 +1,214 @@
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(error_t(error_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