From ed7972f1dabddd270ffca429e950868989b1e5d7 Mon Sep 17 00:00:00 2001 From: Youmu Liu <105042599+Nitload-NSI@users.noreply.github.com> Date: Fri, 6 Feb 2026 18:02:00 +0800 Subject: [PATCH] regex interpreter now can build partial correct AST (i forget groups), but in bad shape. building an optimizer. --- .../Abstraction/AbstractSyntaxTree.cs | 5 ++ .../Abstraction/CompileStack.cs | 2 +- .../Abstraction/ISyntaxNode.cs | 2 + .../TextRegex/RegexAstNode.cs | 2 + .../TextRegex/RegexInterpreter.cs | 80 +++++++++++++------ 5 files changed, 66 insertions(+), 25 deletions(-) diff --git a/StgSharp.RegularAnalysis/Abstraction/AbstractSyntaxTree.cs b/StgSharp.RegularAnalysis/Abstraction/AbstractSyntaxTree.cs index 13403696..455b57bf 100644 --- a/StgSharp.RegularAnalysis/Abstraction/AbstractSyntaxTree.cs +++ b/StgSharp.RegularAnalysis/Abstraction/AbstractSyntaxTree.cs @@ -43,6 +43,11 @@ namespace StgSharp.RegularAnalysis.Abstraction private TNode _root; + public HashSet AllNodes + { + get { return _allToken; } + } + public int Count { get { return _allToken.Count; } diff --git a/StgSharp.RegularAnalysis/Abstraction/CompileStack.cs b/StgSharp.RegularAnalysis/Abstraction/CompileStack.cs index dcb16116..680cd853 100644 --- a/StgSharp.RegularAnalysis/Abstraction/CompileStack.cs +++ b/StgSharp.RegularAnalysis/Abstraction/CompileStack.cs @@ -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 diff --git a/StgSharp.RegularAnalysis/Abstraction/ISyntaxNode.cs b/StgSharp.RegularAnalysis/Abstraction/ISyntaxNode.cs index 6db22c62..2279c1cc 100644 --- a/StgSharp.RegularAnalysis/Abstraction/ISyntaxNode.cs +++ b/StgSharp.RegularAnalysis/Abstraction/ISyntaxNode.cs @@ -53,6 +53,8 @@ namespace StgSharp.RegularAnalysis.Abstraction TNode Right { get; set; } + TNode Parent { get; set; } + static abstract TNode Empty { get; } Token Source { get; } diff --git a/StgSharp.RegularAnalysis/TextRegex/RegexAstNode.cs b/StgSharp.RegularAnalysis/TextRegex/RegexAstNode.cs index 5bc179d2..d987ec0a 100644 --- a/StgSharp.RegularAnalysis/TextRegex/RegexAstNode.cs +++ b/StgSharp.RegularAnalysis/TextRegex/RegexAstNode.cs @@ -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; } diff --git a/StgSharp.RegularAnalysis/TextRegex/RegexInterpreter.cs b/StgSharp.RegularAnalysis/TextRegex/RegexInterpreter.cs index 1ebc323b..a1b924bc 100644 --- a/StgSharp.RegularAnalysis/TextRegex/RegexInterpreter.cs +++ b/StgSharp.RegularAnalysis/TextRegex/RegexInterpreter.cs @@ -41,42 +41,59 @@ namespace StgSharp.RegularAnalysis.TextRegex private AbstractSyntaxTree _tree = new(); private CompileStack _stack = new(); + private string _source; - public AbstractSyntaxTree Analyze( - string regex + public static AbstractSyntaxTree 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 lexer = reader.Pipe(() => new RegexTokenParser()); while (lexer.TryReadToken(out Token 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.");