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 {
operator ()boost::locale::gnu_gettext::lambda::__anon338418d40111::identity19         virtual int operator()(int n) const
20         {
21             return n;
22         };
cloneboost::locale::gnu_gettext::lambda::__anon338418d40111::identity23         virtual identity *clone() const
24         {
25             return new identity();
26         }
27     };
28 
29     struct unary : public plural
30     {
unaryboost::locale::gnu_gettext::lambda::__anon338418d40111::unary31         unary(plural_ptr ptr) :
32             op1(ptr)
33         {
34         }
35     protected:
36         plural_ptr op1;
37     };
38 
39 
40     struct binary : public plural
41     {
binaryboost::locale::gnu_gettext::lambda::__anon338418d40111::binary42         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     {
numberboost::locale::gnu_gettext::lambda::__anon338418d40111::number53         number(int v) :
54             val(v)
55         {
56         }
operator ()boost::locale::gnu_gettext::lambda::__anon338418d40111::number57         virtual int operator()(int /*n*/) const
58         {
59             return val;
60         }
cloneboost::locale::gnu_gettext::lambda::__anon338418d40111::number61         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 {
conditionalboost::locale::gnu_gettext::lambda::__anon338418d40111::conditional171         conditional(plural_ptr p1,plural_ptr p2,plural_ptr p3) :
172              op1(p1),
173              op2(p2),
174              op3(p3)
175         {
176         }
operator ()boost::locale::gnu_gettext::lambda::__anon338418d40111::conditional177         virtual int operator()(int n) const
178         {
179             return (*op1)(n) ? (*op2)(n) : (*op3)(n);
180         }
cloneboost::locale::gnu_gettext::lambda::__anon338418d40111::conditional181         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 
bin_factory(int value,plural_ptr left,plural_ptr right)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 
un_factory(int value,plural_ptr op)220     plural_ptr un_factory(int value,plural_ptr op)
221     {
222         switch(value) {
223         case '!': return plural_ptr(new l_not(op));
224         case '~': return plural_ptr(new bin_not(op));
225         case '-': return plural_ptr(new minus(op));
226         default:
227             return plural_ptr();
228         }
229     }
230 
is_in(int v,int * p)231     static inline bool is_in(int v,int *p)
232     {
233         int len=*p;
234         p++;
235         while(len && *p!=v) { p++;len--; }
236         return len!=0;
237     }
238 
239 
240     class tokenizer {
241     public:
tokenizer(char const * s)242         tokenizer(char const *s) { text=s; pos=0; step(); };
get(int * val=NULL)243         int get(int *val=NULL){
244             int iv=int_value;
245             int res=next_tocken;
246             step();
247             if(val && res==NUM){
248                 *val=iv;
249             }
250             return res;
251         };
next(int * val=NULL)252         int next(int *val=NULL) {
253             if(val && next_tocken==NUM) {
254                 *val=int_value;
255                 return NUM;
256             }
257             return next_tocken;
258         }
259     private:
260         char const *text;
261         int pos;
262         int next_tocken;
263         int int_value;
is_blank(char c)264         bool is_blank(char c)
265         {
266             return c==' ' || c=='\r' || c=='\n' || c=='\t';
267         }
isdigit(char c)268         bool isdigit(char c)
269         {
270             return '0'<=c && c<='9';
271         }
step()272         void step()
273         {
274             while(text[pos] && is_blank(text[pos])) pos++;
275             char const *ptr=text+pos;
276             char *tmp_ptr;
277             if(strncmp(ptr,"<<",2)==0) { pos+=2; next_tocken=SHL; }
278             else if(strncmp(ptr,">>",2)==0) { pos+=2; next_tocken=SHR; }
279             else if(strncmp(ptr,"&&",2)==0) { pos+=2; next_tocken=AND; }
280             else if(strncmp(ptr,"||",2)==0) { pos+=2; next_tocken=OR; }
281             else if(strncmp(ptr,"<=",2)==0) { pos+=2; next_tocken=LTE; }
282             else if(strncmp(ptr,">=",2)==0) { pos+=2; next_tocken=GTE; }
283             else if(strncmp(ptr,"==",2)==0) { pos+=2; next_tocken=EQ; }
284             else if(strncmp(ptr,"!=",2)==0) { pos+=2; next_tocken=NEQ; }
285             else if(*ptr=='n') { pos++; next_tocken=VARIABLE; }
286             else if(isdigit(*ptr)) { int_value=strtol(text+pos,&tmp_ptr,0); pos=tmp_ptr-text; next_tocken=NUM; }
287             else if(*ptr=='\0') { next_tocken=0; }
288             else { next_tocken=*ptr; pos++; }
289         }
290     };
291 
292 
293     #define BINARY_EXPR(expr,hexpr,list)                            \
294         plural_ptr expr()                                           \
295         {                                                           \
296             plural_ptr op1,op2;                                     \
297             if((op1=hexpr()).get()==0)                              \
298                 return plural_ptr();                                \
299             while(is_in(t.next(),list)) {                           \
300                 int o=t.get();                                      \
301                 if((op2=hexpr()).get()==0)                          \
302                     return plural_ptr();                            \
303                 op1=bin_factory(o,op1,op2);                         \
304             }                                                       \
305             return op1;                                             \
306         }
307 
308     class parser {
309     public:
310 
parser(tokenizer & tin)311         parser(tokenizer &tin) : t(tin) {};
312 
compile()313         plural_ptr compile()
314         {
315             plural_ptr res=cond_expr();
316             if(res.get() && t.next()!=END) {
317                 return plural_ptr();
318             };
319             return res;
320         }
321 
322     private:
323 
value_expr()324         plural_ptr value_expr()
325         {
326             plural_ptr op;
327             if(t.next()=='(') {
328                 t.get();
329                 if((op=cond_expr()).get()==0)
330                     return plural_ptr();
331                 if(t.get()!=')')
332                     return plural_ptr();
333                 return op;
334             }
335             else if(t.next()==NUM) {
336                 int value;
337                 t.get(&value);
338                 return plural_ptr(new number(value));
339             }
340             else if(t.next()==VARIABLE) {
341                 t.get();
342                 return plural_ptr(new identity());
343             }
344             return plural_ptr();
345         };
346 
un_expr()347         plural_ptr un_expr()
348         {
349             plural_ptr op1;
350             static int level_unary[]={3,'-','!','~'};
351             if(is_in(t.next(),level_unary)) {
352                 int op=t.get();
353                 if((op1=un_expr()).get()==0)
354                     return plural_ptr();
355                 switch(op) {
356                 case '-':
357                     return plural_ptr(new minus(op1));
358                 case '!':
359                     return plural_ptr(new l_not(op1));
360                 case '~':
361                     return plural_ptr(new bin_not(op1));
362                 default:
363                     return plural_ptr();
364                 }
365             }
366             else {
367                 return value_expr();
368             }
369         };
370 
371         BINARY_EXPR(l10,un_expr,level10);
372         BINARY_EXPR(l9,l10,level9);
373         BINARY_EXPR(l8,l9,level8);
374         BINARY_EXPR(l7,l8,level7);
375         BINARY_EXPR(l6,l7,level6);
376         BINARY_EXPR(l5,l6,level5);
377         BINARY_EXPR(l4,l5,level4);
378         BINARY_EXPR(l3,l4,level3);
379         BINARY_EXPR(l2,l3,level2);
380         BINARY_EXPR(l1,l2,level1);
381 
cond_expr()382         plural_ptr cond_expr()
383         {
384             plural_ptr cond,case1,case2;
385             if((cond=l1()).get()==0)
386                 return plural_ptr();
387             if(t.next()=='?') {
388                 t.get();
389                 if((case1=cond_expr()).get()==0)
390                     return plural_ptr();
391                 if(t.get()!=':')
392                     return plural_ptr();
393                 if((case2=cond_expr()).get()==0)
394                     return plural_ptr();
395             }
396             else {
397                 return cond;
398             }
399             return plural_ptr(new conditional(cond,case1,case2));
400         }
401 
402         tokenizer &t;
403 
404     };
405 
406 } // namespace anon
407 
compile(char const * str)408 plural_ptr compile(char const *str)
409 {
410     tokenizer t(str);
411     parser p(t);
412     return p.compile();
413 }
414 
415 
416 } // lambda
417 } // gnu_gettext
418 } // locale
419 } // boost
420 
421 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
422 
423