613 lines
15 KiB
C#
613 lines
15 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace CPF.ReoGrid.Formula
|
|
{
|
|
internal static class Parser
|
|
{
|
|
public static STNode Parse(IWorkbook workbook, Cell cell, string input)
|
|
{
|
|
ExcelFormulaLexer excelFormulaLexer = new ExcelFormulaLexer(workbook, cell, input);
|
|
STNode result = Parser.ReadExpr(excelFormulaLexer);
|
|
bool flag = excelFormulaLexer.CurrentToken != null && excelFormulaLexer.CurrentToken.Success;
|
|
if (flag)
|
|
{
|
|
throw Parser.CreateException(excelFormulaLexer, "unexpect token: " + excelFormulaLexer.CurrentToken.Value);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static STNode ReadExpr(ExcelFormulaLexer lexer)
|
|
{
|
|
return Parser.ReadCompare(lexer);
|
|
}
|
|
|
|
private static STNode ReadCompare(ExcelFormulaLexer lexer)
|
|
{
|
|
STNode stnode = Parser.ReadConnect(lexer);
|
|
bool flag = stnode == null;
|
|
STNode result;
|
|
if (flag)
|
|
{
|
|
result = null;
|
|
}
|
|
else
|
|
{
|
|
bool flag2 = lexer.IsToken("=") || lexer.IsToken("==");
|
|
STNodeType type;
|
|
if (flag2)
|
|
{
|
|
type = STNodeType.EQUALS;
|
|
}
|
|
else
|
|
{
|
|
bool flag3 = lexer.IsToken("<>") || lexer.IsToken("!=");
|
|
if (flag3)
|
|
{
|
|
type = STNodeType.NOT_EQUALS;
|
|
}
|
|
else
|
|
{
|
|
bool flag4 = lexer.IsToken(">");
|
|
if (flag4)
|
|
{
|
|
type = STNodeType.GREAT_THAN;
|
|
}
|
|
else
|
|
{
|
|
bool flag5 = lexer.IsToken("<");
|
|
if (flag5)
|
|
{
|
|
type = STNodeType.LESS_THAN;
|
|
}
|
|
else
|
|
{
|
|
bool flag6 = lexer.IsToken(">=");
|
|
if (flag6)
|
|
{
|
|
type = STNodeType.GREAT_EQUALS;
|
|
}
|
|
else
|
|
{
|
|
bool flag7 = lexer.IsToken("<=");
|
|
if (!flag7)
|
|
{
|
|
return stnode;
|
|
}
|
|
type = STNodeType.LESS_EQUALS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
lexer.NextToken();
|
|
STNode stnode2 = Parser.ReadExpr(lexer);
|
|
bool flag8 = stnode2 == null;
|
|
if (flag8)
|
|
{
|
|
throw Parser.CreateException(lexer, "expect expression");
|
|
}
|
|
stnode = Parser.CreateNode(lexer, type, stnode.Start, lexer.CommittedLength - stnode.Start, new List<STNode>
|
|
{
|
|
stnode,
|
|
stnode2
|
|
});
|
|
result = stnode;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
internal static STNode ParseInterCompareExp(Cell cell, string input)
|
|
{
|
|
ExcelFormulaLexer excelFormulaLexer = new ExcelFormulaLexer((cell.Worksheet == null) ? null : cell.Worksheet.workbook, cell, input);
|
|
STNodeType stnodeType = STNodeType.NONE;
|
|
bool flag = excelFormulaLexer.IsToken("=") || excelFormulaLexer.IsToken("==");
|
|
if (flag)
|
|
{
|
|
stnodeType = STNodeType.EQUALS;
|
|
}
|
|
else
|
|
{
|
|
bool flag2 = excelFormulaLexer.IsToken("<>") || excelFormulaLexer.IsToken("!=");
|
|
if (flag2)
|
|
{
|
|
stnodeType = STNodeType.NOT_EQUALS;
|
|
}
|
|
else
|
|
{
|
|
bool flag3 = excelFormulaLexer.IsToken(">");
|
|
if (flag3)
|
|
{
|
|
stnodeType = STNodeType.GREAT_THAN;
|
|
}
|
|
else
|
|
{
|
|
bool flag4 = excelFormulaLexer.IsToken("<");
|
|
if (flag4)
|
|
{
|
|
stnodeType = STNodeType.LESS_THAN;
|
|
}
|
|
else
|
|
{
|
|
bool flag5 = excelFormulaLexer.IsToken(">=");
|
|
if (flag5)
|
|
{
|
|
stnodeType = STNodeType.GREAT_EQUALS;
|
|
}
|
|
else
|
|
{
|
|
bool flag6 = excelFormulaLexer.IsToken("<=");
|
|
if (flag6)
|
|
{
|
|
stnodeType = STNodeType.LESS_EQUALS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
bool flag7 = stnodeType > STNodeType.NONE;
|
|
if (flag7)
|
|
{
|
|
excelFormulaLexer.NextToken();
|
|
STNode stnode = Parser.ReadExpr(excelFormulaLexer);
|
|
bool flag8 = stnode != null;
|
|
if (flag8)
|
|
{
|
|
return Parser.CreateNode(excelFormulaLexer, stnodeType, 0, excelFormulaLexer.CommittedLength, new List<STNode>
|
|
{
|
|
null,
|
|
stnode
|
|
});
|
|
}
|
|
}
|
|
STNode stnode2 = Parser.ReadConnect(excelFormulaLexer);
|
|
return new STNode(STNodeType.EQUALS, 0, input.Length, new List<STNode>
|
|
{
|
|
null,
|
|
(stnode2 != null && stnode2.Type != STNodeType.IDENTIFIER) ? stnode2 : new STStringNode(input, 0, input.Length)
|
|
});
|
|
}
|
|
|
|
private static STNode ReadConnect(ExcelFormulaLexer lexer)
|
|
{
|
|
STNode stnode = Parser.ReadAdd(lexer);
|
|
bool flag = stnode == null;
|
|
STNode result;
|
|
if (flag)
|
|
{
|
|
result = null;
|
|
}
|
|
else
|
|
{
|
|
while (lexer.SkipToken("&"))
|
|
{
|
|
STNode stnode2 = Parser.ReadAdd(lexer);
|
|
bool flag2 = stnode2 == null;
|
|
if (flag2)
|
|
{
|
|
throw Parser.CreateException(lexer, "expect expression");
|
|
}
|
|
stnode = Parser.CreateNode(lexer, STNodeType.CONNECT, stnode.Start, lexer.CommittedLength - stnode.Start, new List<STNode>
|
|
{
|
|
stnode,
|
|
stnode2
|
|
});
|
|
}
|
|
result = stnode;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static STNode ReadAdd(ExcelFormulaLexer lexer)
|
|
{
|
|
STNode stnode = Parser.ReadMul(lexer);
|
|
bool flag = stnode == null;
|
|
if (!flag)
|
|
{
|
|
for (;;)
|
|
{
|
|
bool flag2 = lexer.IsToken("+");
|
|
STNodeType type;
|
|
if (flag2)
|
|
{
|
|
type = STNodeType.ADD;
|
|
}
|
|
else
|
|
{
|
|
bool flag3 = lexer.IsToken("-");
|
|
if (!flag3)
|
|
{
|
|
break;
|
|
}
|
|
type = STNodeType.SUB;
|
|
}
|
|
lexer.NextToken();
|
|
STNode stnode2 = Parser.ReadMul(lexer);
|
|
bool flag4 = stnode2 == null;
|
|
if (flag4)
|
|
{
|
|
goto Block_4;
|
|
}
|
|
stnode = Parser.CreateNode(lexer, type, stnode.Start, lexer.CommittedLength - stnode.Start, new List<STNode>
|
|
{
|
|
stnode,
|
|
stnode2
|
|
});
|
|
}
|
|
return stnode;
|
|
Block_4:
|
|
throw Parser.CreateException(lexer, "expect expression");
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private static STNode ReadMul(ExcelFormulaLexer lexer)
|
|
{
|
|
STNode stnode = Parser.ReadExponent(lexer);
|
|
bool flag = stnode == null;
|
|
if (!flag)
|
|
{
|
|
for (;;)
|
|
{
|
|
bool flag2 = lexer.IsToken("*");
|
|
STNodeType type;
|
|
if (flag2)
|
|
{
|
|
type = STNodeType.MUL;
|
|
}
|
|
else
|
|
{
|
|
bool flag3 = lexer.IsToken("/");
|
|
if (!flag3)
|
|
{
|
|
break;
|
|
}
|
|
type = STNodeType.DIV;
|
|
}
|
|
lexer.NextToken();
|
|
STNode stnode2 = Parser.ReadExponent(lexer);
|
|
bool flag4 = stnode2 == null;
|
|
if (flag4)
|
|
{
|
|
goto Block_4;
|
|
}
|
|
stnode = Parser.CreateNode(lexer, type, stnode.Start, lexer.CommittedLength - stnode.Start, new List<STNode>
|
|
{
|
|
stnode,
|
|
stnode2
|
|
});
|
|
}
|
|
return stnode;
|
|
Block_4:
|
|
throw Parser.CreateException(lexer, "expect expression");
|
|
}
|
|
return stnode;
|
|
}
|
|
|
|
private static STNode ReadExponent(ExcelFormulaLexer lexer)
|
|
{
|
|
STNode stnode = Parser.ReadPercent(lexer);
|
|
bool flag = stnode == null;
|
|
STNode result;
|
|
if (flag)
|
|
{
|
|
result = stnode;
|
|
}
|
|
else
|
|
{
|
|
while (lexer.SkipToken("^"))
|
|
{
|
|
STNode stnode2 = Parser.ReadPercent(lexer);
|
|
bool flag2 = stnode2 == null;
|
|
if (flag2)
|
|
{
|
|
throw Parser.CreateException(lexer, "expect expression");
|
|
}
|
|
stnode = Parser.CreateNode(lexer, STNodeType.POW, stnode.Start, lexer.CommittedLength - stnode.Start, new List<STNode>
|
|
{
|
|
stnode,
|
|
stnode2
|
|
});
|
|
}
|
|
result = stnode;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static STNode ReadPercent(ExcelFormulaLexer lexer)
|
|
{
|
|
STNode stnode = Parser.ReadMinus(lexer);
|
|
bool flag = stnode == null;
|
|
STNode result;
|
|
if (flag)
|
|
{
|
|
result = null;
|
|
}
|
|
else
|
|
{
|
|
while (lexer.SkipToken("%"))
|
|
{
|
|
stnode = Parser.CreateNode(lexer, STNodeType.UNARY_PERCENT, stnode.Start, lexer.CommittedLength - stnode.Start, new List<STNode>
|
|
{
|
|
stnode
|
|
});
|
|
}
|
|
result = stnode;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static STNode ReadMinus(ExcelFormulaLexer lexer)
|
|
{
|
|
bool flag = !lexer.IsToken("-");
|
|
STNode result;
|
|
if (flag)
|
|
{
|
|
result = Parser.ReadFunctionCall(lexer);
|
|
}
|
|
else
|
|
{
|
|
int index = lexer.Index;
|
|
lexer.NextToken();
|
|
STNode stnode = Parser.ReadFunctionCall(lexer);
|
|
bool flag2 = stnode == null;
|
|
if (flag2)
|
|
{
|
|
throw Parser.CreateException(lexer, "expect expression");
|
|
}
|
|
result = Parser.CreateNode(lexer, STNodeType.UNARY_MINUS, index, lexer.CommittedLength - index, new List<STNode>
|
|
{
|
|
stnode
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static STNode ReadFunctionCall(ExcelFormulaLexer lexer)
|
|
{
|
|
STNode stnode = Parser.ReadSheetName(lexer);
|
|
bool flag = stnode == null;
|
|
STNode result;
|
|
if (flag)
|
|
{
|
|
result = null;
|
|
}
|
|
else
|
|
{
|
|
bool flag2 = stnode.Type == STNodeType.CELL;
|
|
string name;
|
|
if (flag2)
|
|
{
|
|
Group group;
|
|
bool flag3 = lexer.CurrentToken == null || (group = lexer.CurrentToken.Groups["token"]) == null || !group.Success || group.Value != "(";
|
|
if (flag3)
|
|
{
|
|
return stnode;
|
|
}
|
|
name = lexer.Input.Substring(stnode.Start, stnode.Length);
|
|
lexer.NextToken();
|
|
}
|
|
else
|
|
{
|
|
bool flag4 = stnode.Type != STNodeType.IDENTIFIER || !lexer.SkipToken("(");
|
|
if (flag4)
|
|
{
|
|
return stnode;
|
|
}
|
|
name = ((STIdentifierNode)stnode).Identifier;
|
|
}
|
|
List<STNode> children = Parser.ReadParameterList(lexer);
|
|
bool flag5 = !lexer.SkipToken(")");
|
|
if (flag5)
|
|
{
|
|
throw Parser.CreateException(lexer, "expect )");
|
|
}
|
|
result = new STFunctionNode(name, stnode.Start, lexer.CommittedLength - stnode.Start, children);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static List<STNode> ReadParameterList(ExcelFormulaLexer lexer)
|
|
{
|
|
List<STNode> list = new List<STNode>();
|
|
int num = 0;
|
|
bool flag;
|
|
do
|
|
{
|
|
STNode item = Parser.ReadExpr(lexer);
|
|
list.Add(item);
|
|
num++;
|
|
flag = !lexer.SkipToken(FormulaExtension.ParameterSeparator);
|
|
}
|
|
while (!flag);
|
|
while (list.Count > 0 && list[list.Count - 1] == null)
|
|
{
|
|
list.RemoveAt(list.Count - 1);
|
|
}
|
|
return (list.Count == 0) ? null : list;
|
|
}
|
|
|
|
private static STNode ReadSheetName(ExcelFormulaLexer lexer)
|
|
{
|
|
STNode stnode = Parser.ReadPrimary(lexer);
|
|
bool flag = stnode == null;
|
|
STNode result;
|
|
if (flag)
|
|
{
|
|
result = null;
|
|
}
|
|
else
|
|
{
|
|
bool flag2 = stnode.Type != STNodeType.IDENTIFIER;
|
|
if (flag2)
|
|
{
|
|
result = stnode;
|
|
}
|
|
else
|
|
{
|
|
bool flag3 = lexer.SkipToken("!");
|
|
if (flag3)
|
|
{
|
|
STNode stnode2 = Parser.ReadPrimary(lexer);
|
|
bool flag4 = stnode2.Type != STNodeType.CELL && stnode2.Type != STNodeType.RANGE && stnode2.Type != STNodeType.IDENTIFIER;
|
|
if (flag4)
|
|
{
|
|
throw Parser.CreateException(lexer, "expect Cell/Range/Name reference");
|
|
}
|
|
string identifier = ((STIdentifierNode)stnode).Identifier;
|
|
IWorkbook workbook = lexer.Workbook;
|
|
bool flag5 = workbook == null && lexer.Cell != null && lexer.Cell.Worksheet != null && lexer.Cell.Worksheet.workbook != null;
|
|
if (flag5)
|
|
{
|
|
workbook = lexer.Cell.Worksheet.workbook;
|
|
}
|
|
bool flag6 = workbook != null;
|
|
if (flag6)
|
|
{
|
|
switch (stnode2.Type)
|
|
{
|
|
case STNodeType.IDENTIFIER:
|
|
{
|
|
STIdentifierNode stidentifierNode = (STIdentifierNode)stnode2;
|
|
stidentifierNode.Worksheet = workbook.GetWorksheetByName(identifier);
|
|
break;
|
|
}
|
|
case STNodeType.RANGE:
|
|
{
|
|
STRangeNode strangeNode = (STRangeNode)stnode2;
|
|
strangeNode.Worksheet = workbook.GetWorksheetByName(identifier);
|
|
break;
|
|
}
|
|
case STNodeType.CELL:
|
|
{
|
|
STCellNode stcellNode = (STCellNode)stnode2;
|
|
stcellNode.Worksheet = workbook.GetWorksheetByName(identifier);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
result = stnode2;
|
|
}
|
|
else
|
|
{
|
|
bool flag7 = lexer.SkipToken(".");
|
|
if (flag7)
|
|
{
|
|
STNode stnode3 = Parser.ReadPrimary(lexer);
|
|
bool flag8 = stnode3.Type != STNodeType.IDENTIFIER;
|
|
if (flag8)
|
|
{
|
|
throw Parser.CreateException(lexer, "expect identifier");
|
|
}
|
|
result = stnode3;
|
|
}
|
|
else
|
|
{
|
|
result = stnode;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static STNode ReadPrimary(ExcelFormulaLexer lexer)
|
|
{
|
|
STNode stnode;
|
|
bool flag = Parser.CommitMatchNode(lexer, "string", STNodeType.STRING, out stnode) || Parser.CommitMatchNode(lexer, "identifier", STNodeType.IDENTIFIER, out stnode) || Parser.CommitMatchNode(lexer, "number", STNodeType.NUMBER, out stnode) || Parser.CommitMatchNode(lexer, "cell", STNodeType.CELL, out stnode) || Parser.CommitMatchNode(lexer, "range", STNodeType.RANGE, out stnode) || Parser.CommitMatchNode(lexer, "true", STNodeType.TRUE, out stnode) || Parser.CommitMatchNode(lexer, "false", STNodeType.FALSE, out stnode) || Parser.CommitMatchNode(lexer, "union_ranges", STNodeType.INTERSECTION, out stnode);
|
|
STNode result;
|
|
if (flag)
|
|
{
|
|
result = stnode;
|
|
}
|
|
else
|
|
{
|
|
bool flag2 = lexer.IsToken("(");
|
|
if (flag2)
|
|
{
|
|
int index = lexer.Index;
|
|
lexer.NextToken();
|
|
STNode stnode2 = Parser.ReadExpr(lexer);
|
|
bool flag3 = stnode2 == null;
|
|
if (flag3)
|
|
{
|
|
throw Parser.CreateException(lexer, "expect expression");
|
|
}
|
|
bool flag4 = !lexer.SkipToken(")");
|
|
if (flag4)
|
|
{
|
|
throw Parser.CreateException(lexer, "expect )");
|
|
}
|
|
result = Parser.CreateNode(lexer, STNodeType.SUB_EXPR, index, lexer.CommittedLength - index, new List<STNode>
|
|
{
|
|
stnode2
|
|
});
|
|
}
|
|
else
|
|
{
|
|
result = null;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static FormulaParseException CreateException(ExcelFormulaLexer lexer, string msg)
|
|
{
|
|
return new FormulaParseException(msg, lexer.CommittedLength);
|
|
}
|
|
|
|
private static bool CommitMatchNode(ExcelFormulaLexer lexer, string groupName, STNodeType type, out STNode node)
|
|
{
|
|
bool flag = lexer.IsMatch(groupName);
|
|
bool result;
|
|
if (flag)
|
|
{
|
|
Group group = lexer.CurrentToken.Groups[groupName];
|
|
node = Parser.CommitRunAndCreateNode(lexer, type, group.Index, group.Length, null);
|
|
result = true;
|
|
}
|
|
else
|
|
{
|
|
node = null;
|
|
result = false;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static STNode CommitRunAndCreateNode(ExcelFormulaLexer lexer, STNodeType type, int start, int len, List<STNode> nodes)
|
|
{
|
|
lexer.NextToken();
|
|
return Parser.CreateNode(lexer, type, start, len, nodes);
|
|
}
|
|
|
|
private static STNode CreateNode(ExcelFormulaLexer lexer, STNodeType type)
|
|
{
|
|
return new STNode(type, lexer.CurrentToken.Index, lexer.CurrentToken.Length, null);
|
|
}
|
|
|
|
private static STNode CreateNode(ExcelFormulaLexer lexer, STNodeType type, int start, int len, List<STNode> nodes)
|
|
{
|
|
switch (type)
|
|
{
|
|
case STNodeType.NUMBER:
|
|
{
|
|
string s = lexer.Input.Substring(start, len);
|
|
double value;
|
|
return double.TryParse(s, out value) ? new STNumberNode(value, start, len) : null;
|
|
}
|
|
case STNodeType.STRING:
|
|
return new STStringNode(lexer.Input, start, len);
|
|
case STNodeType.IDENTIFIER:
|
|
return new STIdentifierNode((lexer.Cell == null) ? null : lexer.Cell.Worksheet, lexer.Input.Substring(start, len), start, len);
|
|
case STNodeType.RANGE:
|
|
return new STRangeNode(null, new RangePosition(lexer.Input.Substring(start, len)), start, len);
|
|
case STNodeType.CELL:
|
|
return new STCellNode(null, new CellPosition(lexer.Input.Substring(start, len)), type, start, len);
|
|
}
|
|
return new STNode(type, start, len, nodes);
|
|
}
|
|
}
|
|
}
|