123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- grammar NCalc;
-
- options
- {
- output=AST;
- ASTLabelType=CommonTree;
- language=CSharp;
- }
-
- @header {
- using System.Text;
- using System.Globalization;
- using System.Collections.Generic;
- using NCalc.Domain;
- }
-
- @members {
- private const char BS = '\\';
- private static NumberFormatInfo numberFormatInfo = new NumberFormatInfo();
-
- private string extractString(string text) {
-
- StringBuilder sb = new StringBuilder(text);
- int startIndex = 1; // Skip initial quote
- int slashIndex = -1;
-
- while ((slashIndex = sb.ToString().IndexOf(BS, startIndex)) != -1)
- {
- char escapeType = sb[slashIndex + 1];
- switch (escapeType)
- {
- case 'u':
- string hcode = String.Concat(sb[slashIndex+4], sb[slashIndex+5]);
- string lcode = String.Concat(sb[slashIndex+2], sb[slashIndex+3]);
- char unicodeChar = Encoding.Unicode.GetChars(new byte[] { System.Convert.ToByte(hcode, 16), System.Convert.ToByte(lcode, 16)} )[0];
- sb.Remove(slashIndex, 6).Insert(slashIndex, unicodeChar);
- break;
- case 'n': sb.Remove(slashIndex, 2).Insert(slashIndex, '\n'); break;
- case 'r': sb.Remove(slashIndex, 2).Insert(slashIndex, '\r'); break;
- case 't': sb.Remove(slashIndex, 2).Insert(slashIndex, '\t'); break;
- case '\'': sb.Remove(slashIndex, 2).Insert(slashIndex, '\''); break;
- case '\\': sb.Remove(slashIndex, 2).Insert(slashIndex, '\\'); break;
- default: throw new RecognitionException("Unvalid escape sequence: \\" + escapeType);
- }
-
- startIndex = slashIndex + 1;
-
- }
-
- sb.Remove(0, 1);
- sb.Remove(sb.Length - 1, 1);
-
- return sb.ToString();
- }
-
- public List<string> Errors { get; private set; }
-
- public override void DisplayRecognitionError(String[] tokenNames, RecognitionException e) {
-
- base.DisplayRecognitionError(tokenNames, e);
-
- if(Errors == null)
- {
- Errors = new List<string>();
- }
-
- String hdr = GetErrorHeader(e);
- String msg = GetErrorMessage(e, tokenNames);
- Errors.Add(msg + " at " + hdr);
- }
- }
-
- @init {
- numberFormatInfo.NumberDecimalSeparator = ".";
- }
-
- ncalcExpression returns [LogicalExpression value]
- : logicalExpression EOF! {$value = $logicalExpression.value; }
- ;
-
- logicalExpression returns [LogicalExpression value]
- : left=conditionalExpression { $value = $left.value; } ( '?' middle=conditionalExpression ':' right=conditionalExpression { $value = new TernaryExpression($left.value, $middle.value, $right.value); })?
- ;
-
- conditionalExpression returns [LogicalExpression value]
- @init {
- BinaryExpressionType type = BinaryExpressionType.Unknown;
- }
- : left=booleanAndExpression { $value = $left.value; } (
- ('||' | 'or') { type = BinaryExpressionType.Or; }
- right=conditionalExpression { $value = new BinaryExpression(type, $value, $right.value); }
- )*
- ;
-
- booleanAndExpression returns [LogicalExpression value]
- @init {
- BinaryExpressionType type = BinaryExpressionType.Unknown;
- }
- : left=bitwiseOrExpression { $value = $left.value; } (
- ('&&' | 'and') { type = BinaryExpressionType.And; }
- right=bitwiseOrExpression { $value = new BinaryExpression(type, $value, $right.value); }
- )*
- ;
-
- bitwiseOrExpression returns [LogicalExpression value]
- @init {
- BinaryExpressionType type = BinaryExpressionType.Unknown;
- }
- : left=bitwiseXOrExpression { $value = $left.value; } (
- '|' { type = BinaryExpressionType.BitwiseOr; }
- right=bitwiseOrExpression { $value = new BinaryExpression(type, $value, $right.value); }
- )*
- ;
-
- bitwiseXOrExpression returns [LogicalExpression value]
- @init {
- BinaryExpressionType type = BinaryExpressionType.Unknown;
- }
- : left=bitwiseAndExpression { $value = $left.value; } (
- '^' { type = BinaryExpressionType.BitwiseXOr; }
- right=bitwiseAndExpression { $value = new BinaryExpression(type, $value, $right.value); }
- )*
- ;
-
- bitwiseAndExpression returns [LogicalExpression value]
- @init {
- BinaryExpressionType type = BinaryExpressionType.Unknown;
- }
- : left=equalityExpression { $value = $left.value; } (
- '&' { type = BinaryExpressionType.BitwiseAnd; }
- right=equalityExpression { $value = new BinaryExpression(type, $value, $right.value); }
- )*
- ;
-
- equalityExpression returns [LogicalExpression value]
- @init {
- BinaryExpressionType type = BinaryExpressionType.Unknown;
- }
- : left=relationalExpression { $value = $left.value; } (
- ( ('==' | '=' ) { type = BinaryExpressionType.Equal; }
- | ('!=' | '<>' ) { type = BinaryExpressionType.NotEqual; } )
- right=relationalExpression { $value = new BinaryExpression(type, $value, $right.value); }
- )*
- ;
-
- relationalExpression returns [LogicalExpression value]
- @init {
- BinaryExpressionType type = BinaryExpressionType.Unknown;
- }
- : left=shiftExpression { $value = $left.value; } (
- ( '<' { type = BinaryExpressionType.Lesser; }
- | '<=' { type = BinaryExpressionType.LesserOrEqual; }
- | '>' { type = BinaryExpressionType.Greater; }
- | '>=' { type = BinaryExpressionType.GreaterOrEqual; } )
- right=shiftExpression { $value = new BinaryExpression(type, $value, $right.value); }
- )*
- ;
-
- shiftExpression returns [LogicalExpression value]
- @init {
- BinaryExpressionType type = BinaryExpressionType.Unknown;
- }
- : left=additiveExpression { $value = $left.value; } (
- ( '<<' { type = BinaryExpressionType.LeftShift; }
- | '>>' { type = BinaryExpressionType.RightShift; } )
- right=additiveExpression { $value = new BinaryExpression(type, $value, $right.value); }
- )*
- ;
-
- additiveExpression returns [LogicalExpression value]
- @init {
- BinaryExpressionType type = BinaryExpressionType.Unknown;
- }
- : left=multiplicativeExpression { $value = $left.value; } (
- ( '+' { type = BinaryExpressionType.Plus; }
- | '-' { type = BinaryExpressionType.Minus; } )
- right=multiplicativeExpression { $value = new BinaryExpression(type, $value, $right.value); }
- )*
- ;
-
- multiplicativeExpression returns [LogicalExpression value]
- @init {
- BinaryExpressionType type = BinaryExpressionType.Unknown;
- }
- : left=unaryExpression { $value = $left.value); } (
- ( '*' { type = BinaryExpressionType.Times; }
- | '/' { type = BinaryExpressionType.Div; }
- | '%' { type = BinaryExpressionType.Modulo; } )
- right=unaryExpression { $value = new BinaryExpression(type, $value, $right.value); }
- )*
- ;
-
-
- unaryExpression returns [LogicalExpression value]
- : primaryExpression { $value = $primaryExpression.value; }
- | ('!' | 'not') primaryExpression { $value = new UnaryExpression(UnaryExpressionType.Not, $primaryExpression.value); }
- | ('~') primaryExpression { $value = new UnaryExpression(UnaryExpressionType.BitwiseNot, $primaryExpression.value); }
- | '-' primaryExpression { $value = new UnaryExpression(UnaryExpressionType.Negate, $primaryExpression.value); }
- ;
-
- primaryExpression returns [LogicalExpression value]
- : '(' logicalExpression ')' { $value = $logicalExpression.value; }
- | expr=value { $value = $expr.value; }
- | identifier {$value = (LogicalExpression) $identifier.value; } (arguments {$value = new Function($identifier.value, ($arguments.value).ToArray()); })?
- ;
-
- value returns [ValueExpression value]
- : INTEGER { try { $value = new ValueExpression(int.Parse($INTEGER.text)); } catch(System.OverflowException) { $value = new ValueExpression(long.Parse($INTEGER.text)); } }
- | FLOAT { $value = new ValueExpression(double.Parse($FLOAT.text, NumberStyles.Float, numberFormatInfo)); }
- | STRING { $value = new ValueExpression(extractString($STRING.text)); }
- | DATETIME { $value = new ValueExpression(DateTime.Parse($DATETIME.text.Substring(1, $DATETIME.text.Length-2))); }
- | TRUE { $value = new ValueExpression(true); }
- | FALSE { $value = new ValueExpression(false); }
- ;
-
- identifier returns[Identifier value]
- : ID { $value = new Identifier($ID.text); }
- | NAME { $value = new Identifier($NAME.text.Substring(1, $NAME.text.Length-2)); }
- ;
-
- expressionList returns [List<LogicalExpression> value]
- @init {
- List<LogicalExpression> expressions = new List<LogicalExpression>();
- }
- : first=logicalExpression {expressions.Add($first.value);} ( ',' follow=logicalExpression {expressions.Add($follow.value);})*
- { $value = expressions; }
- ;
-
- arguments returns [List<LogicalExpression> value]
- @init {
- $value = new List<LogicalExpression>();
- }
- : '(' ( expressionList {$value = $expressionList.value;} )? ')'
- ;
-
- TRUE
- : 'true'
- ;
-
- FALSE
- : 'false'
- ;
-
- ID
- : LETTER (LETTER | DIGIT)*
- ;
-
- INTEGER
- : DIGIT+
- ;
-
- FLOAT
- : DIGIT* '.' DIGIT+ E?
- | DIGIT+ E
- ;
-
- STRING
- : '\'' ( EscapeSequence | (options {greedy=false;} : ~('\u0000'..'\u001f' | '\\' | '\'' ) ) )* '\''
- ;
-
- DATETIME
- : '#' (options {greedy=false;} : ~('#')*) '#'
- ;
-
- NAME : '[' (options {greedy=false;} : ~(']')*) ']'
- ;
-
- E : ('E'|'e') ('+'|'-')? DIGIT+
- ;
-
- fragment LETTER
- : 'a'..'z'
- | 'A'..'Z'
- | '_'
- ;
-
- fragment DIGIT
- : '0'..'9'
- ;
-
- fragment EscapeSequence
- : '\\'
- (
- 'n'
- | 'r'
- | 't'
- | '\''
- | '\\'
- | UnicodeEscape
- )
- ;
-
- fragment HexDigit
- : ('0'..'9'|'a'..'f'|'A'..'F') ;
-
-
- fragment UnicodeEscape
- : 'u' HexDigit HexDigit HexDigit HexDigit
- ;
-
- /* Ignore white spaces */
- WS : (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;}
- ;
|