mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 03:37:59 +01:00
- Refreshed keyword lists in expect.txt to reflect recent changes. - Fixed documentation link casing in design.md. - Added Copilot attribution note to mccsParserDesign.md. - Reordered and added using directives in WmiController.cs for clarity and dependency resolution.
6.6 KiB
6.6 KiB
MCCS Capabilities String Parser - Recursive Descent Design
Overview
This document describes the recursive descent parser implementation for DDC/CI MCCS (Monitor Control Command Set) capabilities strings.
Attention!
This document and the code implement are generated by Copilot.
Grammar Definition (BNF)
capabilities ::= ['('] segment* [')']
segment ::= identifier '(' segment_content ')'
segment_content ::= text | vcp_entries | hex_list
vcp_entries ::= vcp_entry*
vcp_entry ::= hex_byte [ '(' hex_list ')' ]
hex_list ::= hex_byte*
hex_byte ::= [0-9A-Fa-f]{2}
identifier ::= [a-z_A-Z]+
text ::= [^()]+
Example Input
(prot(monitor)type(lcd)model(PD3220U)cmds(01 02 03 07)vcp(10 12 14(04 05 06) 16 60(11 12 0F) DC DF)mccs_ver(2.2)vcpname(F0(Custom Setting)))
Parser Architecture
Component Hierarchy
MccsCapabilitiesParser (main parser)
├── ParseCapabilities() → MccsParseResult
├── ParseSegment() → ParsedSegment?
├── ParseBalancedContent() → string
├── ParseIdentifier() → ReadOnlySpan<char>
├── ApplySegment() → void
│ ├── ParseHexList() → List<byte>
│ ├── ParseVcpEntries() → Dictionary<byte, VcpCodeInfo>
│ └── ParseVcpNames() → void
│
├── VcpEntryParser (sub-parser for vcp() content)
│ └── TryParseEntry() → VcpEntry
│
├── VcpNameParser (sub-parser for vcpname() content)
│ └── TryParseEntry() → (byte code, string name)
│
└── WindowParser (sub-parser for windowN() content)
├── Parse() → WindowCapability
└── ParseSubSegment() → (name, content)?
Design Principles
-
ref struct for Zero Allocation
- Main parser uses
ref structto avoid heap allocation - Works with
ReadOnlySpan<char>for efficient string slicing - No intermediate string allocations during parsing
- Main parser uses
-
Recursive Descent Pattern
- Each grammar rule has a corresponding parse method
- Methods call each other recursively for nested structures
- Single-character lookahead via
Peek()
-
Error Recovery
- Errors are accumulated, not thrown
- Parser attempts to continue after errors
- Returns partial results when possible
-
Sub-parsers for Specialized Content
VcpEntryParserfor VCP code entriesVcpNameParserfor custom VCP names- Each sub-parser handles its own grammar subset
Parse Methods Detail
ParseCapabilities()
Entry point. Handles optional outer parentheses and iterates through segments.
private MccsParseResult ParseCapabilities()
{
// Handle optional outer parens
// while (!IsAtEnd()) { ParseSegment() }
// Return result with accumulated errors
}
ParseSegment()
Parses a single identifier(content) segment.
private ParsedSegment? ParseSegment()
{
// 1. ParseIdentifier()
// 2. Expect '('
// 3. ParseBalancedContent()
// 4. Expect ')'
}
ParseBalancedContent()
Extracts content between balanced parentheses, handling nested parens.
private string ParseBalancedContent()
{
int depth = 1;
while (depth > 0) {
if (char == '(') depth++;
if (char == ')') depth--;
}
}
ParseVcpEntries()
Delegates to VcpEntryParser for the specialized VCP entry grammar.
vcp_entry ::= hex_byte [ '(' hex_list ')' ]
Examples:
- "10" → code=0x10, values=[]
- "14(04 05 06)" → code=0x14, values=[4, 5, 6]
- "60(11 12 0F)" → code=0x60, values=[0x11, 0x12, 0x0F]
Comparison with Other Approaches
| Approach | Pros | Cons |
|---|---|---|
| Recursive Descent (this) | Clear structure, handles nesting, extensible | More code |
| Regex (DDCSharp) | Concise | Hard to debug, limited nesting |
| Mixed (original) | Pragmatic | Inconsistent, hard to maintain |
Performance Characteristics
- Time Complexity: O(n) where n = input length
- Space Complexity: O(1) for parsing + O(m) for output where m = number of VCP codes
- Allocations: Minimal - only for output structures
Supported Segments
| Segment | Description | Parser |
|---|---|---|
prot(...) |
Protocol type | Direct assignment |
type(...) |
Display type (lcd/crt) | Direct assignment |
model(...) |
Model name | Direct assignment |
cmds(...) |
Supported commands | ParseHexList |
vcp(...) |
VCP code entries | VcpEntryParser |
mccs_ver(...) |
MCCS version | Direct assignment |
vcpname(...) |
Custom VCP names | VcpNameParser |
windowN(...) |
PIP/PBP window capabilities | WindowParser |
Window Segment Format
The windowN segment (where N is 1, 2, 3, etc.) describes PIP/PBP window capabilities:
window1(type(PIP) area(25 25 1895 1175) max(640 480) min(10 10) window(10))
| Sub-field | Format | Description |
|---|---|---|
type |
type(PIP) or type(PBP) |
Window type (Picture-in-Picture or Picture-by-Picture) |
area |
area(x1 y1 x2 y2) |
Window area coordinates in pixels |
max |
max(width height) |
Maximum window dimensions |
min |
min(width height) |
Minimum window dimensions |
window |
window(id) |
Window identifier |
All sub-fields are optional; missing fields default to zero values.
Error Handling
public readonly struct ParseError
{
public int Position { get; } // Character position
public string Message { get; } // Human-readable error
}
public sealed class MccsParseResult
{
public VcpCapabilities Capabilities { get; }
public IReadOnlyList<ParseError> Errors { get; }
public bool HasErrors => Errors.Count > 0;
public bool IsValid => !HasErrors && Capabilities.SupportedVcpCodes.Count > 0;
}
Usage Example
// Parse capabilities string
var result = MccsCapabilitiesParser.Parse(capabilitiesString);
if (result.IsValid)
{
var caps = result.Capabilities;
Console.WriteLine($"Model: {caps.Model}");
Console.WriteLine($"MCCS Version: {caps.MccsVersion}");
Console.WriteLine($"VCP Codes: {caps.SupportedVcpCodes.Count}");
}
if (result.HasErrors)
{
foreach (var error in result.Errors)
{
Console.WriteLine($"Parse error at {error.Position}: {error.Message}");
}
}
Edge Cases Handled
- Missing outer parentheses (Apple Cinema Display)
- No spaces between hex bytes (
010203vs01 02 03) - Nested parentheses in VCP values
- Unknown segments (logged but not fatal)
- Malformed input (partial results returned)