PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/ILCalc/Parser/LiteralParser.cs

#
C# | 396 lines | 313 code | 72 blank | 11 comment | 79 complexity | 44feb7fab469060ef18c9c7a4ea1d1c8 MD5 | raw file
Possible License(s): LGPL-2.1
  1. using System;
  2. using System.Globalization;
  3. using ILCalc.Custom;
  4. namespace ILCalc
  5. {
  6. static class LiteralParser
  7. {
  8. #region Resolve
  9. static readonly SupportCollection<object> Support;
  10. static LiteralParser()
  11. {
  12. Support = new SupportCollection<object>();
  13. var realParser = new RealLiteralParser();
  14. Support.Add<Double>(realParser);
  15. Support.Add<Single>(realParser);
  16. Support.Add<Decimal>(realParser);
  17. var integralParser = new IntegralLiteralParser();
  18. Support.Add<Int32>(integralParser);
  19. Support.Add<Int64>(integralParser);
  20. }
  21. public static ILiteralParser<T> Resolve<T>()
  22. {
  23. var parser = Support.Find<T>();
  24. if (parser == null)
  25. return new UnknownLiteralParser<T>();
  26. return (ILiteralParser<T>) parser;
  27. }
  28. public static bool IsUnknown<T>(ILiteralParser<T> parser)
  29. {
  30. return parser is UnknownLiteralParser<T>;
  31. }
  32. #endregion
  33. #region Parsers
  34. sealed class RealLiteralParser
  35. : ILiteralParser<Double>,
  36. ILiteralParser<Single>,
  37. ILiteralParser<Decimal>
  38. {
  39. #region ILiterlParser
  40. public int TryParse(int i, IParserSupport<float> p)
  41. {
  42. string expr = p.Expression;
  43. if ((expr[i] < '0' || expr[i] > '9')
  44. && expr[i] != p.DecimalDot) return -1;
  45. return Parse(i, p, Single.Parse);
  46. }
  47. public int TryParse(int i, IParserSupport<double> p)
  48. {
  49. string expr = p.Expression;
  50. if ((expr[i] < '0' || expr[i] > '9')
  51. && expr[i] != p.DecimalDot) return -1;
  52. return Parse(i, p, Double.Parse);
  53. }
  54. public int TryParse(int i, IParserSupport<decimal> p)
  55. {
  56. string expr = p.Expression;
  57. if ((expr[i] < '0' || expr[i] > '9')
  58. && expr[i] != p.DecimalDot) return -1;
  59. return Parse(i, p, Decimal.Parse);
  60. }
  61. #endregion
  62. #region CommonPart
  63. static int Parse<T>(int i, IParserSupport<T> p, Parser<T> parser)
  64. {
  65. var str = ScanNumber(i, p);
  66. if (str == null) return -1;
  67. bool neg = p.DiscardNegate();
  68. try
  69. {
  70. if (neg)
  71. {
  72. p.ParsedValue = parser(
  73. p.NumberFormat.NegativeSign + str,
  74. NumberStyles.AllowLeadingSign |
  75. NumberStyles.AllowDecimalPoint |
  76. NumberStyles.AllowExponent,
  77. p.NumberFormat);
  78. }
  79. else
  80. {
  81. p.ParsedValue = parser(str,
  82. NumberStyles.AllowDecimalPoint |
  83. NumberStyles.AllowExponent,
  84. p.NumberFormat);
  85. }
  86. return str.Length;
  87. }
  88. catch (FormatException e)
  89. {
  90. throw p.InvalidNumberFormat(
  91. Resource.errNumberFormat, str, e);
  92. }
  93. catch (OverflowException e)
  94. {
  95. throw p.InvalidNumberFormat(
  96. Resource.errNumberOverflow, str, e);
  97. }
  98. }
  99. static string ScanNumber<T>(int i, IParserSupport<T> p)
  100. {
  101. string expr = p.Expression;
  102. // Fractal part: ==========================
  103. // numbers not like ".123":
  104. if (expr[i] != p.DecimalDot)
  105. {
  106. // skip digits and decimal point:
  107. for (; i < expr.Length; i++)
  108. {
  109. if (expr[i] >= '0' && expr[i] <= '9') continue;
  110. if (expr[i] == p.DecimalDot) i++;
  111. break;
  112. }
  113. }
  114. else
  115. {
  116. if (!IsDigit(expr, ++i)) return null;
  117. }
  118. // skip digits:
  119. while (IsDigit(expr, i)) i++;
  120. // Exponental part: =======================
  121. // at least 2 chars:
  122. if (i+1 < expr.Length)
  123. {
  124. // E character:
  125. char c = expr[i];
  126. if (c == 'e' || c == 'E')
  127. {
  128. int j = i;
  129. // exponetal sign:
  130. c = expr[++j];
  131. if (c == '-' || c == '+') j++;
  132. // exponental value:
  133. if (IsDigit(expr, j++))
  134. {
  135. while (IsDigit(expr, j)) j++;
  136. i = j;
  137. }
  138. }
  139. }
  140. return expr.Substring(p.BeginPos, i - p.BeginPos);
  141. }
  142. #endregion
  143. }
  144. sealed class IntegralLiteralParser
  145. : ILiteralParser<Int32>,
  146. ILiteralParser<Int64>
  147. {
  148. #region ILiteralParser
  149. public int TryParse(int i, IParserSupport<int> p)
  150. {
  151. string expr = p.Expression;
  152. if (expr[i] < '0' || expr[i] > '9') return -1;
  153. return Parse(i, p, Int32.Parse, ScanInt32Hex, ScanInt32Bin);
  154. }
  155. public int TryParse(int i, IParserSupport<long> p)
  156. {
  157. string expr = p.Expression;
  158. if (expr[i] < '0' || expr[i] > '9') return -1;
  159. return Parse(i, p, Int64.Parse, ScanInt64Hex, ScanInt64Bin);
  160. }
  161. #endregion
  162. #region CommonPart
  163. static int Parse<T>(
  164. int i, IParserSupport<T> p, Parser<T> parser,
  165. HexBinScan<T> hex, HexBinScan<T> bin)
  166. {
  167. string expr = p.Expression;
  168. if (expr[i] < '0' || expr[i] > '9') return -1;
  169. // hex/bin literal support:
  170. if (expr[i] == '0' && i+1 < expr.Length)
  171. {
  172. i++;
  173. char c = expr[i++];
  174. if (c == 'x' || c == 'X') return hex(i, p);
  175. if (c == 'b' || c == 'B') return bin(i, p);
  176. p.ParsedValue = default(T);
  177. return 1;
  178. }
  179. // skip digits and parse:
  180. while (IsDigit(expr, i)) i++;
  181. string str = Substring(i, p);
  182. bool neg = p.DiscardNegate();
  183. try
  184. {
  185. if (neg)
  186. {
  187. p.ParsedValue = parser(
  188. p.NumberFormat.NegativeSign + str,
  189. NumberStyles.AllowLeadingSign |
  190. NumberStyles.AllowDecimalPoint |
  191. NumberStyles.AllowExponent,
  192. p.NumberFormat);
  193. }
  194. else
  195. {
  196. p.ParsedValue = parser(str,
  197. NumberStyles.AllowDecimalPoint |
  198. NumberStyles.AllowExponent,
  199. p.NumberFormat);
  200. }
  201. return str.Length;
  202. }
  203. catch (FormatException e)
  204. {
  205. throw p.InvalidNumberFormat(
  206. Resource.errNumberFormat, str, e);
  207. }
  208. catch (OverflowException e)
  209. {
  210. throw p.InvalidNumberFormat(
  211. Resource.errNumberOverflow, str, e);
  212. }
  213. }
  214. #endregion
  215. #region HexBinParser
  216. static int ScanInt32Hex(int i, IParserSupport<int> p)
  217. {
  218. return ScanHexBin(i, p, 8,
  219. (char c, ref int x) =>
  220. {
  221. int digit = HexDigit(c);
  222. if (digit < 0) return false;
  223. x *= 0x10;
  224. x += digit;
  225. return true;
  226. });
  227. }
  228. static int ScanInt32Bin(int i, IParserSupport<int> p)
  229. {
  230. return ScanHexBin(i, p, 32,
  231. (char c, ref int x) =>
  232. {
  233. if (c == '0') { x <<= 1; return true; }
  234. if (c == '1') { x <<= 1; x |= 1; return true; }
  235. return false;
  236. });
  237. }
  238. static int ScanInt64Hex(int i, IParserSupport<long> p)
  239. {
  240. return ScanHexBin(i, p, 16,
  241. (char c, ref long x) =>
  242. {
  243. int digit = HexDigit(c);
  244. if (digit < 0) return false;
  245. x *= 0x10;
  246. x += digit;
  247. return true;
  248. });
  249. }
  250. static int ScanInt64Bin(int i, IParserSupport<long> p)
  251. {
  252. return ScanHexBin(i, p, 64,
  253. (char c, ref long x) =>
  254. {
  255. if (c == '0') { x <<= 1; return true; }
  256. if (c == '1') { x <<= 1; x |= 1; return true; }
  257. return false;
  258. });
  259. }
  260. delegate int HexBinScan<T>(int i, IParserSupport<T> p);
  261. delegate bool HexBinParser<T>(char c, ref T value);
  262. static int ScanHexBin<T>(int i,
  263. IParserSupport<T> p, int maxDigits,
  264. HexBinParser<T> parser)
  265. {
  266. string expr = p.Expression;
  267. T value = default(T);
  268. int begin = i;
  269. for (; i < expr.Length; i++)
  270. {
  271. if (!parser(expr[i], ref value)) break;
  272. }
  273. int len = i - begin;
  274. if (len == 0)
  275. {
  276. p.ParsedValue = value;
  277. return 1;
  278. }
  279. if (len > maxDigits)
  280. {
  281. throw p.InvalidNumberFormat(
  282. Resource.errNumberOverflow,
  283. Substring(i, p), null);
  284. }
  285. p.ParsedValue = value;
  286. return len + 2;
  287. }
  288. static int HexDigit(char c)
  289. {
  290. if (c >= '0')
  291. {
  292. if (c <= '9') return c - '0';
  293. if (c >= 'a' && c <= 'f') return c-'\x57';
  294. if (c >= 'A' && c <= 'F') return c-'\x37';
  295. }
  296. return -1;
  297. }
  298. #endregion
  299. }
  300. sealed class UnknownLiteralParser<T> : ILiteralParser<T>
  301. {
  302. public int TryParse(int i, IParserSupport<T> p)
  303. {
  304. return -1;
  305. }
  306. }
  307. #endregion
  308. #region Common
  309. delegate T Parser<T>(
  310. string s, NumberStyles style, IFormatProvider format);
  311. static string Substring<T>(int i, IParserSupport<T> p)
  312. {
  313. return p.Expression.Substring(
  314. p.BeginPos, i - p.BeginPos);
  315. }
  316. static bool IsDigit(string s, int i)
  317. {
  318. return i < s.Length
  319. && s[i] >= '0'
  320. && s[i] <= '9';
  321. }
  322. #endregion
  323. }
  324. }