|
- //
- // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
- //
- // Distributed under the Boost Software License, Version 1.0. (See
- // accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- //
- #include "mo_lambda.h"
- #include <string.h>
- #include <stdlib.h>
-
- namespace booster {
- namespace locale {
- namespace gnu_gettext {
- namespace lambda {
-
- namespace { // anon
- struct identity : public plural {
- virtual int operator()(int n) const
- {
- return n;
- };
- virtual identity *clone() const
- {
- return new identity();
- }
- };
-
- struct unary : public plural
- {
- unary(plural_ptr ptr) :
- op1(ptr)
- {
- }
- protected:
- plural_ptr op1;
- };
-
-
- struct binary : public plural
- {
- binary(plural_ptr p1,plural_ptr p2) :
- op1(p1),
- op2(p2)
- {
- }
- protected:
- plural_ptr op1,op2;
- };
-
- struct number : public plural
- {
- number(int v) :
- val(v)
- {
- }
- virtual int operator()(int /*n*/) const
- {
- return val;
- }
- virtual number *clone() const
- {
- return new number(val);
- }
-
- private:
- int val;
- };
-
- #define UNOP(name,oper) \
- struct name: public unary { \
- name(plural_ptr op) : unary(op) \
- { \
- }; \
- virtual int operator()(int n) const \
- { \
- return oper (*op1)(n); \
- } \
- virtual name *clone() const \
- { \
- plural_ptr op1_copy(op1->clone()); \
- return new name(op1_copy); \
- } \
- };
-
- #define BINOP(name,oper) \
- struct name : public binary \
- { \
- name(plural_ptr p1,plural_ptr p2) : \
- binary(p1,p2) \
- { \
- } \
- \
- virtual int operator()(int n) const \
- { \
- return (*op1)(n) oper (*op2)(n); \
- } \
- virtual name *clone() const \
- { \
- plural_ptr op1_copy(op1->clone()); \
- plural_ptr op2_copy(op2->clone()); \
- return new name(op1_copy,op2_copy); \
- } \
- };
-
- #define BINOPD(name,oper) \
- struct name : public binary { \
- name(plural_ptr p1,plural_ptr p2) : \
- binary(p1,p2) \
- { \
- } \
- virtual int operator()(int n) const \
- { \
- int v1=(*op1)(n); \
- int v2=(*op2)(n); \
- return v2==0 ? 0 : v1 oper v2; \
- } \
- virtual name *clone() const \
- { \
- plural_ptr op1_copy(op1->clone()); \
- plural_ptr op2_copy(op2->clone()); \
- return new name(op1_copy,op2_copy); \
- } \
- };
-
- enum { END = 0 , SHL = 256, SHR, GTE,LTE, EQ, NEQ, AND, OR, NUM, VARIABLE };
-
- UNOP(l_not,!)
- UNOP(minus,-)
- UNOP(bin_not,~)
-
- BINOP(mul,*)
- BINOPD(div,/)
- BINOPD(mod,%)
- static int level10[]={3,'*','/','%'};
-
- BINOP(add,+)
- BINOP(sub,-)
- static int level9[]={2,'+','-'};
-
- BINOP(shl,<<)
- BINOP(shr,>>)
- static int level8[]={2,SHL,SHR};
-
- BINOP(gt,>)
- BINOP(lt,<)
- BINOP(gte,>=)
- BINOP(lte,<=)
- static int level7[]={4,'<','>',GTE,LTE};
-
- BINOP(eq,==)
- BINOP(neq,!=)
- static int level6[]={2,EQ,NEQ};
-
- BINOP(bin_and,&)
- static int level5[]={1,'&'};
-
- BINOP(bin_xor,^)
- static int level4[]={1,'^'};
-
- BINOP(bin_or,|)
- static int level3[]={1,'|'};
-
- BINOP(l_and,&&)
- static int level2[]={1,AND};
-
- BINOP(l_or,||)
- static int level1[]={1,OR};
-
- struct conditional : public plural {
- conditional(plural_ptr p1,plural_ptr p2,plural_ptr p3) :
- op1(p1),
- op2(p2),
- op3(p3)
- {
- }
- virtual int operator()(int n) const
- {
- return (*op1)(n) ? (*op2)(n) : (*op3)(n);
- }
- virtual conditional *clone() const
- {
- plural_ptr op1_copy(op1->clone());
- plural_ptr op2_copy(op2->clone());
- plural_ptr op3_copy(op3->clone());
- return new conditional(op1_copy,op2_copy,op3_copy);
- }
- private:
- plural_ptr op1,op2,op3;
- };
-
-
- plural_ptr bin_factory(int value,plural_ptr left,plural_ptr right)
- {
-
- switch(value) {
- case '/': return plural_ptr(new div(left,right));
- case '*': return plural_ptr(new mul(left,right));
- case '%': return plural_ptr(new mod(left,right));
- case '+': return plural_ptr(new add(left,right));
- case '-': return plural_ptr(new sub(left,right));
- case SHL: return plural_ptr(new shl(left,right));
- case SHR: return plural_ptr(new shr(left,right));
- case '>': return plural_ptr(new gt(left,right));
- case '<': return plural_ptr(new lt(left,right));
- case GTE: return plural_ptr(new gte(left,right));
- case LTE: return plural_ptr(new lte(left,right));
- case EQ: return plural_ptr(new eq(left,right));
- case NEQ: return plural_ptr(new neq(left,right));
- case '&': return plural_ptr(new bin_and(left,right));
- case '^': return plural_ptr(new bin_xor(left,right));
- case '|': return plural_ptr(new bin_or (left,right));
- case AND: return plural_ptr(new l_and(left,right));
- case OR: return plural_ptr(new l_or(left,right));
- default:
- return plural_ptr();
- }
- }
-
- static inline bool is_in(int v,int *p)
- {
- int len=*p;
- p++;
- while(len && *p!=v) { p++;len--; }
- return len!=0;
- }
-
-
- class tokenizer {
- public:
- tokenizer(char const *s) { text=s; pos=0; step(); };
- int get(int *val=NULL){
- int iv=int_value;
- int res=next_tocken;
- step();
- if(val && res==NUM){
- *val=iv;
- }
- return res;
- };
- int next(int *val=NULL) {
- if(val && next_tocken==NUM) {
- *val=int_value;
- return NUM;
- }
- return next_tocken;
- }
- private:
- char const *text;
- int pos;
- int next_tocken;
- int int_value;
- bool is_blank(char c)
- {
- return c==' ' || c=='\r' || c=='\n' || c=='\t';
- }
- bool isdigit(char c)
- {
- return '0'<=c && c<='9';
- }
- void step()
- {
- while(text[pos] && is_blank(text[pos])) pos++;
- char const *ptr=text+pos;
- char *tmp_ptr;
- if(strncmp(ptr,"<<",2)==0) { pos+=2; next_tocken=SHL; }
- else if(strncmp(ptr,">>",2)==0) { pos+=2; next_tocken=SHR; }
- else if(strncmp(ptr,"&&",2)==0) { pos+=2; next_tocken=AND; }
- else if(strncmp(ptr,"||",2)==0) { pos+=2; next_tocken=OR; }
- else if(strncmp(ptr,"<=",2)==0) { pos+=2; next_tocken=LTE; }
- else if(strncmp(ptr,">=",2)==0) { pos+=2; next_tocken=GTE; }
- else if(strncmp(ptr,"==",2)==0) { pos+=2; next_tocken=EQ; }
- else if(strncmp(ptr,"!=",2)==0) { pos+=2; next_tocken=NEQ; }
- else if(*ptr=='n') { pos++; next_tocken=VARIABLE; }
- else if(isdigit(*ptr)) { int_value=strtol(text+pos,&tmp_ptr,0); pos=tmp_ptr-text; next_tocken=NUM; }
- else if(*ptr=='\0') { next_tocken=0; }
- else { next_tocken=*ptr; pos++; }
- }
- };
-
-
- #define BINARY_EXPR(expr,hexpr,list) \
- plural_ptr expr() \
- { \
- plural_ptr op1,op2; \
- if((op1=hexpr()).get()==0) \
- return plural_ptr(); \
- while(is_in(t.next(),list)) { \
- int o=t.get(); \
- if((op2=hexpr()).get()==0) \
- return plural_ptr(); \
- op1=bin_factory(o,op1,op2); \
- } \
- return op1; \
- }
-
- class parser {
- public:
-
- parser(tokenizer &tin) : t(tin) {};
-
- plural_ptr compile()
- {
- plural_ptr res=cond_expr();
- if(res.get() && t.next()!=END) {
- return plural_ptr();
- };
- return res;
- }
-
- private:
-
- plural_ptr value_expr()
- {
- plural_ptr op;
- if(t.next()=='(') {
- t.get();
- if((op=cond_expr()).get()==0)
- return plural_ptr();
- if(t.get()!=')')
- return plural_ptr();
- return op;
- }
- else if(t.next()==NUM) {
- int value;
- t.get(&value);
- return plural_ptr(new number(value));
- }
- else if(t.next()==VARIABLE) {
- t.get();
- return plural_ptr(new identity());
- }
- return plural_ptr();
- };
-
- plural_ptr un_expr()
- {
- plural_ptr op1;
- static int level_unary[]={3,'-','!','~'};
- if(is_in(t.next(),level_unary)) {
- int op=t.get();
- if((op1=un_expr()).get()==0)
- return plural_ptr();
- switch(op) {
- case '-':
- return plural_ptr(new minus(op1));
- case '!':
- return plural_ptr(new l_not(op1));
- case '~':
- return plural_ptr(new bin_not(op1));
- default:
- return plural_ptr();
- }
- }
- else {
- return value_expr();
- }
- };
-
- BINARY_EXPR(l10,un_expr,level10);
- BINARY_EXPR(l9,l10,level9);
- BINARY_EXPR(l8,l9,level8);
- BINARY_EXPR(l7,l8,level7);
- BINARY_EXPR(l6,l7,level6);
- BINARY_EXPR(l5,l6,level5);
- BINARY_EXPR(l4,l5,level4);
- BINARY_EXPR(l3,l4,level3);
- BINARY_EXPR(l2,l3,level2);
- BINARY_EXPR(l1,l2,level1);
-
- plural_ptr cond_expr()
- {
- plural_ptr cond,case1,case2;
- if((cond=l1()).get()==0)
- return plural_ptr();
- if(t.next()=='?') {
- t.get();
- if((case1=cond_expr()).get()==0)
- return plural_ptr();
- if(t.get()!=':')
- return plural_ptr();
- if((case2=cond_expr()).get()==0)
- return plural_ptr();
- }
- else {
- return cond;
- }
- return plural_ptr(new conditional(cond,case1,case2));
- }
-
- tokenizer &t;
-
- };
-
- } // namespace anon
-
- plural_ptr compile(char const *str)
- {
- tokenizer t(str);
- parser p(t);
- return p.compile();
- }
-
-
- } // lambda
- } // gnu_gettext
- } // locale
- } // boost
-
- // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|