5 UNICODE_INPUT = true;
\r
6 JAVA_UNICODE_ESCAPE = false;
\r
9 PARSER_BEGIN(SheetFormulaParser)
\r
10 package org.simantics.spreadsheet.graph.parser;
\r
12 import org.simantics.spreadsheet.graph.parser.ast.*;
\r
13 import java.util.ArrayList;
\r
14 import java.util.List;
\r
15 import java.util.Collections;
\r
18 * Parser for spreadsheet formulas
\r
19 * @author Antti Villberg
\r
21 public class SheetFormulaParser {
\r
23 PARSER_END(SheetFormulaParser)
\r
25 /*** Lexer *********************************************************/
\r
28 { <WHITESPACE: " " | "\n" | "\r" | "\t" >
\r
29 | <COMMENT1: "/*" (~["*"] | "*" ~["/"])* "*/" >
\r
30 | <COMMENT2: "//" (~["\n"])* >
\r
34 { ";" | "(" | ")" | "?" | "[" | "]"
\r
35 | "{" | "}" | "|" | "&" | "+" | "*" | "/" | "^"
\r
36 | "," | ".." | "." | "=" | "<" | ">" | "<>"
\r
37 | "true" | "false" | "null" | "TRUE" | "FALSE"
\r
39 "\u0024", //DOLLAR SIGN: milreis, escudo
\r
40 "\u0041"-"\u005a", //LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z
\r
41 "\u005f", //LOW LINE: spacing underscore
\r
42 "\u0061"-"\u007a", //LATIN SMALL LETTER A - LATIN SMALL LETTER Z
\r
43 "\u00aa"-"\u00ad", // 00AA FEMININE ORDINAL INDICATOR: spanish
\r
44 // 00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK: left guillemet
\r
45 // 00AC NOT SIGN: angled dash
\r
46 // 00AD SOFT HYPHEN: discretionary hyphen
\r
47 "\u00b5"-"\u00b6", // 00B5 MICRO SIGN: greek small letter mu
\r
48 // 00B6 PILCROW SIGN: paragraph sign
\r
49 "\u00ba"-"\u00bb", // 00BA MASCULINE ORDINAL INDICATOR: spanish
\r
50 // 00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK : right guillemet
\r
51 "\u00c0"-"\u00d6", //LATIN CAPITAL LETTER A WITH GRAVE - LATIN CAPITAL LETTER O WITH DIAERESIS
\r
52 "\u00d8"-"\u00f6", //LATIN CAPITAL LETTER O WITH STROKE - LATIN SMALL LETTER O WITH DIAERESIS
\r
53 "\u00f8"-"\u00ff", //LATIN SMALL LETTER O WITH STROKE - LATIN SMALL LETTER Y WITH DIAERESIS
\r
54 "\u0100"-"\u1fff", //LATIN CAPITAL LETTER A WITH MACRON - GREEK DASIA:reversed comma
\r
55 "\u3040"-"\u318f", //Hiragana - Hangul
\r
56 "\u3300"-"\u337f", //Squared Katakana
\r
57 "\u3400"-"\u3d2d", //CJK Unified Ideographs Extension A
\r
58 "\u4e00"-"\u9fff", //CJK Unified Ideographs
\r
59 "\uf900"-"\ufaff", //CJK Compatibility Ideographs
\r
60 "\ufb00"-"\ufb06", //LATIN SMALL LIGATURE FF -LATIN SMALL LIGATURE ST
\r
61 "\ufb13"-"\ufb17", //ARMENIAN SMALL LIGATURE MEN NOW - ARMENIAN SMALL LIGATURE MEN XEH
\r
62 "\ufb1f"-"\ufb28", //HEBREW LIGATURE YIDDISH YOD YOD PATAH -HEBREW LETTER WIDE TAV
\r
63 "\ufb2a"-"\ufb36", //HEBREW LETTER SHIN WITH SHIN DOT - HEBREW LETTER ZAYIN WITH DAGESH
\r
64 "\ufb38"-"\ufb3e", //HEBREW LETTER TET WITH DAGESH - HEBREW LETTER MEM WITH DAGESH
\r
65 "\ufb40"-"\ufb41", //HEBREW LETTER NUN WITH DAGESH - HEBREW LETTER SAMEKH WITH DAGESH
\r
66 "\ufb43"-"\ufb44", //HEBREW LETTER FINAL PE WITH DAGESH - HEBREW LETTER PE WITH DAGESH
\r
67 "\ufb46"-"\ufb4f", //HEBREW LETTER TSADI WITH DAGESH - HEBREW LIGATURE ALEF LAMED
\r
68 "\ufb50"-"\ufdd7", //Arabic Presentation Forms(A) - ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM
\r
69 "\ufdf0"-"\ufdfd", //ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM -ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM
\r
70 "\ufe70"-"\ufefc", //Arabic Presentation Forms(B) - ARABIC LIGATURE LAM WITH ALEF FINAL FORM
\r
71 "\uff1f"-"\uff3a", //FULLWIDTH QUESTION MARK - FULLWIDTH LATIN CAPITAL LETTER Z
\r
72 "\uff3f"-"\uff5e", //FULLWIDTH LOW LINE - FULLWIDTH TILDE
\r
73 "\uff61"-"\uffbe", //Halfwidth CJK punctuation:HALFWIDTH IDEOGRAPHIC FULL STOP - HALFWIDTH HANGUL LETTER HIEUH
\r
74 "\uffc2"-"\uffc7", //HALFWIDTH HANGUL LETTER A - HALFWIDTH HANGUL LETTER E
\r
75 "\uffca"-"\uffcf", //HALFWIDTH HANGUL LETTER YEO - HALFWIDTH HANGUL LETTER OE
\r
76 "\uffd2"-"\uffd7", //HALFWIDTH HANGUL LETTER YO - HALFWIDTH HANGUL LETTER YU
\r
77 "\uffda"-"\uffdc" //HALFWIDTH HANGUL LETTER EU - HALFWIDTH HANGUL LETTER I
\r
80 | <#ALPHANUM: < LETTER > | ["0"-"9"] >
\r
81 | <STRING: "\"" (~["\"", "\\", "\n"] | "\\" ~["\n"])* "\"">
\r
82 { matchedToken.image = SheetParserUtils.unescape(
\r
83 matchedToken.image.substring(1,matchedToken.image.length()-1)); }
\r
84 | <SHEET_NAME: "'" (~["'", "\\", "\n"] | "\\" ~["\n"])* "'">
\r
85 { matchedToken.image = SheetParserUtils.unescape(
\r
86 matchedToken.image.substring(1,matchedToken.image.length()-1)); }
\r
87 | <LONG_STRING: "\"\"\"" (~["\""] | "\"" ~["\""] | "\"\"" ~["\""])* "\"\"\"">
\r
88 { matchedToken.image = matchedToken.image.substring(3,matchedToken.image.length()-3); }
\r
89 | <CELL_SINGLE: (["$"]){0,1}(["A"-"Z"]){1,5}(["$"]){0,1}(["0"-"9"]){1,5} >
\r
90 | <#CELL_RANGE_PART: (["$"]){0,1}(["A"-"Z"]){1,5}(["$"]){0,1}(["0"-"9"]){0,5} >
\r
91 | <CELL_RANGE: <CELL_RANGE_PART> [":"] <CELL_RANGE_PART>>
\r
92 | <IDENT: < LETTER > (< ALPHANUM >)* >
\r
93 | <#POSITIVE_INTEGER: (["0"-"9"])+ >
\r
95 ( <POSITIVE_INTEGER> "." <POSITIVE_INTEGER> (["e","E"] <INTEGER>)?
\r
96 | "." <POSITIVE_INTEGER> (["e","E"] <INTEGER>)?
\r
97 | <POSITIVE_INTEGER> ["e","E"] <INTEGER>
\r
99 | <INTEGER: <POSITIVE_INTEGER> >
\r
103 AstValue primary() : {
\r
106 AstRange tempRange;
\r
108 "null" { return AstNull.NULL; }
\r
109 | "true" { return AstBoolean.TRUE; }
\r
110 | "false" { return AstBoolean.FALSE; }
\r
111 | "TRUE" { return AstBoolean.TRUE; }
\r
112 | "FALSE" { return AstBoolean.FALSE; }
\r
113 | <STRING> { return new AstString(token.image); }
\r
114 | <LONG_STRING> { return new AstString(token.image); }
\r
115 | <FLOAT> { return new AstDouble(token.image); }
\r
116 | <INTEGER> { return new AstInteger(Integer.parseInt(token.image)); }
\r
117 | LOOKAHEAD(2) (tok = <IDENT> | tok = <SHEET_NAME>) "!" tempRange = range() { return tempRange.inSheet(tok.image); }
\r
118 | LOOKAHEAD(2) temp = apply() { return temp; }
\r | "(" temp = relation() ")" { return temp; }
\r
119 | temp = range() { return temp; }
\r
120 | temp = array() { return temp; }
\r
121 | <IDENT> { return new AstIdentifier(token.image); }
\r
124 AstApply apply() : {
\r AstArgList al;
\r
127 LOOKAHEAD(3) tok = <IDENT> "(" ")" { return new AstApply(tok.image, null); } |
\r
128 tok = <IDENT> "(" al = arglist() ")" { return new AstApply(tok.image, al); }
\r}
\r
130 AstValue array() : {
\r
131 AstArray arr = new AstArray();
\r
134 LOOKAHEAD(2) "{" "}" { return new AstArray(); } |
\r
135 "{" temp = relation() { arr.add(temp); } "," ( temp = relation() { arr.add(temp); } )* "}" { return arr; }
\r}
\r
137 AstRange range() : {
\r
141 LOOKAHEAD(2) <CELL_RANGE> { return new AstRange(token.image); }
\r
142 | <CELL_SINGLE> { return new AstRange(token.image); }
\r
143 | "#REF!" { return AstRange.REF; }
\r
146 AstArgList arglist() : {
\r
147 AstArgList ret = new AstArgList();
\r
150 temp = relation() { ret.add(temp); }
\r ( (";"|",") { temp = AstNothing.INSTANCE; } (temp = relation())? { ret.add(temp); } )* { return ret; }
\r
153 AstValue relation() : {
\r
158 ex = arithmetic_expression() { ret = new AstRelation(ex); } ( op = rel_op() ex = arithmetic_expression() { ret.setRight(op, ex); } )? { return ret.simplify(); }
\r}
\r
160 String rel_op() : {
\r
162 "<" { return "< ";} | "<=" { return "<=";} | ">" { return " >";} | ">=" { return " >=";} | "=" { return "=";} | "<>" { return "<>";}
\r
166 AstValue arithmetic_expression() : {
\r
167 AstArithmeticExpression ret;
\r
171 (op = add_op())? temp = term() { ret = new AstArithmeticExpression(op, temp); } ( LOOKAHEAD(2) op = add_op() temp = term() { ret.add(op, temp); } )* { return ret.simplify(); }
\r
174 String add_op() : {
\r
176 "+" { return "+";} | "-" { return "-";} | "&" { return "&";}
\r
179 AstValue term() : {
\r
184 temp = factor() { ret = new AstTerm(temp); } (op = mul_op() temp = factor() { ret.add(op, temp); } )* { return ret.simplify(); }
\r
188 String mul_op() : {
\r
190 "*" { return "*";} | "/" { return "/";}
\r
193 AstValue factor() : {
\r
198 temp = primary() { ret = new AstFactor(temp); } (op = factor_op() temp = primary() { ret.add(op, temp); } )* { return ret.simplify(); }
\r
201 String factor_op() : {
\r