begin regex ir opt

This commit is contained in:
Youmu Liu
2026-06-23 20:08:33 +08:00
parent 7e5e4d1f7a
commit 2b05d626c7
10 changed files with 210 additions and 194 deletions
@@ -46,10 +46,11 @@ namespace StgSharp.RegularAnalysis.Text
Count_Set = 7,
Pop = 8,
Pack = 9,
Find_Seq = 10,
}
internal abstract class RegexHIR
internal abstract class RegexIR
{
internal abstract RegexIRCommand Command { get; }
@@ -60,12 +61,30 @@ namespace StgSharp.RegularAnalysis.Text
}
internal sealed class RegexFindSeqIR(
string pattern
) : RegexIR
{
public string Pattern { get; } = pattern;
internal override RegexIRCommand Command => RegexIRCommand.Find_Seq;
internal override string AsCommand(
int lineNum
)
{
return $"[{lineNum}]\t FIND_SEQ \"{(string.IsNullOrEmpty(Pattern) ? "<EPSILON>" : Pattern)}\"";
}
}
/// <summary>
/// Searches for a certain string pattern or charset from current position.
/// </summary>
internal sealed class RegexMatchSeqHIR(
internal sealed class RegexMatchSeqIR(
string pattern
) : RegexHIR
) : RegexIR
{
public string Pattern { get; } = pattern;
@@ -81,9 +100,9 @@ namespace StgSharp.RegularAnalysis.Text
}
internal sealed class RegexMatchSetHIR(
internal sealed class RegexMatchSetIR(
string charset
) : RegexHIR
) : RegexIR
{
public string Charset { get; } = charset;
@@ -99,10 +118,10 @@ namespace StgSharp.RegularAnalysis.Text
}
internal sealed class RegexConditionHIR(
internal sealed class RegexConditionIR(
int success,
int fail
) : RegexHIR
) : RegexIR
{
public int SuccessCase { get; } = success;
@@ -120,10 +139,10 @@ namespace StgSharp.RegularAnalysis.Text
}
internal sealed class RegexPackHIR(
internal sealed class RegexPackIR(
bool condition,
string name = ""
) : RegexHIR
) : RegexIR
{
public bool Condition { get; } = condition;
@@ -141,12 +160,12 @@ namespace StgSharp.RegularAnalysis.Text
}
internal sealed class RegexCountHIR(
internal sealed class RegexCountIR(
int min,
int max,
bool isGreedy,
int operation
) : RegexHIR
) : RegexIR
{
public bool IsGreedy { get; } = isGreedy;
@@ -168,12 +187,12 @@ namespace StgSharp.RegularAnalysis.Text
}
internal sealed class RegexCountSeqHIR(
internal sealed class RegexCountSeqIR(
int min,
int max,
bool isGreedy,
string seq
) : RegexHIR
) : RegexIR
{
public bool IsGreedy { get; } = isGreedy;
@@ -195,12 +214,12 @@ namespace StgSharp.RegularAnalysis.Text
}
internal sealed class RegexCountSetHIR(
internal sealed class RegexCountSetIR(
int min,
int max,
bool isGreedy,
string set
) : RegexHIR
) : RegexIR
{
public bool IsGreedy { get; } = isGreedy;
@@ -222,9 +241,9 @@ namespace StgSharp.RegularAnalysis.Text
}
internal sealed class RegexTryHIR(
internal sealed class RegexTryIR(
int count
) : RegexHIR
) : RegexIR
{
public int CountOfCommand { get; } = count;
@@ -240,9 +259,9 @@ namespace StgSharp.RegularAnalysis.Text
}
internal sealed class RegexPopHIR(
internal sealed class RegexPopIR(
bool isSuccess
) : RegexHIR
) : RegexIR
{
public bool IsSuccess { get; } = isSuccess;
@@ -34,13 +34,13 @@ using System.Threading.Tasks;
namespace StgSharp.RegularAnalysis.Text
{
internal class RegexHIRGenerator
internal class RegexIRGenerator
{
private Node _head = new();
private Node _tail;
public RegexHIRGenerator()
public RegexIRGenerator()
{
_tail = _head;
}
@@ -52,7 +52,7 @@ namespace StgSharp.RegularAnalysis.Text
int fail
)
{
_tail.Add(new RegexConditionHIR(success, fail));
_tail.Add(new RegexConditionIR(success, fail));
Count++;
}
@@ -63,7 +63,7 @@ namespace StgSharp.RegularAnalysis.Text
int operation
)
{
_tail.Add(new RegexCountHIR(min, max, isGreedy, operation));
_tail.Add(new RegexCountIR(min, max, isGreedy, operation));
Count++;
}
@@ -74,7 +74,7 @@ namespace StgSharp.RegularAnalysis.Text
string seq
)
{
_tail.Add(new RegexCountSeqHIR(min, max, isGreedy, seq));
_tail.Add(new RegexCountSeqIR(min, max, isGreedy, seq));
Count++;
}
@@ -85,12 +85,12 @@ namespace StgSharp.RegularAnalysis.Text
string set
)
{
_tail.Add(new RegexCountSetHIR(min, max, isGreedy, set));
_tail.Add(new RegexCountSetIR(min, max, isGreedy, set));
Count++;
}
public void EmitIRStream(
RegexHIRGenerator stream
RegexIRGenerator stream
)
{
if (stream is null || stream.Count == 0) {
@@ -105,7 +105,7 @@ namespace StgSharp.RegularAnalysis.Text
string unit
)
{
_tail.Add(new RegexMatchSeqHIR(unit));
_tail.Add(new RegexMatchSeqIR(unit));
Count++;
}
@@ -113,7 +113,7 @@ namespace StgSharp.RegularAnalysis.Text
string unit
)
{
_tail.Add(new RegexMatchSetHIR(unit));
_tail.Add(new RegexMatchSetIR(unit));
Count++;
}
@@ -122,7 +122,7 @@ namespace StgSharp.RegularAnalysis.Text
string name = ""
)
{
_tail.Add(new RegexPackHIR(condition, name));
_tail.Add(new RegexPackIR(condition, name));
Count++;
}
@@ -130,7 +130,7 @@ namespace StgSharp.RegularAnalysis.Text
bool isSuccess
)
{
_tail.Add(new RegexPopHIR(isSuccess));
_tail.Add(new RegexPopIR(isSuccess));
Count++;
}
@@ -138,13 +138,13 @@ namespace StgSharp.RegularAnalysis.Text
int count
)
{
_tail.Add(new RegexTryHIR(count));
_tail.Add(new RegexTryIR(count));
Count++;
}
public List<RegexHIR> ToList()
public List<RegexIR> ToList()
{
List<RegexHIR> result = new(Count);
List<RegexIR> result = new(Count);
Node current = _head;
while (current != null)
{
@@ -161,11 +161,11 @@ namespace StgSharp.RegularAnalysis.Text
public int Count => IRList.Count;
public List<RegexHIR> IRList { get; } = [];
public List<RegexIR> IRList { get; } = [];
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(
RegexHIR ir
RegexIR ir
)
{
IRList.Add(ir);
@@ -1,6 +1,6 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="RegexInterpreter.Optimize"
// file="RegexInterpreter.ASTOptimize"
// Project: StgSharp
// AuthorGroup: Nitload
// Copyright (c) Nitload. All rights reserved.
@@ -39,7 +39,7 @@ using System.Xml.Linq;
namespace StgSharp.RegularAnalysis.Text
{
public partial class RegexInterpreter
public partial class RegexAnalyzer
{
private static RegexAstNode FlattenAlt(
@@ -40,11 +40,11 @@ using System.Xml;
namespace StgSharp.RegularAnalysis.Text
{
public partial class RegexInterpreter
public partial class RegexAnalyzer
{
internal static List<RegexHIR> GenerateIR(
AbstractSyntaxTree<RegexAstNode, RegexElementLabel> tree
internal static List<RegexIR> GenerateIR(
AbstractSyntaxTree<RegexAstNode, RegexElementLabel> tree
)
{
return GenerateIRRecursion(tree.Root, 0).ToList();
@@ -53,7 +53,7 @@ namespace StgSharp.RegularAnalysis.Text
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void EmitCount(
int curDepth,
RegexHIRGenerator ir,
RegexIRGenerator ir,
int min,
int max,
bool isGreedy,
@@ -66,7 +66,7 @@ namespace StgSharp.RegularAnalysis.Text
if (isRightOperator) // seq to be count is complex
{
ir.EmitCount(min, max, isGreedy, 1);
RegexHIRGenerator rightIR = GenerateIRRecursion(right, curDepth + 1);
RegexIRGenerator rightIR = GenerateIRRecursion(right, curDepth + 1);
ir.EmitTry(rightIR.Count);
ir.EmitIRStream(rightIR);
} else
@@ -89,9 +89,9 @@ namespace StgSharp.RegularAnalysis.Text
}
}
private static RegexHIRGenerator GenerateIRRecursion(
RegexAstNode node,
int depth
private static RegexIRGenerator GenerateIRRecursion(
RegexAstNode node,
int depth
)
{
#pragma warning disable IDE0010
@@ -102,8 +102,8 @@ namespace StgSharp.RegularAnalysis.Text
int curDepth = depth;
RegexAstNode left = node.Left;
RegexAstNode right = node.Right;
RegexHIRGenerator leftIR;
RegexHIRGenerator rightIR;
RegexIRGenerator leftIR;
RegexIRGenerator rightIR;
Token<RegexElementLabel> token = node.Source;
@@ -119,7 +119,7 @@ namespace StgSharp.RegularAnalysis.Text
group_source[3..^1] : /* named group (?<name>) */
string.Empty; /* unnamed group (?:) */
RegexHIRGenerator groupIR = new();
RegexIRGenerator groupIR = new();
rightIR = GenerateIRRecursion(right, curDepth + 1);
groupIR.EmitTry(rightIR.Count);
groupIR.EmitIRStream(rightIR);
@@ -144,7 +144,7 @@ namespace StgSharp.RegularAnalysis.Text
_ => throw new InvalidOperationException("Unexpected sequence mask for count operator"),
};
ReadOnlySpan<char> count_source_span = count_source;
RegexHIRGenerator countIR = new();
RegexIRGenerator countIR = new();
if (count_source_span[0] == '*') // infinite count
{
@@ -185,7 +185,7 @@ namespace StgSharp.RegularAnalysis.Text
return countIR;
case RegexElementLabel.CONCAT:
RegexHIRGenerator concat = new();
RegexIRGenerator concat = new();
// process left node
if (RegexAstNode.IsNullOrEmpty(left))
@@ -238,13 +238,13 @@ namespace StgSharp.RegularAnalysis.Text
}
return concat;
case RegexElementLabel.ALT:
RegexHIRGenerator alt = new();
List<RegexHIRGenerator> casesIRList = [];
RegexIRGenerator alt = new();
List<RegexIRGenerator> casesIRList = [];
RegexAstNode cur_node = right;
int ir_count = 0;
while (!RegexAstNode.IsNullOrEmpty(cur_node))
{
RegexHIRGenerator _case = GenerateIRRecursion(cur_node, curDepth + 1);
RegexIRGenerator _case = GenerateIRRecursion(cur_node, curDepth + 1);
casesIRList.Add(_case);
ir_count += _case.Count;
cur_node = cur_node.Next;
@@ -252,7 +252,7 @@ namespace StgSharp.RegularAnalysis.Text
int case_count = casesIRList.Count;
while (case_count != 0)
{
RegexHIRGenerator cur_ir = casesIRList[^case_count];
RegexIRGenerator cur_ir = casesIRList[^case_count];
ir_count -= cur_ir.Count;
case_count--;
alt.EmitTry(cur_ir.Count);
@@ -265,11 +265,11 @@ namespace StgSharp.RegularAnalysis.Text
case RegexElementLabel.UNIT_SPAN:
goto case RegexElementLabel.UNIT;
case RegexElementLabel.UNIT:
RegexHIRGenerator unit_seq = new();
RegexIRGenerator unit_seq = new();
unit_seq.EmitMatchSeq(node.Source.Value);
return unit_seq;
case RegexElementLabel.UNIT_SET:
RegexHIRGenerator unit_set = new();
RegexIRGenerator unit_set = new();
unit_set.EmitMatchSet(node.Source.Value);
return unit_set;
default:
@@ -0,0 +1,126 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="RegexInterpreter.IROptimize"
// 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 System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StgSharp.RegularAnalysis.Text
{
public partial class RegexAnalyzer
{
internal static RegexInfo ScanAndOptimizeIR(
List<RegexIR> baseIR,
out List<RegexIR> optIR
)
{
int index = 0;
List<RegexIR> optimizedIR = new(baseIR.Count);
List<RegexIR> segment = [];
RegexInfo info = new();
do
{
// TODO scan and opt here
OptimizeIR(baseIR, ref index, segment, info);
optimizedIR.AddRange(segment);
index++;
} while (index < baseIR.Count);
optIR = optimizedIR;
return info;
}
private static void OptimizeDot(
RegexCountSetIR root,
List<RegexIR> ir,
ref int index,
List<RegexIR> optimizedIR,
RegexInfo info
)
{
int next = index + 1;
if (next >= ir.Count)
{
optimizedIR.Clear();
optimizedIR.Add(root);
return;
}
RegexIR nextIR = ir[next];
if (nextIR.Command == RegexIRCommand.Match_Seq)
{
// opt .*abc style
RegexFindSeqIR find = new((nextIR as RegexMatchSeqIR)!.Pattern);
optimizedIR.Add(find);
info.MinLength += find.Pattern.Length;
return;
} else { }
}
private static void OptimizeIR(
List<RegexIR> ir,
ref int index,
List<RegexIR> optimizedIR,
RegexInfo info
)
{
optimizedIR.Clear();
// TODO optimize here
RegexIR root = ir[index];
switch (root.Command)
{
case RegexIRCommand.Count_Set:
RegexCountSetIR count = (root as RegexCountSetIR)!;
if (count.CharSet == ".")
{
// opt for .+ / .* / .{} pattern
OptimizeDot(count, ir, ref index, optimizedIR, info);
}
break;
case RegexIRCommand.Match_Seq:
info.MinLength += (root as RegexMatchSeqIR)!.Pattern.Length;
optimizedIR.Add(root);
break;
default:
optimizedIR.Add(root);
break;
}
}
internal class RegexInfo
{
public int MinLength { get; set; }
public int TryDepth { get; set; }
}
}
}
@@ -1,69 +0,0 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="RegexInterpreter.IRScan"
// 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 System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StgSharp.RegularAnalysis.Text
{
public partial class RegexInterpreter
{
internal static void ScanAndMarkIROptimization(
RegexHIR ir
)
{
switch (ir.Command)
{
case RegexIRCommand.Match_Seq:
break;
case RegexIRCommand.Match_Set:
break;
case RegexIRCommand.Pack:
break;
case RegexIRCommand.Condition:
break;
case RegexIRCommand.Try:
break;
case RegexIRCommand.Count:
break;
case RegexIRCommand.Count_Seq:
break;
case RegexIRCommand.Count_Set:
break;
case RegexIRCommand.Pop:
break;
default:
break;
}
}
}
}
@@ -33,15 +33,15 @@ using System.Threading.Tasks;
namespace StgSharp.RegularAnalysis.Text
{
public partial class RegexInterpreter
public partial class RegexAnalyzer
{
internal static string GetSourceCode(
IEnumerable<RegexHIR> irs
IEnumerable<RegexIR> irs
)
{
StringBuilder sb = new StringBuilder();
foreach (RegexHIR ir in irs) {
foreach (RegexIR ir in irs) {
ScanAndMarkIROptimization(ir);
}
return sb.ToString();
@@ -37,7 +37,7 @@ using System.Threading.Tasks;
namespace StgSharp.RegularAnalysis.Text
{
public partial class RegexInterpreter
public partial class RegexAnalyzer
{
private AbstractSyntaxTree<RegexAstNode, RegexElementLabel> _tree = new();
@@ -45,7 +45,7 @@ namespace StgSharp.RegularAnalysis.Text
private Exception _interpreteException;
private string _source;
private RegexInterpreter() { }
private RegexAnalyzer() { }
internal AbstractSyntaxTree<RegexAstNode, RegexElementLabel> Tree
{
@@ -58,11 +58,11 @@ namespace StgSharp.RegularAnalysis.Text
}
}
public static RegexInterpreter Analyze(
public static RegexAnalyzer Analyze(
string regex
)
{
RegexInterpreter interpreter = new();
RegexAnalyzer interpreter = new();
interpreter._source = regex;
bool isSuccess;
try
-60
View File
@@ -1,60 +0,0 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="RegexLIR"
// 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 System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StgSharp.RegularAnalysis.Text
{
internal enum LIRCommand
{
Search = 0,
Count = 1,
Try = 2,
}
internal abstract class RegexLIR
{
public abstract LIRCommand Command { get; }
}
internal enum RegexSearchMethod
{
Match,
Find,
Assert,
}
}
+2 -2
View File
@@ -51,7 +51,7 @@ namespace StgSharp
{
foreach (string regex in regexSource)
{
RegexInterpreter interpreter = RegexInterpreter.Analyze(regex);
RegexAnalyzer interpreter = RegexAnalyzer.Analyze(regex);
AbstractSyntaxTree<RegexAstNode, RegexElementLabel> tree = interpreter.Tree;
Console.WriteLine($"result of \"{regex}\"");
TreeEnumerator<RegexAstNode, RegexElementLabel> enumerator = new(tree);
@@ -61,7 +61,7 @@ namespace StgSharp
Console.Write(new string('|', enumerator.Depth));
Console.WriteLine($"\t{node.Source.Value}\t{node.Source.Flag}");
}
List<RegexHIR> ir = RegexInterpreter.GenerateIR(tree);
List<RegexIR> ir = RegexAnalyzer.GenerateIR(tree);
Console.WriteLine("-----IR-----");
for (int i = 0; i < ir.Count; i++) {
Console.WriteLine(ir[i].AsCommand(i));