doc/devdocs/modules/powerdisplay/mccsParserDesign.md
This document describes the recursive descent parser implementation for DDC/CI MCCS (Monitor Control Command Set) capabilities strings.
This document and the code implement are generated by Copilot.
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 ::= [^()]+
(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)))
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)?
ref struct for Zero Allocation
ref struct to avoid heap allocationReadOnlySpan<char> for efficient string slicingRecursive Descent Pattern
Peek()Error Recovery
Sub-parsers for Specialized Content
VcpEntryParser for VCP code entriesVcpNameParser for custom VCP namesEntry point. Handles optional outer parentheses and iterates through segments.
private MccsParseResult ParseCapabilities()
{
// Handle optional outer parens
// while (!IsAtEnd()) { ParseSegment() }
// Return result with accumulated errors
}
Parses a single identifier(content) segment.
private ParsedSegment? ParseSegment()
{
// 1. ParseIdentifier()
// 2. Expect '('
// 3. ParseBalancedContent()
// 4. Expect ')'
}
Extracts content between balanced parentheses, handling nested parens.
private string ParseBalancedContent()
{
int depth = 1;
while (depth > 0) {
if (char == '(') depth++;
if (char == ')') depth--;
}
}
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]
| 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 |
| 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 |
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.
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;
}
// 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}");
}
}
010203 vs 01 02 03)