ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

412 lines
12 KiB

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