PageRenderTime 61ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/SampleParsers/Program.cs

#
C# | 224 lines | 152 code | 43 blank | 29 comment | 3 complexity | b6e1e234ae93dfbdb3a546bfc25b82c3 MD5 | raw file
  1. // ----------------------------------------------------------------------------------------------
  2. // Copyright (c) Mårten Rånge.
  3. // ----------------------------------------------------------------------------------------------
  4. // This source code is subject to terms and conditions of the Microsoft Public License. A
  5. // copy of the license can be found in the License.html file at the root of this distribution.
  6. // If you cannot locate the Microsoft Public License, please send an email to
  7. // dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  8. // by the terms of the Microsoft Public License.
  9. // ----------------------------------------------------------------------------------------------
  10. // You must not remove this notice, or any other, from this software.
  11. // ----------------------------------------------------------------------------------------------
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Linq.Expressions;
  15. using System.Reflection;
  16. using MicroParser;
  17. // ReSharper disable InconsistentNaming
  18. namespace SampleParsers
  19. {
  20. static class Program
  21. {
  22. static void Main (string[] args)
  23. {
  24. Sample1 ();
  25. Sample2 ();
  26. Console.ReadKey ();
  27. }
  28. static Program ()
  29. {
  30. // Sample1
  31. {
  32. // Int () is a builtin parser for ints
  33. var p_int = CharParser.Int ();
  34. var p_identifier = CharParser
  35. .ManyCharSatisfy2 ( // Creates a string parser
  36. CharSatisfy.Letter, // A test function applied to the
  37. // first character
  38. CharSatisfy.LetterOrDigit, // A test function applied to the
  39. // rest of the characters
  40. minCount: 1 // We require the identifier to be
  41. // at least 1 character long
  42. );
  43. var p_spaces = CharParser.SkipWhiteSpace ();
  44. var p_assignment = CharParser.SkipChar ('=');
  45. s_parserSample1 = Parser.Group (
  46. p_identifier.KeepLeft (p_spaces),
  47. p_assignment.KeepRight (p_spaces).KeepRight (p_int));
  48. }
  49. // Sample2
  50. {
  51. // Define a parameter expression that represent a dictionary, this dictionary
  52. // will contain the variable values
  53. var inputParameter = Expression.Parameter (
  54. typeof (IDictionary<string, double>),
  55. "input"
  56. );
  57. Func<string, Parser<Empty>> p_str = CharParser.SkipString;
  58. var p_spaces = CharParser.SkipWhiteSpace ();
  59. // Parse a double and map it into a ConstantExpression
  60. var p_value = CharParser.Double ().Map (d => (Expression) Expression.Constant (d));
  61. var p_variable = CharParser
  62. .ManyCharSatisfy2 (
  63. CharSatisfy.Letter,
  64. CharSatisfy.LetterOrDigit,
  65. minCount: 1
  66. )
  67. .Map (identifier => (Expression) Expression.Call (
  68. null,
  69. s_findVariableValueSample2,
  70. inputParameter,
  71. Expression.Constant (identifier.ToString ()))
  72. );
  73. var p_astRedirect = Parser.Redirect<Expression> ();
  74. // p_ast is the complete parser (AST = Abstract Syntax Tree)
  75. var p_ast = p_astRedirect.Parser;
  76. var p_term = Parser.Choice (
  77. p_ast.Between (p_str ("(").KeepLeft (p_spaces), p_str (")")),
  78. p_value,
  79. p_variable
  80. ).KeepLeft (p_spaces);
  81. // p_level is a support parser generator
  82. // it accepts a parser it will apply on the input separated by the operators
  83. // in the ops parameter
  84. Func<Parser<Expression>, string, Parser<Expression>> p_level =
  85. (parser, ops) => parser.Chain (
  86. CharParser.AnyOf (ops, minCount:1, maxCount:1).KeepLeft (p_spaces),
  87. (left, op, right) =>
  88. Expression.MakeBinary (OperatorToExpressionType (op), left, right)
  89. );
  90. // By splitting */ and +- like this we ensure */ binds _harder_
  91. var p_lvl0 = p_level (p_term, "*/");
  92. var p_lvl1 = p_level (p_lvl0, "+-");
  93. // This completes the parser
  94. p_astRedirect.ParserRedirect = p_lvl1;
  95. s_parameterSample2 = inputParameter;
  96. s_parserSample2 = p_ast;
  97. }
  98. }
  99. // Sample1
  100. static readonly Parser<Tuple<SubString, int>> s_parserSample1;
  101. static void Sample1 ()
  102. {
  103. var result = Parser.Parse (
  104. s_parserSample1,
  105. "AnIdentifier = 3"
  106. );
  107. if (result.IsSuccessful)
  108. {
  109. Console.WriteLine (
  110. "{0} = {1}",
  111. result.Value.Item1,
  112. result.Value.Item2
  113. );
  114. }
  115. else
  116. {
  117. Console.WriteLine (
  118. result.ErrorMessage
  119. );
  120. }
  121. }
  122. // Sample2
  123. static readonly ParameterExpression s_parameterSample2;
  124. static readonly Parser<Expression> s_parserSample2;
  125. static readonly MethodInfo s_findVariableValueSample2 = GetMethodInfo (() => FindVariableValue (null, null));
  126. static MethodInfo GetMethodInfo (Expression<Action> expression)
  127. {
  128. return ((MethodCallExpression)expression.Body).Method;
  129. }
  130. static double FindVariableValue (IDictionary<string, double> input, string name)
  131. {
  132. double value;
  133. return input.TryGetValue (name ?? "", out value) ? value : 0.0;
  134. }
  135. static ExpressionType OperatorToExpressionType (SubString op)
  136. {
  137. switch (op[0])
  138. {
  139. case '+':
  140. return ExpressionType.Add;
  141. case '-':
  142. return ExpressionType.Subtract;
  143. case '*':
  144. return ExpressionType.Multiply;
  145. case '/':
  146. return ExpressionType.Divide;
  147. default:
  148. throw new ArgumentException ();
  149. }
  150. }
  151. static void Sample2 ()
  152. {
  153. var input = new Dictionary<string, double>
  154. {
  155. {"x", 1.0},
  156. {"y", 2.0},
  157. };
  158. var expression = "2*(x + 1) + y + 3";
  159. var result = Parser.Parse (s_parserSample2, expression);
  160. if (result.IsSuccessful)
  161. {
  162. var lambda = Expression.Lambda<Func<IDictionary<string, double>, double>> (
  163. result.Value,
  164. s_parameterSample2
  165. );
  166. var del = lambda.Compile ();
  167. Console.WriteLine ("{0} = {1}", expression, del (input));
  168. foreach (var kv in input)
  169. {
  170. Console.WriteLine ("{0} = {1}", kv.Key, kv.Value);
  171. }
  172. }
  173. else
  174. {
  175. Console.WriteLine (
  176. result.ErrorMessage
  177. );
  178. }
  179. }
  180. }
  181. }