options { JDK_VERSION = "1.8"; STATIC = false; IGNORE_CASE = false; UNICODE_INPUT = true; JAVA_UNICODE_ESCAPE = false; } PARSER_BEGIN(SheetFormulaParser) package org.simantics.spreadsheet.graph.parser; import org.simantics.spreadsheet.graph.parser.ast.*; import java.util.ArrayList; import java.util.List; import java.util.Collections; /** * Parser for spreadsheet formulas * @author Antti Villberg */ public class SheetFormulaParser { } PARSER_END(SheetFormulaParser) /*** Lexer *********************************************************/ SKIP: { | | } TOKEN: { ";" | "(" | ")" | "?" | "[" | "]" | "{" | "}" | "|" | "&" | "+" | "*" | "/" | "^" | "," | ".." | "." | "=" | "<" | ">" | "<>" | "true" | "false" | "null" | "TRUE" | "FALSE" | < #LETTER: [ "\u0024", //DOLLAR SIGN: milreis, escudo "\u0041"-"\u005a", //LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z "\u005f", //LOW LINE: spacing underscore "\u0061"-"\u007a", //LATIN SMALL LETTER A - LATIN SMALL LETTER Z "\u00aa"-"\u00ad", // 00AA FEMININE ORDINAL INDICATOR: spanish // 00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK: left guillemet // 00AC NOT SIGN: angled dash // 00AD SOFT HYPHEN: discretionary hyphen "\u00b5"-"\u00b6", // 00B5 MICRO SIGN: greek small letter mu // 00B6 PILCROW SIGN: paragraph sign "\u00ba"-"\u00bb", // 00BA MASCULINE ORDINAL INDICATOR: spanish // 00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK : right guillemet "\u00c0"-"\u00d6", //LATIN CAPITAL LETTER A WITH GRAVE - LATIN CAPITAL LETTER O WITH DIAERESIS "\u00d8"-"\u00f6", //LATIN CAPITAL LETTER O WITH STROKE - LATIN SMALL LETTER O WITH DIAERESIS "\u00f8"-"\u00ff", //LATIN SMALL LETTER O WITH STROKE - LATIN SMALL LETTER Y WITH DIAERESIS "\u0100"-"\u1fff", //LATIN CAPITAL LETTER A WITH MACRON - GREEK DASIA:reversed comma "\u3040"-"\u318f", //Hiragana - Hangul "\u3300"-"\u337f", //Squared Katakana "\u3400"-"\u3d2d", //CJK Unified Ideographs Extension A "\u4e00"-"\u9fff", //CJK Unified Ideographs "\uf900"-"\ufaff", //CJK Compatibility Ideographs "\ufb00"-"\ufb06", //LATIN SMALL LIGATURE FF -LATIN SMALL LIGATURE ST "\ufb13"-"\ufb17", //ARMENIAN SMALL LIGATURE MEN NOW - ARMENIAN SMALL LIGATURE MEN XEH "\ufb1f"-"\ufb28", //HEBREW LIGATURE YIDDISH YOD YOD PATAH -HEBREW LETTER WIDE TAV "\ufb2a"-"\ufb36", //HEBREW LETTER SHIN WITH SHIN DOT - HEBREW LETTER ZAYIN WITH DAGESH "\ufb38"-"\ufb3e", //HEBREW LETTER TET WITH DAGESH - HEBREW LETTER MEM WITH DAGESH "\ufb40"-"\ufb41", //HEBREW LETTER NUN WITH DAGESH - HEBREW LETTER SAMEKH WITH DAGESH "\ufb43"-"\ufb44", //HEBREW LETTER FINAL PE WITH DAGESH - HEBREW LETTER PE WITH DAGESH "\ufb46"-"\ufb4f", //HEBREW LETTER TSADI WITH DAGESH - HEBREW LIGATURE ALEF LAMED "\ufb50"-"\ufdd7", //Arabic Presentation Forms(A) - ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM "\ufdf0"-"\ufdfd", //ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM -ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM "\ufe70"-"\ufefc", //Arabic Presentation Forms(B) - ARABIC LIGATURE LAM WITH ALEF FINAL FORM "\uff1f"-"\uff3a", //FULLWIDTH QUESTION MARK - FULLWIDTH LATIN CAPITAL LETTER Z "\uff3f"-"\uff5e", //FULLWIDTH LOW LINE - FULLWIDTH TILDE "\uff61"-"\uffbe", //Halfwidth CJK punctuation:HALFWIDTH IDEOGRAPHIC FULL STOP - HALFWIDTH HANGUL LETTER HIEUH "\uffc2"-"\uffc7", //HALFWIDTH HANGUL LETTER A - HALFWIDTH HANGUL LETTER E "\uffca"-"\uffcf", //HALFWIDTH HANGUL LETTER YEO - HALFWIDTH HANGUL LETTER OE "\uffd2"-"\uffd7", //HALFWIDTH HANGUL LETTER YO - HALFWIDTH HANGUL LETTER YU "\uffda"-"\uffdc" //HALFWIDTH HANGUL LETTER EU - HALFWIDTH HANGUL LETTER I ] > | <#ALPHANUM: < LETTER > | ["0"-"9"] > | { matchedToken.image = SheetParserUtils.unescape( matchedToken.image.substring(1,matchedToken.image.length()-1)); } | { matchedToken.image = SheetParserUtils.unescape( matchedToken.image.substring(1,matchedToken.image.length()-1)); } | { matchedToken.image = matchedToken.image.substring(3,matchedToken.image.length()-3); } | | <#CELL_RANGE_PART: (["$"]){0,1}(["A"-"Z"]){1,5}(["$"]){0,1}(["0"-"9"]){0,5} > | [":"] > | (< ALPHANUM >)* > | <#POSITIVE_INTEGER: (["0"-"9"])+ > | "." (["e","E"] )? | "." (["e","E"] )? | ["e","E"] ) > | > } AstValue primary() : { Token tok; AstValue temp; AstRange tempRange; } { "null" { return AstNull.NULL; } | "true" { return AstBoolean.TRUE; } | "false" { return AstBoolean.FALSE; } | "TRUE" { return AstBoolean.TRUE; } | "FALSE" { return AstBoolean.FALSE; } | { return new AstString(token.image); } | { return new AstString(token.image); } | { return new AstDouble(token.image); } | { return new AstInteger(Integer.parseInt(token.image)); } | LOOKAHEAD(2) (tok = | tok = ) "!" tempRange = range() { return tempRange.inSheet(tok.image); } | LOOKAHEAD(2) temp = apply() { return temp; } | "(" temp = relation() ")" { return temp; } | temp = range() { return temp; } | temp = array() { return temp; } | { return new AstIdentifier(token.image); } } AstApply apply() : { AstArgList al; Token tok; } { LOOKAHEAD(3) tok = "(" ")" { return new AstApply(tok.image, null); } | tok = "(" al = arglist() ")" { return new AstApply(tok.image, al); } } AstValue array() : { AstArray arr = new AstArray(); AstValue temp; } { LOOKAHEAD(2) "{" "}" { return new AstArray(); } | "{" temp = relation() { arr.add(temp); } "," ( temp = relation() { arr.add(temp); } )* "}" { return arr; } } AstRange range() : { Token temp1; Token temp2; } { LOOKAHEAD(2) { return new AstRange(token.image); } | { return new AstRange(token.image); } | "#REF!" { return AstRange.REF; } } AstArgList arglist() : { AstArgList ret = new AstArgList(); AstValue temp; } { temp = relation() { ret.add(temp); } ( (";"|",") { temp = AstNothing.INSTANCE; } (temp = relation())? { ret.add(temp); } )* { return ret; } } AstValue relation() : { AstRelation ret; String op; AstValue ex; } { ex = arithmetic_expression() { ret = new AstRelation(ex); } ( op = rel_op() ex = arithmetic_expression() { ret.setRight(op, ex); } )? { return ret.simplify(); } } String rel_op() : { } { "<" { return "< ";} | "<=" { return "<=";} | ">" { return " >";} | ">=" { return " >=";} | "=" { return "=";} | "<>" { return "<>";} } // AstValue arithmetic_expression() : { AstArithmeticExpression ret; String op = null; AstValue temp; } { (op = add_op())? temp = term() { ret = new AstArithmeticExpression(op, temp); } ( LOOKAHEAD(2) op = add_op() temp = term() { ret.add(op, temp); } )* { return ret.simplify(); } } String add_op() : { } { "+" { return "+";} | "-" { return "-";} | "&" { return "&";} } AstValue term() : { AstTerm ret; String op; AstValue temp; } { temp = factor() { ret = new AstTerm(temp); } (op = mul_op() temp = factor() { ret.add(op, temp); } )* { return ret.simplify(); } } String mul_op() : { } { "*" { return "*";} | "/" { return "/";} } AstValue factor() : { AstFactor ret; String op; AstValue temp; } { temp = primary() { ret = new AstFactor(temp); } (op = factor_op() temp = primary() { ret.add(op, temp); } )* { return ret.simplify(); } } String factor_op() : { } { "^" { return "^";} }