]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // |
2 | // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) | |
3 | // | |
4 | // Distributed under the Boost Software License, Version 1.0. (See | |
5 | // accompanying file LICENSE_1_0.txt or copy at | |
6 | // http://www.boost.org/LICENSE_1_0.txt) | |
7 | // | |
8 | #include "mo_lambda.hpp" | |
9 | #include <string.h> | |
10 | #include <stdlib.h> | |
11 | ||
12 | namespace boost { | |
13 | namespace locale { | |
14 | namespace gnu_gettext { | |
15 | namespace lambda { | |
16 | ||
17 | namespace { // anon | |
18 | struct identity : public plural { | |
19 | virtual int operator()(int n) const | |
20 | { | |
21 | return n; | |
22 | }; | |
23 | virtual identity *clone() const | |
24 | { | |
25 | return new identity(); | |
26 | } | |
27 | }; | |
28 | ||
29 | struct unary : public plural | |
30 | { | |
31 | unary(plural_ptr ptr) : | |
32 | op1(ptr) | |
33 | { | |
34 | } | |
35 | protected: | |
36 | plural_ptr op1; | |
37 | }; | |
38 | ||
39 | ||
40 | struct binary : public plural | |
41 | { | |
42 | binary(plural_ptr p1,plural_ptr p2) : | |
43 | op1(p1), | |
44 | op2(p2) | |
45 | { | |
46 | } | |
47 | protected: | |
48 | plural_ptr op1,op2; | |
49 | }; | |
50 | ||
51 | struct number : public plural | |
52 | { | |
53 | number(int v) : | |
54 | val(v) | |
55 | { | |
56 | } | |
57 | virtual int operator()(int /*n*/) const | |
58 | { | |
59 | return val; | |
60 | } | |
61 | virtual number *clone() const | |
62 | { | |
63 | return new number(val); | |
64 | } | |
65 | ||
66 | private: | |
67 | int val; | |
68 | }; | |
69 | ||
70 | #define UNOP(name,oper) \ | |
71 | struct name: public unary { \ | |
72 | name(plural_ptr op) : unary(op) \ | |
73 | { \ | |
74 | }; \ | |
75 | virtual int operator()(int n) const \ | |
76 | { \ | |
77 | return oper (*op1)(n); \ | |
78 | } \ | |
79 | virtual name *clone() const \ | |
80 | { \ | |
81 | plural_ptr op1_copy(op1->clone()); \ | |
82 | return new name(op1_copy); \ | |
83 | } \ | |
84 | }; | |
85 | ||
86 | #define BINOP(name,oper) \ | |
87 | struct name : public binary \ | |
88 | { \ | |
89 | name(plural_ptr p1,plural_ptr p2) : \ | |
90 | binary(p1,p2) \ | |
91 | { \ | |
92 | } \ | |
93 | \ | |
94 | virtual int operator()(int n) const \ | |
95 | { \ | |
96 | return (*op1)(n) oper (*op2)(n); \ | |
97 | } \ | |
98 | virtual name *clone() const \ | |
99 | { \ | |
100 | plural_ptr op1_copy(op1->clone()); \ | |
101 | plural_ptr op2_copy(op2->clone()); \ | |
102 | return new name(op1_copy,op2_copy); \ | |
103 | } \ | |
104 | }; | |
105 | ||
106 | #define BINOPD(name,oper) \ | |
107 | struct name : public binary { \ | |
108 | name(plural_ptr p1,plural_ptr p2) : \ | |
109 | binary(p1,p2) \ | |
110 | { \ | |
111 | } \ | |
112 | virtual int operator()(int n) const \ | |
113 | { \ | |
114 | int v1=(*op1)(n); \ | |
115 | int v2=(*op2)(n); \ | |
116 | return v2==0 ? 0 : v1 oper v2; \ | |
117 | } \ | |
118 | virtual name *clone() const \ | |
119 | { \ | |
120 | plural_ptr op1_copy(op1->clone()); \ | |
121 | plural_ptr op2_copy(op2->clone()); \ | |
122 | return new name(op1_copy,op2_copy); \ | |
123 | } \ | |
124 | }; | |
125 | ||
126 | enum { END = 0 , SHL = 256, SHR, GTE,LTE, EQ, NEQ, AND, OR, NUM, VARIABLE }; | |
127 | ||
128 | UNOP(l_not,!) | |
129 | UNOP(minus,-) | |
130 | UNOP(bin_not,~) | |
131 | ||
132 | BINOP(mul,*) | |
133 | BINOPD(div,/) | |
134 | BINOPD(mod,%) | |
135 | static int level10[]={3,'*','/','%'}; | |
136 | ||
137 | BINOP(add,+) | |
138 | BINOP(sub,-) | |
139 | static int level9[]={2,'+','-'}; | |
140 | ||
141 | BINOP(shl,<<) | |
142 | BINOP(shr,>>) | |
143 | static int level8[]={2,SHL,SHR}; | |
144 | ||
145 | BINOP(gt,>) | |
146 | BINOP(lt,<) | |
147 | BINOP(gte,>=) | |
148 | BINOP(lte,<=) | |
149 | static int level7[]={4,'<','>',GTE,LTE}; | |
150 | ||
151 | BINOP(eq,==) | |
152 | BINOP(neq,!=) | |
153 | static int level6[]={2,EQ,NEQ}; | |
154 | ||
155 | BINOP(bin_and,&) | |
156 | static int level5[]={1,'&'}; | |
157 | ||
158 | BINOP(bin_xor,^) | |
159 | static int level4[]={1,'^'}; | |
160 | ||
161 | BINOP(bin_or,|) | |
162 | static int level3[]={1,'|'}; | |
163 | ||
164 | BINOP(l_and,&&) | |
165 | static int level2[]={1,AND}; | |
166 | ||
167 | BINOP(l_or,||) | |
168 | static int level1[]={1,OR}; | |
169 | ||
170 | struct conditional : public plural { | |
171 | conditional(plural_ptr p1,plural_ptr p2,plural_ptr p3) : | |
172 | op1(p1), | |
173 | op2(p2), | |
174 | op3(p3) | |
175 | { | |
176 | } | |
177 | virtual int operator()(int n) const | |
178 | { | |
179 | return (*op1)(n) ? (*op2)(n) : (*op3)(n); | |
180 | } | |
181 | virtual conditional *clone() const | |
182 | { | |
183 | plural_ptr op1_copy(op1->clone()); | |
184 | plural_ptr op2_copy(op2->clone()); | |
185 | plural_ptr op3_copy(op3->clone()); | |
186 | return new conditional(op1_copy,op2_copy,op3_copy); | |
187 | } | |
188 | private: | |
189 | plural_ptr op1,op2,op3; | |
190 | }; | |
191 | ||
192 | ||
193 | plural_ptr bin_factory(int value,plural_ptr left,plural_ptr right) | |
194 | { | |
195 | ||
196 | switch(value) { | |
197 | case '/': return plural_ptr(new div(left,right)); | |
198 | case '*': return plural_ptr(new mul(left,right)); | |
199 | case '%': return plural_ptr(new mod(left,right)); | |
200 | case '+': return plural_ptr(new add(left,right)); | |
201 | case '-': return plural_ptr(new sub(left,right)); | |
202 | case SHL: return plural_ptr(new shl(left,right)); | |
203 | case SHR: return plural_ptr(new shr(left,right)); | |
204 | case '>': return plural_ptr(new gt(left,right)); | |
205 | case '<': return plural_ptr(new lt(left,right)); | |
206 | case GTE: return plural_ptr(new gte(left,right)); | |
207 | case LTE: return plural_ptr(new lte(left,right)); | |
208 | case EQ: return plural_ptr(new eq(left,right)); | |
209 | case NEQ: return plural_ptr(new neq(left,right)); | |
210 | case '&': return plural_ptr(new bin_and(left,right)); | |
211 | case '^': return plural_ptr(new bin_xor(left,right)); | |
212 | case '|': return plural_ptr(new bin_or (left,right)); | |
213 | case AND: return plural_ptr(new l_and(left,right)); | |
214 | case OR: return plural_ptr(new l_or(left,right)); | |
215 | default: | |
216 | return plural_ptr(); | |
217 | } | |
218 | } | |
219 | ||
7c673cae FG |
220 | static inline bool is_in(int v,int *p) |
221 | { | |
222 | int len=*p; | |
223 | p++; | |
224 | while(len && *p!=v) { p++;len--; } | |
225 | return len!=0; | |
226 | } | |
227 | ||
228 | ||
229 | class tokenizer { | |
230 | public: | |
231 | tokenizer(char const *s) { text=s; pos=0; step(); }; | |
232 | int get(int *val=NULL){ | |
233 | int iv=int_value; | |
234 | int res=next_tocken; | |
235 | step(); | |
236 | if(val && res==NUM){ | |
237 | *val=iv; | |
238 | } | |
239 | return res; | |
240 | }; | |
241 | int next(int *val=NULL) { | |
242 | if(val && next_tocken==NUM) { | |
243 | *val=int_value; | |
244 | return NUM; | |
245 | } | |
246 | return next_tocken; | |
247 | } | |
248 | private: | |
249 | char const *text; | |
250 | int pos; | |
251 | int next_tocken; | |
252 | int int_value; | |
253 | bool is_blank(char c) | |
254 | { | |
255 | return c==' ' || c=='\r' || c=='\n' || c=='\t'; | |
256 | } | |
257 | bool isdigit(char c) | |
258 | { | |
259 | return '0'<=c && c<='9'; | |
260 | } | |
261 | void step() | |
262 | { | |
263 | while(text[pos] && is_blank(text[pos])) pos++; | |
264 | char const *ptr=text+pos; | |
265 | char *tmp_ptr; | |
266 | if(strncmp(ptr,"<<",2)==0) { pos+=2; next_tocken=SHL; } | |
267 | else if(strncmp(ptr,">>",2)==0) { pos+=2; next_tocken=SHR; } | |
268 | else if(strncmp(ptr,"&&",2)==0) { pos+=2; next_tocken=AND; } | |
269 | else if(strncmp(ptr,"||",2)==0) { pos+=2; next_tocken=OR; } | |
270 | else if(strncmp(ptr,"<=",2)==0) { pos+=2; next_tocken=LTE; } | |
271 | else if(strncmp(ptr,">=",2)==0) { pos+=2; next_tocken=GTE; } | |
272 | else if(strncmp(ptr,"==",2)==0) { pos+=2; next_tocken=EQ; } | |
273 | else if(strncmp(ptr,"!=",2)==0) { pos+=2; next_tocken=NEQ; } | |
274 | else if(*ptr=='n') { pos++; next_tocken=VARIABLE; } | |
275 | else if(isdigit(*ptr)) { int_value=strtol(text+pos,&tmp_ptr,0); pos=tmp_ptr-text; next_tocken=NUM; } | |
276 | else if(*ptr=='\0') { next_tocken=0; } | |
277 | else { next_tocken=*ptr; pos++; } | |
278 | } | |
279 | }; | |
280 | ||
281 | ||
282 | #define BINARY_EXPR(expr,hexpr,list) \ | |
283 | plural_ptr expr() \ | |
284 | { \ | |
285 | plural_ptr op1,op2; \ | |
286 | if((op1=hexpr()).get()==0) \ | |
287 | return plural_ptr(); \ | |
288 | while(is_in(t.next(),list)) { \ | |
289 | int o=t.get(); \ | |
290 | if((op2=hexpr()).get()==0) \ | |
291 | return plural_ptr(); \ | |
292 | op1=bin_factory(o,op1,op2); \ | |
293 | } \ | |
294 | return op1; \ | |
295 | } | |
296 | ||
297 | class parser { | |
298 | public: | |
299 | ||
300 | parser(tokenizer &tin) : t(tin) {}; | |
301 | ||
302 | plural_ptr compile() | |
303 | { | |
304 | plural_ptr res=cond_expr(); | |
305 | if(res.get() && t.next()!=END) { | |
306 | return plural_ptr(); | |
307 | }; | |
308 | return res; | |
309 | } | |
310 | ||
311 | private: | |
312 | ||
313 | plural_ptr value_expr() | |
314 | { | |
315 | plural_ptr op; | |
316 | if(t.next()=='(') { | |
317 | t.get(); | |
318 | if((op=cond_expr()).get()==0) | |
319 | return plural_ptr(); | |
320 | if(t.get()!=')') | |
321 | return plural_ptr(); | |
322 | return op; | |
323 | } | |
324 | else if(t.next()==NUM) { | |
325 | int value; | |
326 | t.get(&value); | |
327 | return plural_ptr(new number(value)); | |
328 | } | |
329 | else if(t.next()==VARIABLE) { | |
330 | t.get(); | |
331 | return plural_ptr(new identity()); | |
332 | } | |
333 | return plural_ptr(); | |
334 | }; | |
335 | ||
336 | plural_ptr un_expr() | |
337 | { | |
338 | plural_ptr op1; | |
339 | static int level_unary[]={3,'-','!','~'}; | |
340 | if(is_in(t.next(),level_unary)) { | |
341 | int op=t.get(); | |
342 | if((op1=un_expr()).get()==0) | |
343 | return plural_ptr(); | |
344 | switch(op) { | |
345 | case '-': | |
346 | return plural_ptr(new minus(op1)); | |
347 | case '!': | |
348 | return plural_ptr(new l_not(op1)); | |
349 | case '~': | |
350 | return plural_ptr(new bin_not(op1)); | |
351 | default: | |
352 | return plural_ptr(); | |
353 | } | |
354 | } | |
355 | else { | |
356 | return value_expr(); | |
357 | } | |
358 | }; | |
359 | ||
360 | BINARY_EXPR(l10,un_expr,level10); | |
361 | BINARY_EXPR(l9,l10,level9); | |
362 | BINARY_EXPR(l8,l9,level8); | |
363 | BINARY_EXPR(l7,l8,level7); | |
364 | BINARY_EXPR(l6,l7,level6); | |
365 | BINARY_EXPR(l5,l6,level5); | |
366 | BINARY_EXPR(l4,l5,level4); | |
367 | BINARY_EXPR(l3,l4,level3); | |
368 | BINARY_EXPR(l2,l3,level2); | |
369 | BINARY_EXPR(l1,l2,level1); | |
370 | ||
371 | plural_ptr cond_expr() | |
372 | { | |
373 | plural_ptr cond,case1,case2; | |
374 | if((cond=l1()).get()==0) | |
375 | return plural_ptr(); | |
376 | if(t.next()=='?') { | |
377 | t.get(); | |
378 | if((case1=cond_expr()).get()==0) | |
379 | return plural_ptr(); | |
380 | if(t.get()!=':') | |
381 | return plural_ptr(); | |
382 | if((case2=cond_expr()).get()==0) | |
383 | return plural_ptr(); | |
384 | } | |
385 | else { | |
386 | return cond; | |
387 | } | |
388 | return plural_ptr(new conditional(cond,case1,case2)); | |
389 | } | |
390 | ||
391 | tokenizer &t; | |
392 | ||
393 | }; | |
394 | ||
395 | } // namespace anon | |
396 | ||
397 | plural_ptr compile(char const *str) | |
398 | { | |
399 | tokenizer t(str); | |
400 | parser p(t); | |
401 | return p.compile(); | |
402 | } | |
403 | ||
404 | ||
405 | } // lambda | |
406 | } // gnu_gettext | |
407 | } // locale | |
408 | } // boost | |
409 | ||
410 | // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 | |
411 |