diff --git a/StgSharp.RegularAnalysis/Abstraction/AbstractSyntaxTree.cs b/StgSharp.RegularAnalysis/Abstraction/AbstractSyntaxTree.cs index fe7f85eb..765907f8 100644 --- a/StgSharp.RegularAnalysis/Abstraction/AbstractSyntaxTree.cs +++ b/StgSharp.RegularAnalysis/Abstraction/AbstractSyntaxTree.cs @@ -33,6 +33,7 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Security.Cryptography.X509Certificates; using System.Text; +using System.Xml.Linq; using System.Xml.Schema; namespace StgSharp.RegularAnalysis.Abstraction @@ -81,122 +82,168 @@ namespace StgSharp.RegularAnalysis.Abstraction public IEnumerator GetEnumerator() { - return new Enumerator(this); + return new TreeEnumerator(this); } - private class Enumerator : IEnumerator + } + + internal class TreeEnumerator( + TNode root + ) : IEnumerator where TNode : ISyntaxNode where TType : unmanaged + { + + private bool _completed = false; + + private int _state, _target; // 0: not started, 1: on right, 2: ended + private Stack _recycle = []; + private Stack _stack = []; + + // private TNode _lRoot; + private TNode _root = root; + + internal TreeEnumerator( + AbstractSyntaxTree tree + ) + : this(tree.Root) { } + + public TNode Current + { + get + { + if (_stack.TryPeek(out Record? r)) { + return r.Node; + } + return TNode.Empty; + } + } + + public void Dispose() + { + return; + } + + public bool MoveNext() + { + if (_completed) { + return false; + } + while (_stack.TryPeek(out Record? cur)) + { + switch (cur.State) + { + case 0: + cur.State++; + if (TNode.IsNullOrEmpty(cur.Node.Left)) + { + goto case 1; + } else + { + _stack.Push(GetNewRecord(cur.Node.Left)); + return true; + } + case 1: + cur.State++; + if (TNode.IsNullOrEmpty(cur.Node.Right)) + { + goto case 2; + } else + { + _stack.Push(GetNewRecord(cur.Node.Right)); + return true; + } + case 2: + if (TNode.IsNullOrEmpty(cur.Node.Next)) + { + _recycle.Push(_stack.Pop()); + if (_stack.Count == 0) + { + _completed = true; + return false; + } + } else + { + _stack.Push(GetNewRecord(cur.Node.Next)); + return true; + } + break; + default: + break; + } + } + _stack.Push(GetNewRecord(_root)); + return true; + } + + public void Reset() + { + _completed = false; + _stack.Clear(); + _state = 0; + } + + public void SkipNode() + { + if (_stack.TryPop(out Record? r)) { + _recycle.Push(r); + } + } + + public void SkipOnce() + { + if (_stack.TryPeek(out Record? cur)) + { + switch (cur.State) + { + case 0: + cur.State++; + break; + case 1: + cur.State++; + break; + case 2: + if (TNode.IsNullOrEmpty(cur.Node.Next)) + { + _recycle.Push(_stack.Pop()); + if (_stack.Count == 0) + { + _completed = true; + return; + } + } else + { + _stack.Push(GetNewRecord(cur.Node.Next)); + } + break; + default: + break; + } + } + } + + private Record GetNewRecord( + TNode node + ) + { + if (_recycle.TryPop(out Record? r)) + { + r.State = 0; + r.Node = node; + return r; + } + return new Record(node, 0); + } + + object IEnumerator.Current => Current; + + private class Record( + TNode node, + int state + ) { - private int _state,_target; // 0: not started, 1: on right, 2: ended - private Stack _recycle; - private Stack _stack; - private TNode _lRoot; - private TNode _root; + public int State { get; set; } = state; - public Enumerator( - AbstractSyntaxTree tree - ) - { - _root = tree.Root; - _stack = []; - _recycle = []; - } - - public TNode Current - { - get - { - if (_stack.TryPeek(out Record? r)) { - return r.Node; - } - return TNode.Empty; - } - } - - public void Dispose() - { - return; - } - - public bool MoveNext() - { - while (_stack.TryPeek(out Record? cur)) - { - switch (cur.State) - { - case 0: - cur.State++; - if (TNode.IsNullOrEmpty(cur.Node.Left)) - { - goto case 1; - } else - { - _stack.Push(GetNewRecord(cur.Node.Left)); - return true; - } - case 1: - cur.State++; - if (TNode.IsNullOrEmpty(cur.Node.Right)) - { - goto case 2; - } else - { - _stack.Push(GetNewRecord(cur.Node.Right)); - return true; - } - case 2: - if (TNode.IsNullOrEmpty(cur.Node.Next)) - { - _recycle.Push(_stack.Pop()); - if (_stack.Count == 0) { - return false; - } - } else - { - _stack.Push(GetNewRecord(cur.Node.Next)); - return true; - } - break; - default: - break; - } - } - _stack.Push(GetNewRecord(_root)); - return true; - } - - public void Reset() - { - _stack.Clear(); - _state = 0; - } - - private Record GetNewRecord( - TNode node - ) - { - if (_recycle.TryPop(out Record? r)) - { - r.State = 0; - r.Node = node; - return r; - } - return new Record(node, 0); - } - - object IEnumerator.Current => Current; - - private class Record( - TNode node, - int state - ) - { - - public int State { get; set; } = state; - - public TNode Node { get; set; } = node; - - } + public TNode Node { get; set; } = node; } diff --git a/StgSharp.RegularAnalysis/TextRegex/RegexInterpreter.Optimize.cs b/StgSharp.RegularAnalysis/TextRegex/RegexInterpreter.Optimize.cs new file mode 100644 index 00000000..38f7211a --- /dev/null +++ b/StgSharp.RegularAnalysis/TextRegex/RegexInterpreter.Optimize.cs @@ -0,0 +1,53 @@ +//----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// file="RegexInterpreter.Optimize" +// Project: StgSharp +// AuthorGroup: Nitload +// Copyright (c) Nitload. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +using StgSharp.RegularAnalysis.Abstraction; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StgSharp.RegularAnalysis.TextRegex +{ + public partial class RegexInterpreter + { + + private static RegexAstNode FlattenAlt( + RegexAstNode root + ) + { + TreeEnumerator enumerator = new(root); + List cases = []; + while (enumerator.MoveNext()) + { + RegexAstNode current = enumerator.Current; + } + } + + } +} diff --git a/StgSharp.RegularAnalysis/TextRegex/RegexInterpreter.cs b/StgSharp.RegularAnalysis/TextRegex/RegexInterpreter.cs index 1cc5c746..ca8e038e 100644 --- a/StgSharp.RegularAnalysis/TextRegex/RegexInterpreter.cs +++ b/StgSharp.RegularAnalysis/TextRegex/RegexInterpreter.cs @@ -37,7 +37,7 @@ using System.Threading.Tasks; namespace StgSharp.RegularAnalysis.TextRegex { - public class RegexInterpreter + public partial class RegexInterpreter { private AbstractSyntaxTree _tree = new(); @@ -113,8 +113,11 @@ namespace StgSharp.RegularAnalysis.TextRegex if (op.Source.Flag != RegexElementLabel.GROUP_BEGIN) { throw new InvalidOperationException("Unmatched group begin and end symbol"); } - op.Right = _stack.PopOperand(); - _stack.PushOperand(op); + if (op.Source.Value.Length > 1) + { + op.Right = _stack.PopOperand(); + _stack.PushOperand(op); + } } else if ((token.Flag & RegexElementLabel.OPERATOR) != 0) { Console.Write($"Operator {token.Value} with flag {token.Flag}, "); @@ -179,27 +182,9 @@ namespace StgSharp.RegularAnalysis.TextRegex RegexAstNode node = enumerator.Current; if ((RegexElementLabel)node.NodeFlag == RegexElementLabel.ALT) { - RegexAstNode right, left = node.Left; - while (node.Right.Source.Flag == RegexElementLabel.ALT) - { - // flatten a alternation to left linked list of root ALT - right = node.Right; - RegexAstNode nextAlt = right.Left; - left.Next = nextAlt; - nextAlt.Previous = left; - nextAlt.Parent = node; - right.Left = RegexAstNode.Empty; - left = nextAlt; - - // remove the right ALT node and connect its right child to current node - node.Right = right.Right; - right.Right.Parent = node; - } - - // connect the last ALT node to the right child of current node - right = node.Right; - left.Next = right; - right.Previous = left; + RegexAstNode list = FlattenAlt(node); + node.Left = list; + node.Right = RegexAstNode.Empty; } } diff --git a/StgSharpDebug/TestRegexAnalyse.cs b/StgSharpDebug/TestRegexAnalyse.cs index bf8f29b8..96981606 100644 --- a/StgSharpDebug/TestRegexAnalyse.cs +++ b/StgSharpDebug/TestRegexAnalyse.cs @@ -38,7 +38,7 @@ namespace StgSharp public class TestRegexAnalyse { - private const string regex = @"ab[1-9]+(?abc)"; + private const string regex = @"(ab[1-9])+(?abc)"; public static void Run() {