Move parsers to unique files
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Register, RegisterAccess, Note } from '@/utils/parser';
|
import { Register, RegisterAccess, Note } from '@/utils/register_parser';
|
||||||
import { Form, Container, Row, Table, OverlayTrigger, Tooltip } from 'react-bootstrap';
|
import { Form, Container, Row, Table, OverlayTrigger, Tooltip } from 'react-bootstrap';
|
||||||
import RegisterDetail from "@/app/registers/RegisterDetail";
|
import RegisterDetail from "@/app/registers/RegisterDetail";
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Col, Card, Tabs, Tab, Button, Modal } from 'react-bootstrap';
|
import { Col, Card, Tabs, Tab, Button, Modal } from 'react-bootstrap';
|
||||||
import { Register } from '@/utils/parser';
|
import { Register } from '@/utils/register_parser';
|
||||||
import { renderAccess } from './RegisterBrowser';
|
import { renderAccess } from './RegisterBrowser';
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import * as Icon from 'react-bootstrap-icons';
|
import * as Icon from 'react-bootstrap-icons';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { notFound } from 'next/navigation';
|
import { notFound } from 'next/navigation';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { Register } from '@/utils/parser';
|
import { Register } from '@/utils/register_parser';
|
||||||
import RegisterDetail from '@/app/registers/RegisterDetail';
|
import RegisterDetail from '@/app/registers/RegisterDetail';
|
||||||
import {Container, Row} from "react-bootstrap";
|
import {Container, Row} from "react-bootstrap";
|
||||||
import { getRegisters } from '@/app/services/register.service';
|
import { getRegisters } from '@/app/services/register.service';
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
import { promises as fs } from 'fs';
|
import { promises as fs } from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { Register } from '@/utils/parser';
|
import { Register } from '@/utils/register_parser';
|
||||||
import { parseNextReg } from '@/utils/parser';
|
import { parseNextReg } from '@/utils/register_parser';
|
||||||
|
|
||||||
let registers: Register[] = [];
|
let registers: Register[] = [];
|
||||||
|
|
||||||
|
|||||||
@@ -1,191 +0,0 @@
|
|||||||
export interface BitwiseOperation {
|
|
||||||
bits: string;
|
|
||||||
description: string;
|
|
||||||
value?: string;
|
|
||||||
footnoteRef?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Note {
|
|
||||||
ref: string;
|
|
||||||
text: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RegisterAccess {
|
|
||||||
description?: string;
|
|
||||||
operations: BitwiseOperation[];
|
|
||||||
notes: Note[];
|
|
||||||
}
|
|
||||||
export interface Register {
|
|
||||||
hex_address: string;
|
|
||||||
dec_address: number | string;
|
|
||||||
name: string;
|
|
||||||
description: string;
|
|
||||||
read?: RegisterAccess;
|
|
||||||
write?: RegisterAccess;
|
|
||||||
common?: RegisterAccess;
|
|
||||||
text: string;
|
|
||||||
notes: Note[];
|
|
||||||
issue_4_only: boolean;
|
|
||||||
source: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the content of the nextreg.txt file and returns an array of register objects.
|
|
||||||
* @param fileContent The content of the nextreg.txt file.
|
|
||||||
* @returns A promise that resolves to an array of Register objects.
|
|
||||||
*/
|
|
||||||
export async function parseNextReg(fileContent: string): Promise<Register[]> {
|
|
||||||
const registers: Register[] = [];
|
|
||||||
const paragraphs = fileContent.split(/\n\s*\n/);
|
|
||||||
|
|
||||||
for (const paragraph of paragraphs) {
|
|
||||||
if (!paragraph.trim()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
processRegisterBlock(paragraph, registers);
|
|
||||||
}
|
|
||||||
|
|
||||||
return registers;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function processRegisterBlock(paragraph: string, registers: Register[]) {
|
|
||||||
const lines = paragraph.trim().split('\n');
|
|
||||||
const firstLine = lines[0];
|
|
||||||
|
|
||||||
const registerMatch = firstLine.match(/([0-9a-fA-F,x]+)\s*\((.*?)\)\s*=>\s*(.*)/);
|
|
||||||
|
|
||||||
if (!registerMatch) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const hexAddresses = registerMatch[1].trim();
|
|
||||||
const decAddresses = registerMatch[2].trim();
|
|
||||||
const name = registerMatch[3] ? registerMatch[3].trim() : '';
|
|
||||||
const description = lines.slice(1).join('\n').trim();
|
|
||||||
|
|
||||||
const hexList = hexAddresses.split(',').map(h => h.trim());
|
|
||||||
const decList = decAddresses.includes('-') ? decAddresses.split('-') : decAddresses.split(',').map(d => d.trim());
|
|
||||||
|
|
||||||
const createRegister = (hex: string, dec: string | number, regName: string): Register => {
|
|
||||||
const reg: Register = {
|
|
||||||
hex_address: hex,
|
|
||||||
dec_address: dec,
|
|
||||||
name: regName,
|
|
||||||
description: description,
|
|
||||||
notes: [],
|
|
||||||
text: "",
|
|
||||||
issue_4_only: false,
|
|
||||||
source: []
|
|
||||||
};
|
|
||||||
|
|
||||||
const descriptionLines = description.split('\n');
|
|
||||||
let currentAccess: 'read' | 'write' | 'common' | null = null;
|
|
||||||
let accessData: RegisterAccess = { operations: [], notes: [] };
|
|
||||||
|
|
||||||
for (const line of descriptionLines) {
|
|
||||||
if(line.includes('Issue 4 Only')) reg.issue_4_only = true;
|
|
||||||
|
|
||||||
const trimmedLine = line.trim();
|
|
||||||
reg.source.push(line);
|
|
||||||
|
|
||||||
if (trimmedLine.startsWith('//')) continue;
|
|
||||||
|
|
||||||
if (trimmedLine.startsWith('(R)')) {
|
|
||||||
if (currentAccess) reg[currentAccess] = accessData;
|
|
||||||
accessData = { operations: [], notes: [] };
|
|
||||||
currentAccess = 'read';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (trimmedLine.startsWith('(W)')) {
|
|
||||||
if (currentAccess) reg[currentAccess] = accessData;
|
|
||||||
accessData = { operations: [], notes: [] };
|
|
||||||
currentAccess = 'write';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (trimmedLine.startsWith('(R/W')) {
|
|
||||||
if (currentAccess) reg[currentAccess] = accessData;
|
|
||||||
accessData = { operations: [], notes: [] };
|
|
||||||
currentAccess = 'common';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (line.startsWith(trimmedLine)) {
|
|
||||||
if (currentAccess) reg[currentAccess] = accessData;
|
|
||||||
accessData = { operations: [], notes: [] };
|
|
||||||
currentAccess = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
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('*')) {
|
|
||||||
const noteMatch = trimmedLine.match(/^(\*+)\s*(.*)/);
|
|
||||||
if (noteMatch) {
|
|
||||||
accessData.notes.push({
|
|
||||||
ref: noteMatch[1],
|
|
||||||
text: noteMatch[2],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} 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('*')) {
|
|
||||||
const noteMatch = trimmedLine.match(/^(\*+)\s*(.*)/);
|
|
||||||
if (noteMatch) {
|
|
||||||
reg.notes.push({
|
|
||||||
ref: noteMatch[1],
|
|
||||||
text: noteMatch[2],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
reg.text += `${line}\n`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (currentAccess) {
|
|
||||||
reg[currentAccess] = accessData;
|
|
||||||
}
|
|
||||||
|
|
||||||
return reg;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (hexList.length > 1) {
|
|
||||||
for (let i = 0; i < hexList.length; i++) {
|
|
||||||
const hexAddr = hexList[i];
|
|
||||||
const decAddr = decList[i] || decAddresses;
|
|
||||||
const dec = isNaN(parseInt(decAddr, 10)) ? decAddr : parseInt(decAddr, 10);
|
|
||||||
registers.push(createRegister(hexAddr, dec, `${name} (${hexAddr})`));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const dec = isNaN(parseInt(decAddresses, 10)) ? decAddresses : parseInt(decAddresses, 10);
|
|
||||||
registers.push(createRegister(hexAddresses, dec, name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
118
src/utils/register_parser.ts
Normal file
118
src/utils/register_parser.ts
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
import { parseDescriptionDefault } from "./register_parsers/reg_default";
|
||||||
|
import { parseDescriptionF0 } from "./register_parsers/reg_f0";
|
||||||
|
|
||||||
|
export interface RegisterBitwiseOperation {
|
||||||
|
bits: string;
|
||||||
|
description: string;
|
||||||
|
value?: string;
|
||||||
|
footnoteRef?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Note {
|
||||||
|
ref: string;
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RegisterAccess {
|
||||||
|
description?: string;
|
||||||
|
operations: RegisterBitwiseOperation[];
|
||||||
|
notes: Note[];
|
||||||
|
}
|
||||||
|
export interface Register {
|
||||||
|
hex_address: string;
|
||||||
|
dec_address: number | string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
read?: RegisterAccess;
|
||||||
|
write?: RegisterAccess;
|
||||||
|
common?: RegisterAccess;
|
||||||
|
text: string;
|
||||||
|
notes: Note[];
|
||||||
|
issue_4_only: boolean;
|
||||||
|
source: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the content of the nextreg.txt file and returns an array of register objects.
|
||||||
|
* @param fileContent The content of the nextreg.txt file.
|
||||||
|
* @returns A promise that resolves to an array of Register objects.
|
||||||
|
*/
|
||||||
|
export async function parseNextReg(fileContent: string): Promise<Register[]> {
|
||||||
|
const registers: Register[] = [];
|
||||||
|
const paragraphs = fileContent.split(/\n\s*\n/);
|
||||||
|
|
||||||
|
for (const paragraph of paragraphs) {
|
||||||
|
if (!paragraph.trim()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
processRegisterBlock(paragraph, registers);
|
||||||
|
}
|
||||||
|
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function processRegisterBlock(paragraph: string, registers: Register[]) {
|
||||||
|
const lines = paragraph.trim().split('\n');
|
||||||
|
const firstLine = lines[0];
|
||||||
|
|
||||||
|
const registerMatch = firstLine.match(/([0-9a-fA-F,x]+)\s*\((.*?)\)\s*=>\s*(.*)/);
|
||||||
|
|
||||||
|
if (!registerMatch) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hexAddresses = registerMatch[1].trim();
|
||||||
|
const decAddresses = registerMatch[2].trim();
|
||||||
|
const name = registerMatch[3] ? registerMatch[3].trim() : '';
|
||||||
|
const description = lines.slice(1).join('\n').trim();
|
||||||
|
|
||||||
|
const hexList = hexAddresses.split(',').map(h => h.trim());
|
||||||
|
const decList = decAddresses.includes('-') ? decAddresses.split('-') : decAddresses.split(',').map(d => d.trim());
|
||||||
|
|
||||||
|
const normalizeHex = (hex: string): string => {
|
||||||
|
let h = hex.trim();
|
||||||
|
if (!/^0x/i.test(h)) {
|
||||||
|
h = '0x' + h;
|
||||||
|
}
|
||||||
|
return '0x' + h.slice(2).toUpperCase();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const createRegister = (hex: string, dec: string | number, regName: string): Register => {
|
||||||
|
const reg: Register = {
|
||||||
|
hex_address: hex,
|
||||||
|
dec_address: dec,
|
||||||
|
name: regName,
|
||||||
|
description: description,
|
||||||
|
notes: [],
|
||||||
|
text: "",
|
||||||
|
issue_4_only: false,
|
||||||
|
source: []
|
||||||
|
};
|
||||||
|
|
||||||
|
// Dispatch to appropriate parser based on hex
|
||||||
|
const hexKey = normalizeHex(hex);
|
||||||
|
switch (hexKey) {
|
||||||
|
case '0xF0':
|
||||||
|
parseDescriptionF0(reg, description);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
parseDescriptionDefault(reg, description);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reg;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (hexList.length > 1) {
|
||||||
|
for (let i = 0; i < hexList.length; i++) {
|
||||||
|
const hexAddr = hexList[i];
|
||||||
|
const decAddr = decList[i] || decAddresses;
|
||||||
|
const dec = isNaN(parseInt(decAddr, 10)) ? decAddr : parseInt(decAddr, 10);
|
||||||
|
registers.push(createRegister(hexAddr, dec, `${name} (${hexAddr})`));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const dec = isNaN(parseInt(decAddresses, 10)) ? decAddresses : parseInt(decAddresses, 10);
|
||||||
|
registers.push(createRegister(hexAddresses, dec, name));
|
||||||
|
}
|
||||||
|
}
|
||||||
97
src/utils/register_parsers/reg_default.ts
Normal file
97
src/utils/register_parsers/reg_default.ts
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
import {Register, RegisterAccess} from "@/utils/register_parser";
|
||||||
|
|
||||||
|
export const parseDescriptionDefault = (reg: Register, description: string) => {
|
||||||
|
const descriptionLines = description.split('\n');
|
||||||
|
let currentAccess: 'read' | 'write' | 'common' | null = null;
|
||||||
|
let accessData: RegisterAccess = { operations: [], notes: [] };
|
||||||
|
|
||||||
|
for (const line of descriptionLines) {
|
||||||
|
if (line.includes('Issue 4 Only')) reg.issue_4_only = true;
|
||||||
|
|
||||||
|
const trimmedLine = line.trim();
|
||||||
|
reg.source.push(line);
|
||||||
|
|
||||||
|
if (trimmedLine.startsWith('//')) continue;
|
||||||
|
|
||||||
|
if (trimmedLine.startsWith('(R)')) {
|
||||||
|
if (currentAccess) reg[currentAccess] = accessData;
|
||||||
|
accessData = { operations: [], notes: [] };
|
||||||
|
currentAccess = 'read';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (trimmedLine.startsWith('(W)')) {
|
||||||
|
if (currentAccess) reg[currentAccess] = accessData;
|
||||||
|
accessData = { operations: [], notes: [] };
|
||||||
|
currentAccess = 'write';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (trimmedLine.startsWith('(R/W')) {
|
||||||
|
if (currentAccess) reg[currentAccess] = accessData;
|
||||||
|
accessData = { operations: [], notes: [] };
|
||||||
|
currentAccess = 'common';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (line.startsWith(trimmedLine)) {
|
||||||
|
if (currentAccess) reg[currentAccess] = accessData;
|
||||||
|
accessData = { operations: [], notes: [] };
|
||||||
|
currentAccess = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
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('*')) {
|
||||||
|
const noteMatch = trimmedLine.match(/^(\*+)\s*(.*)/);
|
||||||
|
if (noteMatch) {
|
||||||
|
accessData.notes.push({
|
||||||
|
ref: noteMatch[1],
|
||||||
|
text: noteMatch[2],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} 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('*')) {
|
||||||
|
const noteMatch = trimmedLine.match(/^(\*+)\s*(.*)/);
|
||||||
|
if (noteMatch) {
|
||||||
|
reg.notes.push({
|
||||||
|
ref: noteMatch[1],
|
||||||
|
text: noteMatch[2],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (trimmedLine) {
|
||||||
|
reg.text += `${line}\n`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentAccess) {
|
||||||
|
reg[currentAccess] = accessData;
|
||||||
|
}
|
||||||
|
};
|
||||||
98
src/utils/register_parsers/reg_f0.ts
Normal file
98
src/utils/register_parsers/reg_f0.ts
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
|
||||||
|
// 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} 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: [] };
|
||||||
|
|
||||||
|
for (const line of descriptionLines) {
|
||||||
|
if (line.includes('Issue 4 Only')) reg.issue_4_only = true;
|
||||||
|
|
||||||
|
const trimmedLine = line.trim();
|
||||||
|
reg.source.push(line);
|
||||||
|
|
||||||
|
if (trimmedLine.startsWith('//')) continue;
|
||||||
|
|
||||||
|
if (trimmedLine.startsWith('(R)')) {
|
||||||
|
if (currentAccess) reg[currentAccess] = accessData;
|
||||||
|
accessData = { operations: [], notes: [] };
|
||||||
|
currentAccess = 'read';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (trimmedLine.startsWith('(W)')) {
|
||||||
|
if (currentAccess) reg[currentAccess] = accessData;
|
||||||
|
accessData = { operations: [], notes: [] };
|
||||||
|
currentAccess = 'write';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (trimmedLine.startsWith('(R/W')) {
|
||||||
|
if (currentAccess) reg[currentAccess] = accessData;
|
||||||
|
accessData = { operations: [], notes: [] };
|
||||||
|
currentAccess = 'common';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (line.startsWith(trimmedLine)) {
|
||||||
|
if (currentAccess) reg[currentAccess] = accessData;
|
||||||
|
accessData = { operations: [], notes: [] };
|
||||||
|
currentAccess = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
const noteMatch = trimmedLine.match(/^(\*+)\s*(.*)/);
|
||||||
|
if (noteMatch) {
|
||||||
|
reg.notes.push({
|
||||||
|
ref: noteMatch[1],
|
||||||
|
text: noteMatch[2],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (trimmedLine) {
|
||||||
|
reg.text += `${line}\n`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentAccess) {
|
||||||
|
reg[currentAccess] = accessData;
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user