暫無描述
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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. grammar NCalc;
  2. options
  3. {
  4. output=AST;
  5. ASTLabelType=CommonTree;
  6. language=CSharp;
  7. }
  8. @header {
  9. using System.Text;
  10. using System.Globalization;
  11. using System.Collections.Generic;
  12. using NCalc.Domain;
  13. }
  14. @members {
  15. private const char BS = '\\';
  16. private static NumberFormatInfo numberFormatInfo = new NumberFormatInfo();
  17. private string extractString(string text) {
  18. StringBuilder sb = new StringBuilder(text);
  19. int startIndex = 1; // Skip initial quote
  20. int slashIndex = -1;
  21. while ((slashIndex = sb.ToString().IndexOf(BS, startIndex)) != -1)
  22. {
  23. char escapeType = sb[slashIndex + 1];
  24. switch (escapeType)
  25. {
  26. case 'u':
  27. string hcode = String.Concat(sb[slashIndex+4], sb[slashIndex+5]);
  28. string lcode = String.Concat(sb[slashIndex+2], sb[slashIndex+3]);
  29. char unicodeChar = Encoding.Unicode.GetChars(new byte[] { System.Convert.ToByte(hcode, 16), System.Convert.ToByte(lcode, 16)} )[0];
  30. sb.Remove(slashIndex, 6).Insert(slashIndex, unicodeChar);
  31. break;
  32. case 'n': sb.Remove(slashIndex, 2).Insert(slashIndex, '\n'); break;
  33. case 'r': sb.Remove(slashIndex, 2).Insert(slashIndex, '\r'); break;
  34. case 't': sb.Remove(slashIndex, 2).Insert(slashIndex, '\t'); break;
  35. case '\'': sb.Remove(slashIndex, 2).Insert(slashIndex, '\''); break;
  36. case '\\': sb.Remove(slashIndex, 2).Insert(slashIndex, '\\'); break;
  37. default: throw new RecognitionException("Unvalid escape sequence: \\" + escapeType);
  38. }
  39. startIndex = slashIndex + 1;
  40. }
  41. sb.Remove(0, 1);
  42. sb.Remove(sb.Length - 1, 1);
  43. return sb.ToString();
  44. }
  45. public List<string> Errors { get; private set; }
  46. public override void DisplayRecognitionError(String[] tokenNames, RecognitionException e) {
  47. base.DisplayRecognitionError(tokenNames, e);
  48. if(Errors == null)
  49. {
  50. Errors = new List<string>();
  51. }
  52. String hdr = GetErrorHeader(e);
  53. String msg = GetErrorMessage(e, tokenNames);
  54. Errors.Add(msg + " at " + hdr);
  55. }
  56. }
  57. @init {
  58. numberFormatInfo.NumberDecimalSeparator = ".";
  59. }
  60. ncalcExpression returns [LogicalExpression value]
  61. : logicalExpression EOF! {$value = $logicalExpression.value; }
  62. ;
  63. logicalExpression returns [LogicalExpression value]
  64. : left=conditionalExpression { $value = $left.value; } ( '?' middle=conditionalExpression ':' right=conditionalExpression { $value = new TernaryExpression($left.value, $middle.value, $right.value); })?
  65. ;
  66. conditionalExpression returns [LogicalExpression value]
  67. @init {
  68. BinaryExpressionType type = BinaryExpressionType.Unknown;
  69. }
  70. : left=booleanAndExpression { $value = $left.value; } (
  71. ('||' | 'or') { type = BinaryExpressionType.Or; }
  72. right=conditionalExpression { $value = new BinaryExpression(type, $value, $right.value); }
  73. )*
  74. ;
  75. booleanAndExpression returns [LogicalExpression value]
  76. @init {
  77. BinaryExpressionType type = BinaryExpressionType.Unknown;
  78. }
  79. : left=bitwiseOrExpression { $value = $left.value; } (
  80. ('&&' | 'and') { type = BinaryExpressionType.And; }
  81. right=bitwiseOrExpression { $value = new BinaryExpression(type, $value, $right.value); }
  82. )*
  83. ;
  84. bitwiseOrExpression returns [LogicalExpression value]
  85. @init {
  86. BinaryExpressionType type = BinaryExpressionType.Unknown;
  87. }
  88. : left=bitwiseXOrExpression { $value = $left.value; } (
  89. '|' { type = BinaryExpressionType.BitwiseOr; }
  90. right=bitwiseOrExpression { $value = new BinaryExpression(type, $value, $right.value); }
  91. )*
  92. ;
  93. bitwiseXOrExpression returns [LogicalExpression value]
  94. @init {
  95. BinaryExpressionType type = BinaryExpressionType.Unknown;
  96. }
  97. : left=bitwiseAndExpression { $value = $left.value; } (
  98. '^' { type = BinaryExpressionType.BitwiseXOr; }
  99. right=bitwiseAndExpression { $value = new BinaryExpression(type, $value, $right.value); }
  100. )*
  101. ;
  102. bitwiseAndExpression returns [LogicalExpression value]
  103. @init {
  104. BinaryExpressionType type = BinaryExpressionType.Unknown;
  105. }
  106. : left=equalityExpression { $value = $left.value; } (
  107. '&' { type = BinaryExpressionType.BitwiseAnd; }
  108. right=equalityExpression { $value = new BinaryExpression(type, $value, $right.value); }
  109. )*
  110. ;
  111. equalityExpression returns [LogicalExpression value]
  112. @init {
  113. BinaryExpressionType type = BinaryExpressionType.Unknown;
  114. }
  115. : left=relationalExpression { $value = $left.value; } (
  116. ( ('==' | '=' ) { type = BinaryExpressionType.Equal; }
  117. | ('!=' | '<>' ) { type = BinaryExpressionType.NotEqual; } )
  118. right=relationalExpression { $value = new BinaryExpression(type, $value, $right.value); }
  119. )*
  120. ;
  121. relationalExpression returns [LogicalExpression value]
  122. @init {
  123. BinaryExpressionType type = BinaryExpressionType.Unknown;
  124. }
  125. : left=shiftExpression { $value = $left.value; } (
  126. ( '<' { type = BinaryExpressionType.Lesser; }
  127. | '<=' { type = BinaryExpressionType.LesserOrEqual; }
  128. | '>' { type = BinaryExpressionType.Greater; }
  129. | '>=' { type = BinaryExpressionType.GreaterOrEqual; } )
  130. right=shiftExpression { $value = new BinaryExpression(type, $value, $right.value); }
  131. )*
  132. ;
  133. shiftExpression returns [LogicalExpression value]
  134. @init {
  135. BinaryExpressionType type = BinaryExpressionType.Unknown;
  136. }
  137. : left=additiveExpression { $value = $left.value; } (
  138. ( '<<' { type = BinaryExpressionType.LeftShift; }
  139. | '>>' { type = BinaryExpressionType.RightShift; } )
  140. right=additiveExpression { $value = new BinaryExpression(type, $value, $right.value); }
  141. )*
  142. ;
  143. additiveExpression returns [LogicalExpression value]
  144. @init {
  145. BinaryExpressionType type = BinaryExpressionType.Unknown;
  146. }
  147. : left=multiplicativeExpression { $value = $left.value; } (
  148. ( '+' { type = BinaryExpressionType.Plus; }
  149. | '-' { type = BinaryExpressionType.Minus; } )
  150. right=multiplicativeExpression { $value = new BinaryExpression(type, $value, $right.value); }
  151. )*
  152. ;
  153. multiplicativeExpression returns [LogicalExpression value]
  154. @init {
  155. BinaryExpressionType type = BinaryExpressionType.Unknown;
  156. }
  157. : left=unaryExpression { $value = $left.value); } (
  158. ( '*' { type = BinaryExpressionType.Times; }
  159. | '/' { type = BinaryExpressionType.Div; }
  160. | '%' { type = BinaryExpressionType.Modulo; } )
  161. right=unaryExpression { $value = new BinaryExpression(type, $value, $right.value); }
  162. )*
  163. ;
  164. unaryExpression returns [LogicalExpression value]
  165. : primaryExpression { $value = $primaryExpression.value; }
  166. | ('!' | 'not') primaryExpression { $value = new UnaryExpression(UnaryExpressionType.Not, $primaryExpression.value); }
  167. | ('~') primaryExpression { $value = new UnaryExpression(UnaryExpressionType.BitwiseNot, $primaryExpression.value); }
  168. | '-' primaryExpression { $value = new UnaryExpression(UnaryExpressionType.Negate, $primaryExpression.value); }
  169. ;
  170. primaryExpression returns [LogicalExpression value]
  171. : '(' logicalExpression ')' { $value = $logicalExpression.value; }
  172. | expr=value { $value = $expr.value; }
  173. | identifier {$value = (LogicalExpression) $identifier.value; } (arguments {$value = new Function($identifier.value, ($arguments.value).ToArray()); })?
  174. ;
  175. value returns [ValueExpression value]
  176. : INTEGER { try { $value = new ValueExpression(int.Parse($INTEGER.text)); } catch(System.OverflowException) { $value = new ValueExpression(long.Parse($INTEGER.text)); } }
  177. | FLOAT { $value = new ValueExpression(double.Parse($FLOAT.text, NumberStyles.Float, numberFormatInfo)); }
  178. | STRING { $value = new ValueExpression(extractString($STRING.text)); }
  179. | DATETIME { $value = new ValueExpression(DateTime.Parse($DATETIME.text.Substring(1, $DATETIME.text.Length-2))); }
  180. | TRUE { $value = new ValueExpression(true); }
  181. | FALSE { $value = new ValueExpression(false); }
  182. ;
  183. identifier returns[Identifier value]
  184. : ID { $value = new Identifier($ID.text); }
  185. | NAME { $value = new Identifier($NAME.text.Substring(1, $NAME.text.Length-2)); }
  186. ;
  187. expressionList returns [List<LogicalExpression> value]
  188. @init {
  189. List<LogicalExpression> expressions = new List<LogicalExpression>();
  190. }
  191. : first=logicalExpression {expressions.Add($first.value);} ( ',' follow=logicalExpression {expressions.Add($follow.value);})*
  192. { $value = expressions; }
  193. ;
  194. arguments returns [List<LogicalExpression> value]
  195. @init {
  196. $value = new List<LogicalExpression>();
  197. }
  198. : '(' ( expressionList {$value = $expressionList.value;} )? ')'
  199. ;
  200. TRUE
  201. : 'true'
  202. ;
  203. FALSE
  204. : 'false'
  205. ;
  206. ID
  207. : LETTER (LETTER | DIGIT)*
  208. ;
  209. INTEGER
  210. : DIGIT+
  211. ;
  212. FLOAT
  213. : DIGIT* '.' DIGIT+ E?
  214. | DIGIT+ E
  215. ;
  216. STRING
  217. : '\'' ( EscapeSequence | (options {greedy=false;} : ~('\u0000'..'\u001f' | '\\' | '\'' ) ) )* '\''
  218. ;
  219. DATETIME
  220. : '#' (options {greedy=false;} : ~('#')*) '#'
  221. ;
  222. NAME : '[' (options {greedy=false;} : ~(']')*) ']'
  223. ;
  224. E : ('E'|'e') ('+'|'-')? DIGIT+
  225. ;
  226. fragment LETTER
  227. : 'a'..'z'
  228. | 'A'..'Z'
  229. | '_'
  230. ;
  231. fragment DIGIT
  232. : '0'..'9'
  233. ;
  234. fragment EscapeSequence
  235. : '\\'
  236. (
  237. 'n'
  238. | 'r'
  239. | 't'
  240. | '\''
  241. | '\\'
  242. | UnicodeEscape
  243. )
  244. ;
  245. fragment HexDigit
  246. : ('0'..'9'|'a'..'f'|'A'..'F') ;
  247. fragment UnicodeEscape
  248. : 'u' HexDigit HexDigit HexDigit HexDigit
  249. ;
  250. /* Ignore white spaces */
  251. WS : (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;}
  252. ;