diff options
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 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 | |||
5 | using namespace soc_desc; | ||
6 | |||
7 | namespace soc_desc | ||
8 | { | ||
9 | |||
10 | namespace | ||
11 | { | ||
12 | |||
13 | struct 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 | |||
182 | struct 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 | |||
205 | bool 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 | ||