]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/formula/parser/SheetFormulaParser.jj
Adopt spreadsheet changes made in Balas development
[simantics/platform.git] / bundles / org.simantics.spreadsheet / src / org / simantics / spreadsheet / solver / formula / parser / SheetFormulaParser.jj
1 options {\r
2   JDK_VERSION = "1.8";\r
3   STATIC = false;\r
4   IGNORE_CASE = false;\r
5   UNICODE_INPUT = true;\r
6   JAVA_UNICODE_ESCAPE = false;\r
7 }\r
8 \r
9 PARSER_BEGIN(SheetFormulaParser)\r
10 package org.simantics.spreadsheet.graph.parser;\r
11 \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
16 \r
17 /**\r
18  * Parser for spreadsheet formulas\r
19  * @author Antti Villberg\r
20  */\r
21 public class SheetFormulaParser {    \r
22 }\r
23 PARSER_END(SheetFormulaParser)\r
24 \r
25 /*** Lexer *********************************************************/\r
26 \r
27 SKIP:\r
28 { <WHITESPACE: " " | "\n" | "\r" | "\t" > \r
29 | <COMMENT1: "/*" (~["*"] | "*" ~["/"])* "*/" >  \r
30 | <COMMENT2: "//" (~["\n"])* >\r
31 }\r
32 \r
33 TOKEN:\r
34 { ";" | "(" | ")" | "?" | "[" | "]"\r
35 | "{" | "}" | "|" | "&" | "+" | "*" | "/" | "^" \r
36 | "," | ".." | "." | "=" | "<" | ">" | "<>"\r
37 | "true" | "false" | "null" | "TRUE" | "FALSE"\r
38 | < #LETTER: [\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
78       ]\r
79   >\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
94 | <FLOAT: \r
95     ( <POSITIVE_INTEGER> "." <POSITIVE_INTEGER> (["e","E"] <INTEGER>)?\r
96     | "." <POSITIVE_INTEGER> (["e","E"] <INTEGER>)?\r
97     | <POSITIVE_INTEGER> ["e","E"] <INTEGER>\r
98     ) >\r
99 | <INTEGER: <POSITIVE_INTEGER> >\r
100 \r
101 }\r
102 \r
103 AstValue primary() : {\r
104     Token tok;\r
105     AstValue temp;\r
106     AstRange tempRange;\r
107 } {\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
122 }\r
123 \r
124 AstApply apply() : {\r    AstArgList al;\r
125     Token tok;\r
126 } {\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
129 \r
130 AstValue array() : {\r
131     AstArray arr = new AstArray();\r
132     AstValue temp;\r
133 } {\r
134   LOOKAHEAD(2) "{" "}" { return new AstArray(); } |\r
135   "{" temp = relation() { arr.add(temp); } "," ( temp = relation() { arr.add(temp); } )* "}" { return arr; }\r}\r
136 \r
137 AstRange range() : {\r
138     Token temp1;\r
139     Token temp2;\r
140 } {\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
144 }\r
145 \r
146 AstArgList arglist() : {\r
147     AstArgList ret = new AstArgList();\r
148     AstValue temp;\r
149 } {\r
150   temp = relation()  { ret.add(temp); }\r  ( (";"|",") { temp = AstNothing.INSTANCE; } (temp = relation())? { ret.add(temp); } )*  { return ret; }\r
151 }\r
152 \r
153 AstValue relation() : {\r
154   AstRelation ret;\r
155   String op;\r
156   AstValue ex;\r
157 } {\r
158         ex = arithmetic_expression() {  ret = new AstRelation(ex); } ( op = rel_op() ex = arithmetic_expression() {     ret.setRight(op, ex); } )? { return ret.simplify(); }\r}\r
159 \r
160 String rel_op() : {\r
161 } {\r
162         "<" { return "< ";} | "<=" { return "<=";} | ">" { return " >";} | ">=" { return " >=";} | "=" { return "=";} | "<>" { return "<>";}\r
163 }\r
164 \r
165 //   \r
166 AstValue arithmetic_expression() : {\r
167     AstArithmeticExpression ret;\r
168     String op = null;\r
169     AstValue temp;\r
170 } {\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
172 }\r
173 \r
174 String add_op() : {\r
175 } {\r
176     "+" { return "+";} | "-" { return "-";} | "&" { return "&";}\r
177 }\r
178 \r
179 AstValue term() : {\r
180     AstTerm ret;\r
181     String op;\r
182     AstValue temp;\r
183 } {\r
184   temp = factor() { ret = new AstTerm(temp); } (op = mul_op() temp = factor() { ret.add(op, temp); } )* { return ret.simplify(); }\r
185 }\r
186 \r
187 \r
188 String mul_op() : {\r
189 } {\r
190     "*" { return "*";} | "/" { return "/";} \r
191 }\r
192 \r
193 AstValue factor() : {\r
194     AstFactor ret;\r
195     String op;\r
196     AstValue temp;\r
197 } {\r
198   temp = primary() { ret = new AstFactor(temp); } (op = factor_op() temp = primary() { ret.add(op, temp); } )* { return ret.simplify(); }\r
199 }\r
200 \r
201 String factor_op() : {\r
202 } {\r
203     "^" { return "^";}\r
204 }\r
205 \r