regex interpreter now can build partial correct AST (i forget groups), but in bad shape. building an optimizer.
This commit is contained in:
@@ -43,6 +43,11 @@ namespace StgSharp.RegularAnalysis.Abstraction
|
||||
|
||||
private TNode _root;
|
||||
|
||||
public HashSet<TNode> AllNodes
|
||||
{
|
||||
get { return _allToken; }
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return _allToken.Count; }
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace StgSharp.RegularAnalysis.Abstraction
|
||||
public int OperatorInDepthCount
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _operators.Count - _depthMarks.Peek().OperandPos;
|
||||
get => _operators.Count - _depthMarks.Peek().OperatorPos;
|
||||
}
|
||||
|
||||
public int Depth
|
||||
|
||||
@@ -53,6 +53,8 @@ namespace StgSharp.RegularAnalysis.Abstraction
|
||||
|
||||
TNode Right { get; set; }
|
||||
|
||||
TNode Parent { get; set; }
|
||||
|
||||
static abstract TNode Empty { get; }
|
||||
|
||||
Token<TLabel> Source { get; }
|
||||
|
||||
@@ -66,6 +66,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
|
||||
get;
|
||||
set
|
||||
{
|
||||
field?.Parent = null;
|
||||
field = value;
|
||||
value.Parent = this;
|
||||
}
|
||||
@@ -76,6 +77,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
|
||||
get;
|
||||
set
|
||||
{
|
||||
field?.Parent = null;
|
||||
field = value;
|
||||
value.Parent = this;
|
||||
}
|
||||
|
||||
@@ -41,42 +41,59 @@ namespace StgSharp.RegularAnalysis.TextRegex
|
||||
private AbstractSyntaxTree<RegexAstNode, RegexElementLabel> _tree = new();
|
||||
|
||||
private CompileStack<RegexAstNode, RegexElementLabel> _stack = new();
|
||||
private string _source;
|
||||
|
||||
public AbstractSyntaxTree<RegexAstNode, RegexElementLabel> Analyze(
|
||||
string regex
|
||||
public static AbstractSyntaxTree<RegexAstNode, RegexElementLabel> Interpret(
|
||||
string regex
|
||||
)
|
||||
{
|
||||
RegexTokenReader reader = new RegexTokenReader(regex);
|
||||
RegexInterpreter interpreter = new RegexInterpreter();
|
||||
interpreter._source = regex;
|
||||
interpreter.Analyze();
|
||||
interpreter.OptimizeTree();
|
||||
return interpreter._tree;
|
||||
}
|
||||
|
||||
private void Analyze()
|
||||
{
|
||||
RegexTokenReader reader = new RegexTokenReader(_source);
|
||||
TokenParser<RegexElementLabel, RegexElementLabel> lexer = reader.Pipe(() => new RegexTokenParser());
|
||||
|
||||
while (lexer.TryReadToken(out Token<RegexElementLabel> token))
|
||||
{
|
||||
if ((token.Flag & RegexElementLabel.SEQUENCE) != 0)
|
||||
{
|
||||
Console.WriteLine($"Unit {token.Value}");
|
||||
|
||||
// char or charset
|
||||
Console.WriteLine($"Unit {token.Value}");
|
||||
_stack.PushOperand(new RegexAstNode(token));
|
||||
} else if ((token.Flag & RegexElementLabel.GROUP_BEGIN) != 0)
|
||||
{
|
||||
Console.WriteLine($"Group begin {token.Value}");
|
||||
_stack.PushOperator(new RegexAstNode(token));
|
||||
_stack.IncreaseDepth(0);
|
||||
Console.WriteLine(/**/_stack.OperatorInDepthCount/**/);
|
||||
} else if ((token.Flag & RegexElementLabel.GROUP_END) != 0)
|
||||
{
|
||||
// close all nodes here
|
||||
Console.WriteLine($"Group end {token.Value}");
|
||||
|
||||
// TODO: close all nodes here
|
||||
while (_stack.TryPopOperator(out RegexAstNode? op))
|
||||
{
|
||||
RegexAstNode op;
|
||||
while (_stack.TryPopOperator(out op)) {
|
||||
ProcessOperator(op);
|
||||
}
|
||||
if (_stack.OperandInDepthCount != 1) {
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
_stack.DecreaseDepth();
|
||||
op = _stack.PopOperator();
|
||||
if (op.Source.Flag != RegexElementLabel.GROUP_BEGIN) {
|
||||
throw new InvalidOperationException("Unmatched group begin and end symbol");
|
||||
}
|
||||
op.Right = _stack.PopOperand();
|
||||
_stack.PushOperand(op);
|
||||
} else if ((token.Flag & RegexElementLabel.OPERATOR) != 0)
|
||||
{
|
||||
Console.WriteLine($"Operator {token.Value} with flag {token.Flag}");
|
||||
Console.Write($"Operator {token.Value} with flag {token.Flag}, ");
|
||||
Console.WriteLine(/**/_stack.OperatorInDepthCount/**/);
|
||||
if (_stack.OperatorInDepthCount == 0)
|
||||
{
|
||||
// the first operator in stack
|
||||
@@ -117,13 +134,35 @@ namespace StgSharp.RegularAnalysis.TextRegex
|
||||
if (_stack.OperandInDepthCount == 1 && _stack.OperatorInDepthCount == 0)
|
||||
{
|
||||
_tree.Root = _stack.PopOperand();
|
||||
return _tree;
|
||||
return;
|
||||
}
|
||||
throw new InvalidOperationException("Invalid regular expression syntax.");
|
||||
}
|
||||
throw new InvalidOperationException("Invalid regular expression syntax.");
|
||||
}
|
||||
|
||||
private void OptimizeTree(
|
||||
)
|
||||
{
|
||||
// phase0P: ALT flatten
|
||||
int opCount = 0;
|
||||
do
|
||||
{
|
||||
opCount = 1;
|
||||
} while (opCount != 0);
|
||||
|
||||
// phase1: ALT merge
|
||||
opCount = 0;
|
||||
do
|
||||
{
|
||||
opCount = 1;
|
||||
} while (opCount != 0);
|
||||
|
||||
// phase2: CONCAT merge
|
||||
// phase3: scan container and remove no parent nodes
|
||||
_tree.AllNodes.RemoveWhere(node => node.Parent == null && node != _tree.Root);
|
||||
}
|
||||
|
||||
private void ProcessOperator(
|
||||
RegexAstNode op
|
||||
)
|
||||
@@ -134,19 +173,12 @@ namespace StgSharp.RegularAnalysis.TextRegex
|
||||
if (_stack.TryPopOperand(out RegexAstNode? _1) &&
|
||||
_stack.TryPopOperand(out RegexAstNode? _2))
|
||||
{
|
||||
if (RegexAstNode.TryMergeUnit(_2, _1, out RegexAstNode? _3))
|
||||
{
|
||||
_stack.PushOperand(_3);
|
||||
_tree.AddNode(_3);
|
||||
} else
|
||||
{
|
||||
op.Left = _2;
|
||||
op.Right = _1;
|
||||
_stack.PushOperand(op);
|
||||
_tree.AddNode(op);
|
||||
_tree.AddNode(_1);
|
||||
_tree.AddNode(_2);
|
||||
}
|
||||
op.Left = _2;
|
||||
op.Right = _1;
|
||||
_stack.PushOperand(op);
|
||||
_tree.AddNode(op);
|
||||
_tree.AddNode(_1);
|
||||
_tree.AddNode(_2);
|
||||
} else
|
||||
{
|
||||
throw new InvalidOperationException("Insufficient operands for CONCAT operator.");
|
||||
|
||||
Reference in New Issue
Block a user