1 // Copyright (C) 2000-2007, Luca Padovani <padovani@sti.uniurb.it>.
2 //
3 // This file is part of GtkMathView, a flexible, high-quality rendering
4 // engine for MathML documents.
5 //
6 // GtkMathView is free software; you can redistribute it and/or modify it
7 // under the terms of the GNU Lesser General Public License as published
8 // by the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // GtkMathView is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public License
17 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 
19 #ifndef __TemplateStringScanners_hh__
20 #define __TemplateStringScanners_hh__
21 
22 #include "RGBColor.hh"
23 #include "String.hh"
24 
25 class Scan
26 {
27 public:
28   static UCS4String::value_type
toChar(const UCS4String::const_iterator & begin,const UCS4String::const_iterator &)29   toChar(const UCS4String::const_iterator& begin, const UCS4String::const_iterator&)
30   {
31     return *begin;
32   }
33 
34   static String
toString(const UCS4String::const_iterator & begin,const UCS4String::const_iterator & end)35   toString(const UCS4String::const_iterator& begin, const UCS4String::const_iterator& end)
36   {
37     return StringOfUCS4String(UCS4String(begin, end));
38   }
39 };
40 
41 // ScanAny: any character
42 
43 class ScanAny : public Scan
44 {
45 public:
46   static inline bool
scan(const UCS4String::const_iterator & begin,const UCS4String::const_iterator & end,UCS4String::const_iterator & next)47   scan(const UCS4String::const_iterator& begin, const UCS4String::const_iterator& end, UCS4String::const_iterator& next)
48   {
49     if (begin != end)
50       {
51 	next = begin + 1;
52 	return true;
53       }
54     else
55       return false;
56   }
57 
58   static inline Char
parse(const UCS4String::const_iterator & begin,const UCS4String::const_iterator &)59   parse(const UCS4String::const_iterator& begin, const UCS4String::const_iterator&)
60   {
61     return *begin;
62   }
63 };
64 
65 // ScanSpace: an XML space
66 
67 class ScanSpace : public Scan
68 {
69 public:
70   static inline bool
scan(const UCS4String::const_iterator & begin,const UCS4String::const_iterator & end,UCS4String::const_iterator & next)71   scan(const UCS4String::const_iterator& begin, const UCS4String::const_iterator& end, UCS4String::const_iterator& next)
72   {
73     if (begin != end && isXmlSpace(*begin))
74       {
75 	next = begin + 1;
76 	return true;
77       }
78     else
79       return false;
80   }
81 };
82 
83 // ScanLiteral: character
84 
85 template <UCS4String::value_type c>
86 class ScanLiteral : public Scan
87 {
88 public:
89   static inline bool
scan(const UCS4String::const_iterator & begin,const UCS4String::const_iterator & end,UCS4String::const_iterator & next)90   scan(const UCS4String::const_iterator& begin, const UCS4String::const_iterator& end, UCS4String::const_iterator& next)
91   {
92     if (begin != end && *begin == c)
93       {
94 	next = begin + 1;
95 	return true;
96       }
97     else
98       return false;
99   }
100 };
101 
102 // ScanRange: range of characters
103 
104 template <UCS4String::value_type first, UCS4String::value_type last>
105 class ScanRange : public Scan
106 {
107 public:
108   static inline bool
scan(const UCS4String::const_iterator & begin,const UCS4String::const_iterator & end,UCS4String::const_iterator & next)109   scan(const UCS4String::const_iterator& begin, const UCS4String::const_iterator& end, UCS4String::const_iterator& next)
110   {
111     if (begin != end && *begin >= first && *begin <= last)
112       {
113 	next = begin + 1;
114 	return true;
115       }
116     else
117       return false;
118   }
119 };
120 
121 // ScanSeq: sequence of expressions
122 
123 template <typename E1, typename E2>
124 class ScanSeq : public Scan
125 {
126 public:
127   static inline bool
scan(const UCS4String::const_iterator & begin,const UCS4String::const_iterator & end,UCS4String::const_iterator & next)128   scan(const UCS4String::const_iterator& begin, const UCS4String::const_iterator& end, UCS4String::const_iterator& next)
129   {
130     UCS4String::const_iterator p;
131     if (E1::scan(begin, end, p))
132       return E2::scan(p, end, next);
133     else
134       return false;
135   }
136 };
137 
138 // ScanRep: repetition of expression
139 
140 template <unsigned n0, typename E>
141 class ScanRep : public Scan
142 {
143 public:
144   static inline bool
scan(const UCS4String::const_iterator & begin,const UCS4String::const_iterator & end,UCS4String::const_iterator & next)145   scan(const UCS4String::const_iterator& begin, const UCS4String::const_iterator& end, UCS4String::const_iterator& next)
146   {
147     UCS4String::const_iterator p = begin;
148     unsigned n;
149     for (n = 0; n < n0 && E::scan(p, end, next); n++)
150       p = next;
151     return n == n0;
152   }
153 };
154 
155 // ScanChoice: alternative expressions
156 
157 template <typename E1, typename E2>
158 class ScanChoice : public Scan
159 {
160 public:
161   static inline bool
scan(const UCS4String::const_iterator & begin,const UCS4String::const_iterator & end,UCS4String::const_iterator & next)162   scan(const UCS4String::const_iterator& begin, const UCS4String::const_iterator& end, UCS4String::const_iterator& next)
163   {
164     if (E1::scan(begin, end, next))
165       {
166 	UCS4String::const_iterator next2;
167 	if (E2::scan(begin, end, next2))
168 	  next = std::max(next, next2);
169 	return true;
170       }
171 
172     return E2::scan(begin, end, next);
173   }
174 };
175 
176 // ScanOption: optional expression
177 
178 template <typename E>
179 class ScanZeroOrOne : public Scan
180 {
181 public:
182   static inline bool
scan(const UCS4String::const_iterator & begin,const UCS4String::const_iterator & end,UCS4String::const_iterator & next)183   scan(const UCS4String::const_iterator& begin, const UCS4String::const_iterator& end, UCS4String::const_iterator& next)
184   {
185     if (E::scan(begin, end, next))
186       return true;
187     else
188       {
189 	next = begin;
190 	return true;
191       }
192   }
193 };
194 
195 // ScanOneOrMore: one or more
196 
197 template <typename E>
198 class ScanOneOrMore : public Scan
199 {
200 public:
201   static inline bool
scan(const UCS4String::const_iterator & begin,const UCS4String::const_iterator & end,UCS4String::const_iterator & next)202   scan(const UCS4String::const_iterator& begin, const UCS4String::const_iterator& end, UCS4String::const_iterator& next)
203   {
204     UCS4String::const_iterator p = begin;
205     while (E::scan(p, end, next))
206       p = next;
207 
208     if (p != begin)
209       {
210 	next = p;
211 	return true;
212       }
213     else
214       return false;
215   }
216 };
217 
218 // ScanZeroOrMore
219 
220 template <typename E>
221 class ScanZeroOrMore : public ScanZeroOrOne< ScanOneOrMore<E> >
222 { };
223 
224 // ScanSpaces: zero or more XML spaces
225 
226 typedef ScanZeroOrMore<ScanSpace> ScanSpaces;
227 
228 // Some more specialized scanners
229 
230 typedef ScanLiteral<'-'> ScanMinus;
231 typedef ScanLiteral<'+'> ScanPlus;
232 typedef ScanLiteral<'%'> ScanPercentage;
233 typedef ScanLiteral<'{'> ScanLeftBrace;
234 typedef ScanLiteral<'}'> ScanRightBrace;
235 typedef ScanChoice<ScanLeftBrace,ScanRightBrace> ScanBrace;
236 typedef ScanChoice<ScanPlus,ScanMinus> ScanPlusOrMinus;
237 typedef ScanChoice<ScanPlusOrMinus,ScanChoice<ScanBrace,ScanPercentage> > ScanSpecialToken;
238 typedef ScanRange<'0','9'> ScanDecDigit;
239 typedef ScanZeroOrOne<ScanMinus> ScanOptionalMinus;
240 typedef ScanChoice< ScanRange<'a','z'>,ScanRange<'A','Z'> > ScanLetter;
241 typedef ScanChoice<ScanLetter,ScanMinus> ScanLetterOrMinus;
242 typedef ScanSeq<ScanLetter,ScanZeroOrMore<ScanLetterOrMinus> > ScanKeywordToken;
243 typedef ScanChoice<ScanDecDigit,ScanChoice<ScanRange<'a','f'>,ScanRange<'A','F'> > > ScanHexDigit;
244 typedef ScanRep<3,ScanHexDigit> ScanRGB4Color;
245 typedef ScanRep<4,ScanHexDigit> ScanRGB4AColor;
246 typedef ScanRep<6,ScanHexDigit> ScanRGB8Color;
247 typedef ScanRep<8,ScanHexDigit> ScanRGB8AColor;
248 typedef ScanSeq<ScanLiteral<'#'>,ScanChoice<ScanRGB8AColor,ScanChoice<ScanRGB8Color,ScanChoice<ScanRGB4AColor,ScanRGB4Color> > > > ScanRGBColorValue;
249 
250 class ScanSign : public ScanZeroOrOne<ScanPlusOrMinus>
251 {
252 public:
253   static int
parse(const UCS4String::const_iterator & begin,const UCS4String::const_iterator & end)254   parse(const UCS4String::const_iterator& begin, const UCS4String::const_iterator& end)
255   {
256     if (begin != end)
257       return (*begin == '+') ? 1 : -1;
258     else
259       return 0;
260   }
261 };
262 
263 class ScanUnsignedInteger : public ScanOneOrMore<ScanDecDigit>
264 {
265 public:
266   static int
parse(const UCS4String::const_iterator & begin,const UCS4String::const_iterator & end)267   parse(const UCS4String::const_iterator& begin, const UCS4String::const_iterator& end)
268   {
269     int v = 0;
270     for (UCS4String::const_iterator p = begin; p != end; p++)
271       v = v * 10 + *p - '0';
272     return v;
273   }
274 };
275 
276 class ScanInteger : public ScanSeq<ScanOptionalMinus,ScanUnsignedInteger>
277 {
278 public:
279   static int
parse(const UCS4String::const_iterator & begin,const UCS4String::const_iterator & end)280   parse(const UCS4String::const_iterator& begin, const UCS4String::const_iterator& end)
281   {
282     if (*begin == '-')
283       return -ScanUnsignedInteger::parse(begin + 1, end);
284     else
285       return ScanUnsignedInteger::parse(begin, end);
286   }
287 };
288 
289 class ScanToken : public ScanChoice<ScanKeywordToken,ScanSpecialToken>
290 {
291 public:
292   static TokenId
parse(const UCS4String::const_iterator & begin,const UCS4String::const_iterator & end)293   parse(const UCS4String::const_iterator& begin, const UCS4String::const_iterator& end)
294   {
295     return tokenIdOfString(Scan::toString(begin, end));
296   }
297 };
298 
299 class ScanRGBColor : public ScanRGBColorValue
300 {
301 private:
302   static unsigned
hexOfChar(UCS4String::value_type ch)303   hexOfChar(UCS4String::value_type ch)
304   {
305     if (ch >= '0' && ch <= '9') return ch - '0';
306     else if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10;
307     else return ch - 'a' + 10;
308   }
309 
310 public:
311   static RGBColor
parse(const UCS4String::const_iterator & begin,const UCS4String::const_iterator & end)312   parse(const UCS4String::const_iterator& begin, const UCS4String::const_iterator& end)
313   {
314     switch (end - begin)
315       {
316       case 4:
317 	return RGBColor(17 * hexOfChar(*(begin + 1)),
318 			17 * hexOfChar(*(begin + 2)),
319 			17 * hexOfChar(*(begin + 3)));
320       case 5:
321 	return RGBColor(17 * hexOfChar(*(begin + 1)),
322 			17 * hexOfChar(*(begin + 2)),
323 			17 * hexOfChar(*(begin + 3)),
324 			17 * hexOfChar(*(begin + 4)));
325       case 7:
326 	return RGBColor(16 * hexOfChar(*(begin + 1)) + hexOfChar(*(begin + 2)),
327 			16 * hexOfChar(*(begin + 3)) + hexOfChar(*(begin + 4)),
328 			16 * hexOfChar(*(begin + 5)) + hexOfChar(*(begin + 6)));
329       case 9:
330 	return RGBColor(16 * hexOfChar(*(begin + 1)) + hexOfChar(*(begin + 2)),
331 			16 * hexOfChar(*(begin + 3)) + hexOfChar(*(begin + 4)),
332 			16 * hexOfChar(*(begin + 5)) + hexOfChar(*(begin + 6)),
333 			16 * hexOfChar(*(begin + 7)) + hexOfChar(*(begin + 8)));
334       default:
335 	assert(false);
336       }
337   }
338 };
339 
340 typedef ScanSeq<ScanLiteral<'.'>,ScanUnsignedInteger> ScanDecimalPart;
341 
342 class ScanUnsignedNumber : public ScanChoice<ScanSeq<ScanUnsignedInteger,ScanDecimalPart>,
343 			   ScanChoice<ScanDecimalPart,ScanUnsignedInteger> >
344 {
345 public:
346   static float
parse(const UCS4String::const_iterator & begin,const UCS4String::const_iterator & end)347   parse(const UCS4String::const_iterator& begin, const UCS4String::const_iterator& end)
348   {
349     bool decimal = false; // true if decimal point found
350     unsigned n = 0;       // number of digits after decimal point
351 
352     float v = float();
353     UCS4String::const_iterator p = begin;
354     while (p != end)
355       {
356 	if (*p == '.')
357 	  decimal = true;
358 	else
359 	  {
360 	    v = v * 10 + *p - '0';
361 	    if (decimal) n++;
362 	  }
363 	p++;
364       }
365 
366     while (n-- > 0) v /= 10;
367 
368     return v;
369   }
370 };
371 
372 class ScanNumber : public ScanSeq<ScanOptionalMinus,ScanUnsignedNumber>
373 {
374 public:
375   static float
parse(const UCS4String::const_iterator & begin,const UCS4String::const_iterator & end)376   parse(const UCS4String::const_iterator& begin, const UCS4String::const_iterator& end)
377   {
378     if (*begin == '-')
379       return -ScanUnsignedNumber::parse(begin + 1, end);
380     else
381       return ScanUnsignedNumber::parse(begin, end);
382   }
383 };
384 
385 #endif // __TemplateStringScanners_hh__
386