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