Moving towards a "custom" parser for NextReg 0xF0

This commit is contained in:
2025-10-10 17:17:35 +01:00
parent 20764d74d3
commit 7031088bcd
7 changed files with 184 additions and 125 deletions

View File

@@ -20,11 +20,11 @@ export interface RegisterAccess {
}
export interface RegisterDetail {
modeName?: string;
read?: RegisterAccess;
write?: RegisterAccess;
common?: RegisterAccess;
text: string;
notes: Note[];
}
export interface Register {
@@ -35,6 +35,8 @@ export interface Register {
description: string;
issue_4_only: boolean;
source: string[];
text: string;
notes: Note[];
}
/**
@@ -91,7 +93,9 @@ export function processRegisterBlock(paragraph: string, registers: Register[]) {
description: description,
modes: [],
issue_4_only: false,
source: []
source: [],
text: "",
notes: [],
};
// Dispatch to appropriate parser based on hex

View File

@@ -5,11 +5,12 @@ export const parseDescriptionDefault = (reg: Register, description: string) => {
let currentAccess: 'read' | 'write' | 'common' | null = null;
let accessData: RegisterAccess = { operations: [], notes: [] };
// Prepare a new RegisterDetail for this description block
const detail: RegisterDetail = { read: undefined, write: undefined, common: undefined, text: '', notes: [] };
const detail: RegisterDetail = { read: undefined, write: undefined, common: undefined, text: ''};
for (const line of descriptionLines) {
if (line.includes('Issue 4 Only')) reg.issue_4_only = true;
const spaces_at_start = line.match(/^(\s*)/)?.[0].length || 0;
const trimmedLine = line.trim();
reg.source.push(line);
@@ -50,7 +51,7 @@ export const parseDescriptionDefault = (reg: Register, description: string) => {
if (currentAccess) {
const bitMatch = trimmedLine.match(/^(bits?|bit)\s+([\d:-]+)\s*=\s*(.*)/);
const valueMatch = !line.match(/^\s+/) && trimmedLine.match(/^([01\s]+)\s*=\s*(.*)/);
// const valueMatch = !line.match(/^\s+/) && trimmedLine.match(/^([01\s]+)\s*=\s*(.*)/);
if (bitMatch) {
let bitDescription = bitMatch[3];
@@ -65,13 +66,15 @@ export const parseDescriptionDefault = (reg: Register, description: string) => {
description: bitDescription,
footnoteRef: footnoteRef,
});
} else if (valueMatch) {
accessData.operations.push({
bits: valueMatch[1].trim().replace(/\s/g, ''),
description: valueMatch[2].trim(),
});
// } else if (valueMatch) {
// console.error("VALUE MATCH",valueMatch);
// accessData.operations.push({
// bits: valueMatch[1].trim().replace(/\s/g, ''),
// description: valueMatch[2].trim(),
// });
} else if (trimmedLine.startsWith('*')) {
const noteMatch = trimmedLine.match(/^(\*+)\s*(.*)/);
console.log("NOTE MATCH",noteMatch);
if (noteMatch) {
accessData.notes.push({
ref: noteMatch[1],
@@ -79,6 +82,12 @@ export const parseDescriptionDefault = (reg: Register, description: string) => {
});
}
} else if (trimmedLine) {
if(spaces_at_start == 2) {
reg.text += `${line}\n`;
continue;
}
// console.log("LINE",line);
console.log(line.match(/^\s+/), line);
if (line.match(/^\s+/) && accessData.operations.length > 0) {
accessData.operations[accessData.operations.length - 1].description += `\n${line}`;
} else {
@@ -92,7 +101,7 @@ export const parseDescriptionDefault = (reg: Register, description: string) => {
if (trimmedLine.startsWith('*')) {
const noteMatch = trimmedLine.match(/^(\*+)\s*(.*)/);
if (noteMatch) {
detail.notes.push({
reg.notes.push({
ref: noteMatch[1],
text: noteMatch[2],
});

View File

@@ -1,101 +1,131 @@
// Special-case parser for 0xF0 (XDEV CMD): treat headings beginning with '*' inside access blocks
// as descriptive text instead of notes, so sub-modes become part of the section descriptions.
import {Register, RegisterAccess, RegisterDetail} from "@/utils/register_parser";
// Special-case parser for 0xF0 (XDEV CMD): implement multi-mode parsing.
// Rules:
// - A line that begins with exactly two spaces (" ") and then a non-* character starts a new mode; the trimmed text is modeName.
// - Lines with three or more leading spaces (>=3) belong to the current mode.
// - A line with exactly two spaces followed by '*' is a parent (register-level) note, not a mode note.
// - Inside access blocks for F0, lines starting with '*' are headings for description (not notes).
import { Register, RegisterAccess, RegisterDetail } from "@/utils/register_parser";
export const parseDescriptionF0 = (reg: Register, description: string) => {
const descriptionLines = description.split('\n');
let currentAccess: 'read' | 'write' | 'common' | null = null;
let accessData: RegisterAccess = { operations: [], notes: [] };
const detail: RegisterDetail = { read: undefined, write: undefined, common: undefined, text: '', notes: [] };
const descriptionLines = description.split('\n');
let currentAccess: 'read' | 'write' | 'common' | null = null;
let accessData: RegisterAccess = { operations: [], notes: [] };
// Prepare a new RegisterDetail for this description block
let detail: RegisterDetail = { read: undefined, write: undefined, common: undefined, text: ''};
reg.modes = reg.modes || [];
for (const line of descriptionLines) {
if (line.includes('Issue 4 Only')) reg.issue_4_only = true;
for (const line of descriptionLines) {
reg.source.push(line);
const spaces_at_start = line.match(/^(\s*)/)?.[0].length || 0;
const trimmedLine = line.trim();
const trimmedLine = line.trim();
reg.source.push(line);
if (trimmedLine.startsWith('//')) continue;
if (trimmedLine.startsWith('(R)')) {
if (currentAccess) detail[currentAccess] = accessData;
accessData = { operations: [], notes: [] };
currentAccess = 'read';
continue;
if(spaces_at_start == 2) {
if (trimmedLine.startsWith('*')) {
console.log("PARENT",trimmedLine);
const noteMatch = trimmedLine.match(/^(\*+)\s*(.*)/);
if (noteMatch) {
reg.notes.push({
ref: noteMatch[1],
text: noteMatch[2],
});
}
if (trimmedLine.startsWith('(W)')) {
if (currentAccess) detail[currentAccess] = accessData;
accessData = { operations: [], notes: [] };
currentAccess = 'write';
continue;
}
if (trimmedLine.startsWith('(R/W')) {
if (currentAccess) detail[currentAccess] = accessData;
accessData = { operations: [], notes: [] };
currentAccess = 'common';
continue;
}
if (line.startsWith(trimmedLine)) {
if (currentAccess) detail[currentAccess] = accessData;
accessData = { operations: [], notes: [] };
currentAccess = null;
}
continue;
} else {
if (currentAccess) {
const bitMatch = trimmedLine.match(/^(bits?|bit)\s+([\d:-]+)\s*=\s*(.*)/);
const valueMatch = !line.match(/^\s+/) && trimmedLine.match(/^([01\s]+)\s*=\s*(.*)/);
if (bitMatch) {
let bitDescription = bitMatch[3];
const footnoteMatch = bitDescription.match(/(\*+)$/);
let footnoteRef: string | undefined = undefined;
if (footnoteMatch) {
footnoteRef = footnoteMatch[1];
bitDescription = bitDescription.substring(0, bitDescription.length - footnoteRef.length).trim();
}
accessData.operations.push({
bits: bitMatch[2],
description: bitDescription,
footnoteRef: footnoteRef,
});
} else if (valueMatch) {
accessData.operations.push({
bits: valueMatch[1].trim().replace(/\s/g, ''),
description: valueMatch[2].trim(),
});
} else if (trimmedLine.startsWith('*')) {
// SPECIAL: treat star lines as headings in description rather than notes
const heading = trimmedLine.replace(/^\*+\s*/, '').trim();
if (!accessData.description) accessData.description = '';
accessData.description += (accessData.description ? '\n' : '') + heading;
} else if (trimmedLine) {
if (line.match(/^\s+/) && accessData.operations.length > 0) {
accessData.operations[accessData.operations.length - 1].description += `\n${line}`;
} else {
if (!accessData.description) {
accessData.description = '';
}
accessData.description += `\n${trimmedLine}`;
}
}
} else {
if (trimmedLine.startsWith('*')) {
// Outside access blocks, keep notes as-is but attach to detail now
const noteMatch = trimmedLine.match(/^(\*+)\s*(.*)/);
if (noteMatch) {
detail.notes.push({
ref: noteMatch[1],
text: noteMatch[2],
});
}
} else if (trimmedLine) {
detail.text += `${line}\n`;
}
// finalize previous access block into detail
detail[currentAccess] = accessData;
}
reg.modes.push(detail);
detail = {read: undefined, write: undefined, common: undefined, text: ''};
detail.modeName = trimmedLine;
accessData = {operations: [], notes: []};
currentAccess = null;
continue;
}
}
if (currentAccess) {
if (line.includes('Issue 4 Only')) reg.issue_4_only = true;
if (trimmedLine.startsWith('//')) continue;
if (trimmedLine.startsWith('(R)')) {
if (currentAccess) {
// finalize previous access block into detail
detail[currentAccess] = accessData;
}
accessData = { operations: [], notes: [] };
currentAccess = 'read';
continue;
}
reg.modes = reg.modes || [];
reg.modes.push(detail);
if (trimmedLine.startsWith('(W)')) {
if (currentAccess) {
detail[currentAccess] = accessData;
}
accessData = { operations: [], notes: [] };
currentAccess = 'write';
continue;
}
if (trimmedLine.startsWith('(R/W')) {
if (currentAccess) {
detail[currentAccess] = accessData;
}
accessData = { operations: [], notes: [] };
currentAccess = 'common';
continue;
}
if (currentAccess) {
const bitMatch = trimmedLine.match(/^(bits?|bit)\s+([\d:-]+)\s*=\s*(.*)/);
const valueMatch = !line.match(/^\s+/) && trimmedLine.match(/^([01\s]+)\s*=\s*(.*)/);
if (bitMatch) {
let bitDescription = bitMatch[3];
const footnoteMatch = bitDescription.match(/(\*+)$/);
let footnoteRef: string | undefined = undefined;
if (footnoteMatch) {
console.log("FOOTNOTE",footnoteMatch);
footnoteRef = footnoteMatch[1];
bitDescription = bitDescription.substring(0, bitDescription.length - footnoteRef.length).trim();
}
accessData.operations.push({
bits: bitMatch[2],
description: bitDescription,
footnoteRef: footnoteRef,
});
} else if (valueMatch) {
accessData.operations.push({
bits: valueMatch[1].trim().replace(/\s/g, ''),
description: valueMatch[2].trim(),
});
} else if (trimmedLine.startsWith('*') && spaces_at_start > 2) {
const noteMatch = trimmedLine.match(/^(\*+)\s*(.*)/);
if (noteMatch) {
reg.notes.push({
ref: noteMatch[1],
text: noteMatch[2],
});
}
}
} else if (trimmedLine) {
console.log("LINE", trimmedLine);
if (line.match(/^\s+/) && accessData.operations.length > 0) {
accessData.operations[accessData.operations.length - 1].description += `\n${line}`;
} else {
if (!accessData.description) {
accessData.description = '';
}
accessData.description += `\n${trimmedLine}`;
}
}
}
if (currentAccess) {
detail[currentAccess] = accessData;
console.log("FINAL",detail,currentAccess);
}
// Push the parsed detail into modes
reg.modes.push(detail);
};