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;
|
private TNode _root;
|
||||||
|
|
||||||
|
public HashSet<TNode> AllNodes
|
||||||
|
{
|
||||||
|
get { return _allToken; }
|
||||||
|
}
|
||||||
|
|
||||||
public int Count
|
public int Count
|
||||||
{
|
{
|
||||||
get { return _allToken.Count; }
|
get { return _allToken.Count; }
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ namespace StgSharp.RegularAnalysis.Abstraction
|
|||||||
public int OperatorInDepthCount
|
public int OperatorInDepthCount
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => _operators.Count - _depthMarks.Peek().OperandPos;
|
get => _operators.Count - _depthMarks.Peek().OperatorPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Depth
|
public int Depth
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ namespace StgSharp.RegularAnalysis.Abstraction
|
|||||||
|
|
||||||
TNode Right { get; set; }
|
TNode Right { get; set; }
|
||||||
|
|
||||||
|
TNode Parent { get; set; }
|
||||||
|
|
||||||
static abstract TNode Empty { get; }
|
static abstract TNode Empty { get; }
|
||||||
|
|
||||||
Token<TLabel> Source { get; }
|
Token<TLabel> Source { get; }
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
|
|||||||
get;
|
get;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
field?.Parent = null;
|
||||||
field = value;
|
field = value;
|
||||||
value.Parent = this;
|
value.Parent = this;
|
||||||
}
|
}
|
||||||
@@ -76,6 +77,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
|
|||||||
get;
|
get;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
field?.Parent = null;
|
||||||
field = value;
|
field = value;
|
||||||
value.Parent = this;
|
value.Parent = this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,42 +41,59 @@ namespace StgSharp.RegularAnalysis.TextRegex
|
|||||||
private AbstractSyntaxTree<RegexAstNode, RegexElementLabel> _tree = new();
|
private AbstractSyntaxTree<RegexAstNode, RegexElementLabel> _tree = new();
|
||||||
|
|
||||||
private CompileStack<RegexAstNode, RegexElementLabel> _stack = new();
|
private CompileStack<RegexAstNode, RegexElementLabel> _stack = new();
|
||||||
|
private string _source;
|
||||||
|
|
||||||
public AbstractSyntaxTree<RegexAstNode, RegexElementLabel> Analyze(
|
public static AbstractSyntaxTree<RegexAstNode, RegexElementLabel> Interpret(
|
||||||
string regex
|
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());
|
TokenParser<RegexElementLabel, RegexElementLabel> lexer = reader.Pipe(() => new RegexTokenParser());
|
||||||
|
|
||||||
while (lexer.TryReadToken(out Token<RegexElementLabel> token))
|
while (lexer.TryReadToken(out Token<RegexElementLabel> token))
|
||||||
{
|
{
|
||||||
if ((token.Flag & RegexElementLabel.SEQUENCE) != 0)
|
if ((token.Flag & RegexElementLabel.SEQUENCE) != 0)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Unit {token.Value}");
|
|
||||||
|
|
||||||
// char or charset
|
// char or charset
|
||||||
|
Console.WriteLine($"Unit {token.Value}");
|
||||||
_stack.PushOperand(new RegexAstNode(token));
|
_stack.PushOperand(new RegexAstNode(token));
|
||||||
} else if ((token.Flag & RegexElementLabel.GROUP_BEGIN) != 0)
|
} else if ((token.Flag & RegexElementLabel.GROUP_BEGIN) != 0)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Group begin {token.Value}");
|
Console.WriteLine($"Group begin {token.Value}");
|
||||||
|
_stack.PushOperator(new RegexAstNode(token));
|
||||||
_stack.IncreaseDepth(0);
|
_stack.IncreaseDepth(0);
|
||||||
|
Console.WriteLine(/**/_stack.OperatorInDepthCount/**/);
|
||||||
} else if ((token.Flag & RegexElementLabel.GROUP_END) != 0)
|
} else if ((token.Flag & RegexElementLabel.GROUP_END) != 0)
|
||||||
{
|
{
|
||||||
|
// close all nodes here
|
||||||
Console.WriteLine($"Group end {token.Value}");
|
Console.WriteLine($"Group end {token.Value}");
|
||||||
|
RegexAstNode op;
|
||||||
// TODO: close all nodes here
|
while (_stack.TryPopOperator(out op)) {
|
||||||
while (_stack.TryPopOperator(out RegexAstNode? op))
|
|
||||||
{
|
|
||||||
ProcessOperator(op);
|
ProcessOperator(op);
|
||||||
}
|
}
|
||||||
if (_stack.OperandInDepthCount != 1) {
|
if (_stack.OperandInDepthCount != 1) {
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
_stack.DecreaseDepth();
|
_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)
|
} 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)
|
if (_stack.OperatorInDepthCount == 0)
|
||||||
{
|
{
|
||||||
// the first operator in stack
|
// the first operator in stack
|
||||||
@@ -117,13 +134,35 @@ namespace StgSharp.RegularAnalysis.TextRegex
|
|||||||
if (_stack.OperandInDepthCount == 1 && _stack.OperatorInDepthCount == 0)
|
if (_stack.OperandInDepthCount == 1 && _stack.OperatorInDepthCount == 0)
|
||||||
{
|
{
|
||||||
_tree.Root = _stack.PopOperand();
|
_tree.Root = _stack.PopOperand();
|
||||||
return _tree;
|
return;
|
||||||
}
|
}
|
||||||
throw new InvalidOperationException("Invalid regular expression syntax.");
|
throw new InvalidOperationException("Invalid regular expression syntax.");
|
||||||
}
|
}
|
||||||
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(
|
private void ProcessOperator(
|
||||||
RegexAstNode op
|
RegexAstNode op
|
||||||
)
|
)
|
||||||
@@ -134,19 +173,12 @@ namespace StgSharp.RegularAnalysis.TextRegex
|
|||||||
if (_stack.TryPopOperand(out RegexAstNode? _1) &&
|
if (_stack.TryPopOperand(out RegexAstNode? _1) &&
|
||||||
_stack.TryPopOperand(out RegexAstNode? _2))
|
_stack.TryPopOperand(out RegexAstNode? _2))
|
||||||
{
|
{
|
||||||
if (RegexAstNode.TryMergeUnit(_2, _1, out RegexAstNode? _3))
|
op.Left = _2;
|
||||||
{
|
op.Right = _1;
|
||||||
_stack.PushOperand(_3);
|
_stack.PushOperand(op);
|
||||||
_tree.AddNode(_3);
|
_tree.AddNode(op);
|
||||||
} else
|
_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
|
} else
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Insufficient operands for CONCAT operator.");
|
throw new InvalidOperationException("Insufficient operands for CONCAT operator.");
|
||||||
|
|||||||
Reference in New Issue
Block a user