Módulo Analizador (Parser) de VHDL
Proyecto: Kmila-9s
Este módulo es un componente central de Kmila-9s, un proyecto titulado oficialmente "Aplicación Multiplataforma para el Aprendizaje y Depuración de Código VHDL sin Requerimiento de Hardware Físico" (Multiplatform Application for Learning and Debugging VHDL Code without Requiring Physical Hardware).
Autor: Ulrich Tamayo Daniel
Correo: [email protected]
Correo 2: [email protected]
Versión: 1.3.0 (rama v1.3.0)
Última actualización: 2026-08-03
1. Descripción general del proyecto
El objetivo principal de este proyecto es desarrollar una aplicación de escritorio libre, de código abierto y multiplataforma para la depuración interactiva de código VHDL. La aplicación busca facilitar el aprendizaje del diseño digital al proporcionar un entorno unificado para la simulación y la visualización en tiempo real de señales digitales, ciclos de reloj y estados de puertos, eliminando por completo la necesidad de hardware físico como las FPGA.
Motivaciones clave
- Accesibilidad: Superar la barrera económica que representan las costosas tarjetas FPGA y las licencias de software propietario.
- Mejora pedagógica: Ofrecer una interfaz gráfica intuitiva e integrada que simplifica el proceso de depuración, a diferencia de los flujos de trabajo fragmentados por línea de comandos de herramientas como GHDL y GTKWave.
- Flexibilidad: Proporcionar una aplicación autónoma que se ejecuta localmente en múltiples sistemas operativos (Windows, macOS, Linux, Android, iOS) sin requerir conexión a internet.
Este proyecto está construido con .NET y MAUI, lo que garantiza una base de código moderna y mantenible con amplio soporte de plataformas.
2. El módulo analizador
Este módulo específico, el Analizador de VHDL, funciona como el primer paso fundamental del flujo de simulación. Su única responsabilidad es leer el código fuente VHDL en bruto (archivos .vhdl) y transformarlo en una representación estructurada, en memoria, utilizando clases de C#. Estos datos estructurados se pasan luego al motor de simulación para su ejecución y análisis.
El analizador está diseñado para ser robusto, manejando sintaxis VHDL compleja y proporcionando mensajes de error claros para código no válido.
Responsabilidades principales
- Análisis léxico: Descomponer el código VHDL en bruto en un flujo de tokens individuales (palabras clave, identificadores, operadores, literales, etc.).
- Análisis sintáctico: Validar la secuencia de tokens contra las reglas gramaticales de VHDL para comprender la estructura del código.
- Generación del árbol de sintaxis abstracta (AST): Construir una estructura en forma de árbol de objetos de C# que representa el diseño VHDL, incluyendo sus entidades, arquitecturas, señales, procesos y sentencias secuenciales.
- Gestión de ámbitos (scopes): Rastrear todos los identificadores declarados (señales, variables, puertos, etc.) y el ámbito en el que son válidos (por ejemplo, entidad, arquitectura, proceso).
3. Arquitectura del módulo analizador
El analizador está construido con un diseño modular y orientado a objetos, donde distintas clases son responsables de analizar partes específicas del lenguaje VHDL.
Componentes clave
Tokenizer.cs: La primera etapa del flujo. Lee un archivo.vhdlo una cadena en bruto, elimina los comentarios y utiliza expresiones regulares para dividir el código en una lista de tokens de cadena en bruto. Luego evalúa estos tokens para clasificarlos en tipos (por ejemplo,KEYWORD,IDENTIFIER) y crea una lista de objetosToken.TokenStream.cs: Un envoltorio alrededor de la lista de objetosTokengenerada por elTokenizer. Proporciona una API tipo flujo (Current,Previous,MoveNext,Expect,Match,SetRollBack,RollBack) que permite a las clases del analizador consumir y validar tokens en secuencia de forma sencilla. También incluyeStreamerExceptionpara el reporte detallado de errores relacionados con los tokens.Parser.cs: El orquestador principal. Inicializa elTokenStreamy delega el análisis de las unidades de diseño VHDL de alto nivel (entity,architecture,package) a sus clases analizadoras especializadas.ParseV2()además maneja las cláusulaslibrary/useen cualquier punto entre unidades de diseño (se toleran múltiples declaraciones de librería) y recorre los bloquesconfigurationen su lugar medianteParseConfigurationBlock()/ParseConfigurationBody(), incluyendo la forma de enlacefor CompLabel : CompType use entity work.X(Arch);.Analizadores estructurales (
IParseStructures):EntityParser.cs: Analiza un bloqueentity, incluyendo su nombre y las delegaciones para los bloquesgenericyport.ArchitectureParser.cs: Analiza un bloquearchitecture, incluyendo su encabezado (declaraciones de señales/constantes) y su cuerpo (procesos, sentencias concurrentes).PackageParser.cs: Analiza las declaracionespackageypackage body.
Analizadores de declaraciones (
IParseDeclarations):PortsParser.cs: Maneja el bloqueport (...)dentro de una entidad, creando objetosVariablepara cada puerto.GenericParser.cs: Maneja el bloquegeneric (...), analizando las constantes genéricas.ArchitectureAssignationParser.cs: Analiza las declaraciones en el encabezado de una arquitectura, comosignalyconstant.
Analizadores de sentencias y expresiones:
DataStructuresParser.cs: Un analizador versátil para las sentencias secuenciales que se encuentran dentro de procesos, funciones y cuerpos de arquitectura. Puede analizarif-then-elsif-else,case-when,for-loop,while-loop,exit,wait,null,return, y asignaciones de señales/variables. Admite contextos de sentencias tanto concurrentes como secuenciales.FunctionParser.cs: Analiza las declaraciones de funciones, incluyendo parámetros, tipos de retorno (con límites complejos), declaraciones de variables locales y cuerpos de función con sentencias secuenciales.FunctionAssignationParser.cs: Analiza las declaraciones de parámetros dentro de la firma de una función.VectorParser.csyRangeParser.cs: Analizadores auxiliares que manejan la sintaxis específica para tipos de vector (por ejemplo,std_logic_vector(7 downto 0),signed,unsigned) y rangos (por ejemplo,integer range 0 to 255). También manejan atributos de vector como'length,'range,'high,'low.
Modelos de datos principales
Token.cs: Representa una única unidad léxica del código fuente. Contiene suValue(por ejemplo, "entity", "clk"), suType(por ejemplo,KEYWORDS) y su ubicación (Line,Col).Variable.cs: Una clase crucial que representa cualquier objeto con nombre en VHDL (una señal, puerto, variable o constante). Almacena suName, suTypede dato, suValuey suSize. También incluye un eventoOnValueChangepara notificar al motor de simulación las actualizaciones. Adición del 2026-06-22:ElementSize+ArrayLengthllevan el ancho por elemento y la cantidad de ranuras para señales de tipo arreglo (por ejemplo,signal mem : rom_tdonderom_t = array(0 to 7) of std_logic_vector(7 downto 0)queda comoElementSize=8,ArrayLength=8).DeferredIndex/DynamicIndexlos consultan para segmentar por elemento en las lecturas demem(N); sin ellos el indexador recurría a lecturas bit a bit y devolvía basura. Cuidado:Variablesobrecargaoperator==para comparar nombres (no referencias), así que use siempreis null/is not nullpara las comprobaciones de referencia.Constants.cs: Una clase estática que centraliza todas las constantes utilizadas por el analizador, incluyendo:enum TYPE: Define todos los posibles tipos de token.enum DATATYPES: Define todos los tipos de dato VHDL admitidos.- Expresiones regulares para identificar cada tipo de token.
ParserException.cs: Una clase de excepción personalizada usada para reportar errores sintácticos y semánticos detallados durante el análisis, incluyendo:- Números de línea y columna (base 1) para la ubicación del error
- Información de contexto (el valor del token donde ocurrió el error)
- Códigos de error predefinidos (
INITIALIZATION,DUPLICATE_DECLARATION,MISSING_STRUCTURE,DUPLICATE_STRUCTURE,MISSING_DECLARATION,SYNTAX_ERROR) - Métodos de fábrica para errores comunes:
UnexpectedToken(),UndeclaredVariable(),TypeMismatch()
Construcciones VHDL admitidas
El analizador admite un conjunto completo de características del lenguaje VHDL:
- Estructuras de alto nivel:
entity,architecture,package,package body,configuration - Declaraciones:
signal,constant,variable,attribute,alias,component,disconnect,type,subtype - Tipos personalizados: tipos
record(con declaraciones de campos), tiposarray(con restricciones de índice), tipos de enumeración, subtipos con restricciones - Puertos y genéricos: declaraciones completas de puertos/genéricos con tipos de vector, rangos y valores predeterminados
- Sentencias secuenciales:
if-then-elsif-else,case-when,for-loop,while-loop,exit,wait,null,return - Sentencias concurrentes: asignaciones de señales, instanciaciones de componentes con
port mapygeneric map - Sentencias generate:
for-generate,if-generate, generates anidados con declaraciones locales de señales/constantes - Sentencias de bloque: soporte completo de sentencias de bloque con expresiones de guarda, declaraciones locales y bloques anidados
- Construcciones etiquetadas: procesos etiquetados, sentencias generate etiquetadas, instanciaciones de componentes etiquetadas, bloques etiquetados
- Funciones: declaraciones de funciones con parámetros, variables locales, límites de tipo de retorno (incluyendo expresiones complejas) y expresiones complejas
- Expresiones: aritméticas (
+,-,*,/,mod,**), lógicas (and,or,xor,nand,nor,xnor,not,sll,srl,sla,sra,rol,ror), de comparación (=,/=,<,>,<=,>=) - Operaciones con vectores: acceso indexado (por ejemplo,
signal(7 downto 0),signal(i)), atributos de vector (por ejemplo,A'length,A'range,A'high,A'low,A'left,A'right,A'event,A'last_value,A'stable,A'quiet,A'active,A'transaction) - Tipos de dato:
std_logic,std_logic_vector,integer,boolean,bit,bit_vector,natural,positive,signed,unsigned,std_ulogic,std_ulogic_vector,boolean_vector,integer_vector,character,string,time,real - Construcciones especiales:
rising_edge,falling_edge, expresiones de agregado (por ejemplo,(others => '0')), llamadas a funciones en límites (por ejemplo,clog2(N)), operador de concatenación (&), especificaciones de temporizaciónaftercon unidades de tiempo (fs,ps,ns,us,ms,sec,min,hr)
Funciones de la biblioteca estándar
El analizador reconoce las siguientes funciones de la biblioteca estándar IEEE (estas no requieren declaración explícita):
| Categoría | Funciones |
|---|---|
| Conversión IEEE.numeric_std | to_unsigned, to_signed, to_integer, unsigned, signed |
| Redimensionado/Desplazamiento IEEE.numeric_std | resize, shift_left, shift_right |
| IEEE.std_logic_1164 | std_logic_vector, std_ulogic_vector, to_stdlogicvector, to_stdulogicvector, to_bit, to_bitvector, to_x01, to_x01z, to_ux01 |
| Funciones matemáticas | clog2, log2, ceil, floor, abs, minimum, maximum |
| Conversiones de tipo | conv_integer, conv_unsigned, conv_signed, conv_std_logic_vector, integer, natural, positive, real, boolean, bit, character, string |
| Detección de flancos | rising_edge, falling_edge |
| IEEE.math_real | sqrt, sin, cos, tan, exp, log, pow |
| Otras | now, time |
Soporte de sentencias de bloque
Las sentencias de bloque proporcionan una forma de agrupar sentencias concurrentes con expresiones de guarda opcionales y declaraciones locales:
my_block : block (guard_signal = '1') is
signal local_sig : std_logic;
begin
guarded output <= input;
end block my_block;
Características admitidas:
- Expresiones de guarda (opcionales)
- Declaraciones locales de señales/constantes dentro de los bloques
- Bloques anidados (bloques dentro de bloques)
- Bloques etiquetados con etiquetas de cierre opcionales
- Asignaciones de señales con guarda mediante la palabra clave
guarded
Soporte de tipos personalizados
El analizador admite tipos definidos por el usuario, incluyendo registros (records), arreglos (arrays) y enumeraciones:
-- Record type declaration
type ComplexNumber is record
re : signed(15 downto 0);
im : signed(15 downto 0);
end record;
-- Array type declaration
type MemoryArray is array (0 to 255) of std_logic_vector(7 downto 0);
-- Enumeration type declaration
type State is (IDLE, RUNNING, STOPPED, ERROR);
-- Subtype declaration
subtype SmallInt is integer range 0 to 100;
Características admitidas:
- Tipos record con múltiples campos de diversos tipos de dato
- Tipos array con restricciones de índice (usando
toodownto) - Tipos de enumeración con constantes con nombre (agregadas al ámbito automáticamente)
- Declaraciones de subtipos con restricciones de rango
Instanciación de componentes
El analizador admite plenamente las instanciaciones de componentes con mapeos de puertos y genéricos:
-- Component declaration in architecture header
component Adder
generic (WIDTH : integer := 8);
port (
A, B : in std_logic_vector(WIDTH-1 downto 0);
Sum : out std_logic_vector(WIDTH-1 downto 0)
);
end component;
-- Component instantiation
U1 : Adder
generic map (WIDTH => 16)
port map (A => input_a, B => input_b, Sum => result);
Convención de nombres de ámbitos
Los ámbitos de arquitectura usan la convención de nombres {entityName}_{archName} para admitir múltiples arquitecturas con el mismo nombre para diferentes entidades:
Entity "Adder" with architecture "Behavioral" → scope key: "Adder_Behavioral"
Entity "Counter" with architecture "Behavioral" → scope key: "Counter_Behavioral"
Característica de retroceso (rollback) de TokenStream
La clase TokenStream proporciona capacidad de retroceso (rollback) para dar marcha atrás durante el análisis:
// Mark current position
stream.SetRollBack();
// Try to parse something
try {
ParseComplexConstruct();
} catch {
// Restore to marked position if parsing fails
stream.RollBack();
ParseAlternativeConstruct();
}
4. Cómo usar este módulo
Para usar el analizador, se instancia la clase principal Parser, proporcionándole la ruta a un archivo VHDL. Luego, se llama al método ParseV2() para iniciar el proceso.
using Parser.Repositories;
using System;
try
{
// 1. The Tokenizer reads the file and performs lexical analysis.
Tokenizer tokenizer = new("path/to/your/design.vhdl");
// 2. The Parser class orchestrates the syntactic analysis.
Parser vhdlParser = new(tokenizer);
vhdlParser.ParseV2();
// 3. After parsing, the results are available in the Scopes dictionary.
// This dictionary contains all entities, architectures, and their declared variables.
var scopes = vhdlParser.GetScopes();
Console.WriteLine("Parsing completed successfully!");
// You can now inspect the parsed data structures.
foreach (var scope in scopes)
{
Console.WriteLine($"Scope: {scope.Key}");
foreach (var variable in scope.Value)
{
Console.WriteLine($" - Variable: {variable.Name}, Type: {variable.Type}");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred during parsing: {ex.Message}");
}
5. Dependencias
Este módulo depende de las siguientes bibliotecas de .NET:
Microsoft.Extensions.Logging: Para registrar información y errores durante el proceso de análisis.
Todo el resto del código es autónomo dentro de este módulo del proyecto.
6. Flujo del analizador y relaciones entre clases
Para comprender mejor el funcionamiento interno del analizador, los siguientes diagramas ilustran el flujo de datos, las relaciones entre clases y la secuencia de operaciones.
6.1. Flujo de análisis de alto nivel
Este diagrama muestra el proceso general, comenzando desde el archivo VHDL en bruto y terminando con el diccionario estructurado Scopes que el motor de simulación puede utilizar.
graph TD
A["VHDL File (.vhdl)"] --> B(Tokenizer);
B --> C{"List<Token>"};
C --> D[TokenStream];
D --> E(Parser);
E --> F(EntityParser);
E --> G(ArchitectureParser);
E --> H(PackageParser);
subgraph "Parsing Execution"
F --> I{Scopes};
G --> I;
H --> I;
end
I --> J[Simulation Engine];
style B fill:#f9f,stroke:#333,stroke-width:2px
style E fill:#ccf,stroke:#333,stroke-width:2px
style J fill:#bbf,stroke:#333,stroke-width:2px
6.2. Diagrama de clases detallado
Este diagrama detalla las relaciones de composición y herencia entre las clases clave del módulo analizador. Destaca cómo los analizadores especializados se componen para manejar diferentes partes de la sintaxis VHDL.
classDiagram
direction LR
class Parser {
+ParseV2()
+Parse()
+GetScopes() : Dictionary~string, HashSet~Variable~~
}
class Tokenizer {
+ReadFile()
+ReadString(string)
+TokenizeLine(string)
+Evaluate(string) : Token
+GetDictionaryType() : List~Token~
}
class TokenStream {
+Current : Token
+Previous : Token
+MoveNext()
+Expect(TYPE)
+Match(TYPE) : bool
+SetRollBack()
+RollBack()
+EndStream() : bool
}
class EntityParser {
+Parse()
+ParseDeclaration()
+GetName() : string
+ExistsVariable(string) : bool
}
class ArchitectureParser {
+Parse()
+ParseDeclaration()
+ParseHeader()
+ParseBodyDeclaration()
+ParseGenerateStatement()
+ParseBlockStatement()
+ParseComponentInstantiation()
}
class PackageParser {
+Parse()
+ParseDeclaration()
+ParseBodyDeclaration()
+ParseProcedureBody()
}
class DataStructuresParser {
+Parse()
+ParseSequentialBody()
+ParseProcess()
+ParseIfStructure()
+ParseCaseStructure()
+ParseForStructure()
+ParseWhileStructure()
+ParseAsignations()
+ParseOperation()
}
class FunctionParser {
+Parse()
+ParseDeclaration()
+ParseBodyDeclaration()
+ParseReturnTypeBounds()
}
class GenericParser {
+Parse()
+ParseStructure()
+ParseAssignations()
+ParseAssignationsWithComas()
}
class PortsParser {
+Parse()
+ParseDeclarations()
+ParseTypeBounds()
}
class ArchitectureAssignationParser {
+Parse()
+ParseDeclarations()
+ParseAttributeDeclaration()
+ParseDisconnectSpecification()
}
class FunctionAssignationParser {
+Parse()
+ParseDeclarations()
}
class VectorParser {
+Parsed : bool
+Parse()
+ParseBody()
+ParseAttributes()
+ParseBoundExpression()
}
class RangeParser {
+Parse()
+ParseBody()
}
subgraph Models
class Token {
+Value : string
+Type : TYPE
+Line : int
+Col : int
}
class Variable {
+Name : string
+Type : DATATYPES
+Value : object
+Size : int
+IsPort : bool
+PortType : PortType
+IsStub : bool
+CustomTypeName : string?
+RecordFields : Dictionary?
+ElementSize : int
+ArrayLength : int
+OnValueChange : event
}
class Constants {
<<static>>
+TYPE enum
+DATATYPES enum
+ParseExceptions enum
+OperatorType enum
+PortType enum
}
class ParserException {
+Line : int
+Column : int
+ErrorCode : ParseExceptions
+Context : string
+UnexpectedToken()$ ParserException
+UndeclaredVariable()$ ParserException
+TypeMismatch()$ ParserException
}
class Diagnostic {
+Severity : DiagnosticSeverity
+Line : int
+StartColumn : int
+EndColumn : int
+Code : string
+Message : string
+FromException(ParserException)$ Diagnostic
}
class DiagnosticSeverity {
<<enumeration>>
Info
Warning
Error
}
end
Parser o-- TokenStream : uses
Parser o-- EntityParser : creates
Parser o-- ArchitectureParser : creates
Parser o-- PackageParser : creates
Tokenizer --> TokenStream : provides tokens for
EntityParser o-- GenericParser : creates
EntityParser o-- PortsParser : creates
ArchitectureParser o-- DataStructuresParser : creates
ArchitectureParser o-- FunctionParser : creates
ArchitectureParser o-- ArchitectureAssignationParser : creates
PackageParser o-- DataStructuresParser : creates
PackageParser o-- FunctionParser : creates
FunctionParser o-- DataStructuresParser : creates
FunctionParser o-- FunctionAssignationParser : creates
PortsParser o-- VectorParser : uses
GenericParser o-- VectorParser : uses
GenericParser o-- RangeParser : uses
VectorParser <|-- RangeParser : inherits from
6.3. Diagrama de secuencia: análisis de una entidad
Este diagrama de secuencia muestra las interacciones en tiempo de ejecución entre objetos cuando el método ParseV2() encuentra un bloque entity en el código VHDL.
sequenceDiagram
participant User
participant Parser
participant TokenStream
participant EntityParser
participant GenericParser
participant PortsParser
User->>Parser: ParseV2()
Parser->>EntityParser: new(stream, scopes)
Parser->>EntityParser: Parse()
activate EntityParser
EntityParser->>TokenStream: Expect(KEYWORD 'entity')
EntityParser->>TokenStream: Current (get entity name)
loop until 'is'
EntityParser->>TokenStream: MoveNext()
end
alt 'generic' keyword found
EntityParser->>GenericParser: new(stream, scopes, name)
EntityParser->>GenericParser: Parse()
activate GenericParser
loop Parse generic declarations
GenericParser->>TokenStream: Expect/MoveNext
end
deactivate GenericParser
end
alt 'port' keyword found
EntityParser->>PortsParser: new(stream, scopes, name)
EntityParser->>PortsParser: Parse()
activate PortsParser
loop Parse port declarations
PortsParser->>TokenStream: Expect/MoveNext
end
deactivate PortsParser
end
EntityParser->>TokenStream: Expect(KEYWORD 'end')
deactivate EntityParser
6.4. Diagrama de módulos
graph TD
vhdl_files["VHDL Source Files<br>(.vhdl)"]
subgraph parser_system["VHDL Parser Module"]
subgraph repositories["Repositories"]
tokenizer["Tokenizer<br>/Repositories/Tokenizer.cs"]
token_stream["TokenStream<br>/Repositories/TokenStream.cs"]
parser_core["Parser<br>/Repositories/Parser.cs"]
structural_parsers["Structural Parsers<br>EntityParser, ArchitectureParser,<br>PackageParser"]
declaration_parsers["Declaration Parsers<br>PortsParser, GenericParser,<br>ArchitectureAssignationParser,<br>FunctionAssignationParser"]
statement_parsers["Statement Parsers<br>DataStructuresParser, FunctionParser"]
helper_parsers["Helper Parsers<br>VectorParser, RangeParser"]
end
subgraph models["Models"]
token_model["Token"]
variable_model["Variable"]
constants_model["Constants"]
exception_model["ParserException"]
diagnostic_model["Diagnostic<br>+ DiagnosticSeverity"]
end
subgraph interfaces["Interfaces"]
iparser["IParser, IParserBaseMethods"]
iparse_structures["IParseStructures"]
iparse_declarations["IParseDeclarations"]
iparse_vector["IParseVectorStructure"]
iparse_generic["IParseGeneric"]
end
end
scopes["Scopes Dictionary<br>Dictionary<string, HashSet<Variable>>"]
downstream["Downstream Modules<br>(Debugger / Interpreter)"]
editor_markers["Editor (Monaco markers)<br>Kmila.Shared.Pages.Editor"]
vhdl_files -->|"reads"| tokenizer
tokenizer -->|"produces List<Token>"| token_stream
token_stream -->|"consumed by"| parser_core
parser_core -->|"delegates to"| structural_parsers
structural_parsers -->|"delegates to"| declaration_parsers
structural_parsers -->|"delegates to"| statement_parsers
declaration_parsers -->|"uses"| helper_parsers
structural_parsers -.->|"implements"| interfaces
declaration_parsers -.->|"implements"| interfaces
statement_parsers -.->|"implements"| interfaces
helper_parsers -.->|"implements"| interfaces
repositories -->|"uses"| models
parser_core -->|"populates"| scopes
scopes -->|"consumed by"| downstream
diagnostic_model -->|"FromException(ParserException)"| editor_markers
exception_model -.->|"adapted via"| diagnostic_model
7. Historial de cambios
Re-sincronización de la documentación (2026-08-03, rama v1.3.0)
- Se actualizó el sello del encabezado a la rama actual (
v1.3.0) y la fecha. Se volvió a cotejar la referencia de clases contra el árbol en disco: se agregaronParserSkipOverflowExceptionyDiagnostica la tabla de Modelos,SharedLogginga la tabla de Analizadores y una nueva tabla de Servicios paraUserTypeRegistry/ParseProfile. Se actualizó la lista de fixtures negativos de la "Pasada de rigurosidad" para incluir el tercer fixture (test_negative_garbage_in_body.vhdl), queProgram.csya cablea. Solo documentación; sin cambios en el código fuente del analizador ni en la API pública.
Versión 1.14.1 (2026-05-01)
Verificación de la documentación
- README.md: Se cotejó el documento completo contra el código fuente actual de
Repositories/,Models/eInterfaces/. Se confirmó que los puntos de entrada del orquestador siguen siendoParser(Tokenizer)/Parser(string FilePath), conParseV2()como la ruta recomendada yParse()conservado como la implementación monolítica heredada. El conjunto completoIParserdocumentado aquí coincide uno a uno con los archivos*.csen disco (14 clases analizadoras, 6 interfaces, 5 archivos de modelo incluyendoDiagnostic). - §2 Arquitectura /
Parser.cs: Se aclaró queParseV2()también maneja las declaracioneslibrary/useen línea entre unidades de diseño y recorre los bloquesconfiguration(con la forma de enlacefor CompLabel : CompType use entity work.X(Arch);) medianteParseConfigurationBlock/ParseConfigurationBody. Las versiones anteriores de este documento solo mencionaban el cambio entreentity/architecture/package. - §6.2 Diagrama de clases: Se agregó el modelo
Diagnostic(con el adaptador estáticoFromException(ParserException)) y la enumeraciónDiagnosticSeverityal clúster de Modelos. - §6.4 Diagrama de módulos: Se agregó el nodo
Diagnostic/DiagnosticSeverityal subgrafo de Modelos y una arista explícita hacia la superficie del editor (Kmila.Shared.Pages.Editor) que muestra cómoParserExceptionse adapta medianteDiagnostic.FromException(...)para alimentar los marcadores de Monaco. - Sin cambios en la API pública ni en el comportamiento en tiempo de ejecución en esta versión; la superficie del analizador sigue siendo retrocompatible con la versión v1.14.0 que introdujo el flujo de diagnósticos.
Versión 0.13.1 (2026-02-21)
Mejoras de documentación
- Variable.cs: Se agregó documentación XML exhaustiva para todos los constructores, operadores, campos de respaldo (
_size,_value),IsPort,PortType,ToString(), la conversión implícita y los operadores de igualdad/desigualdad - DataStructuresParser.cs: Se agregaron documentos XML para
ParseDeclaration()(lanza NotImplementedException) y se documentaron los grupos de campos privados - VectorParser.cs: Se agregaron documentos XML para el método protegido
CheckVariable()y el método privadoIsVector() - TokenizerTests.cs: Se agregó documentación XML para la clase de prueba y el método de prueba con descripciones de parámetros
- Program.cs: Se agregó documentación XML para la clase ejecutora de pruebas y su punto de entrada
Versión 0.13.0 (2025-12-13)
Esta versión incluye mejoras exhaustivas de documentación, correcciones de errores y mejoras menores de código.
Correcciones de errores
- Corrección de fuga de memoria en TokenStream: Se corrigió una fuga de memoria significativa causada por que cada instancia de
TokenStreamcreaba su propioLoggerFactory. Ahora usa unLoggerFactorycompartido estático para evitar la acumulación de memoria durante operaciones de análisis repetidas.
Mejoras de documentación
Actualizaciones del README: Se agregó documentación exhaustiva para características antes no documentadas:
- Funciones de la biblioteca estándar: tabla completa de más de 50 funciones reconocidas de la biblioteca estándar IEEE
- Soporte de sentencias de bloque: explicación detallada con ejemplos de código VHDL
- Instanciación de componentes: documentación completa con ejemplos de generic/port map
- Convención de nombres de ámbitos: explicación del patrón
{entityName}_{archName} - Característica de retroceso (rollback) de TokenStream: documentación de uso con ejemplos de código
Documentación de Constants.cs: Se agregó documentación XML a todos los valores de enum y patrones de regex:
- Enum
TYPE: cada tipo de token ahora tiene una descripción detallada - Enum
ParseExceptions: cada código de error tiene una explicación con ejemplos - Enum
DATATYPES: cada tipo de dato tiene una descripción de su semántica VHDL - Enum
OperatorType: cada categoría de operador está documentada - Enum
PortType: descripciones de puertos de entrada/salida - Todos los patrones de regex: se agregaron ejemplos y explicaciones para cada patrón
- Enum
Actualizaciones (del 2025-12-09)
- Operadores de desplazamiento/rotación en LOGIC_OPERATORS: Se agregaron
sll,srl,sla,sra,rol,roral patrón de regexLOGIC_OPERATORS. Estos operadores ya estaban en KEYWORDS pero no estaban clasificados como operadores lógicos, lo que causaba problemas en la evaluación de expresiones del Intérprete.
Versión 0.12.5 (2025-12-09)
Esta versión agrega los operadores de desplazamiento y rotación a LOGIC_OPERATORS para su clasificación adecuada por parte del intérprete aguas abajo.
Actualizaciones
- Operadores de desplazamiento/rotación en LOGIC_OPERATORS: Se agregaron
sll,srl,sla,sra,rol,roral patrón de regexLOGIC_OPERATORS. Estos operadores ya estaban en KEYWORDS pero no estaban clasificados como operadores lógicos, lo que causaba problemas en la evaluación de expresiones del Intérprete.
Versión 0.12.5 (2025-12-09)
Esta versión corrige las fallas de prueba restantes (pruebas 18, 19, 20) y agrega soporte para construcciones VHDL avanzadas, incluyendo sentencias de bloque, señales con guarda, atributos de señal y generates condicionales complejos.
Nuevas características
- Soporte de sentencias de bloque: Análisis completo de sentencias de bloque VHDL con:
- Expresiones de guarda (por ejemplo,
block (guard_signal = '1')) - Declaraciones locales de señales/constantes dentro de los bloques
- Bloques anidados (bloques dentro de bloques)
- Bloques etiquetados con etiquetas de cierre opcionales
- Expresiones de guarda (por ejemplo,
- Asignaciones de señales con guarda: Soporte para asignaciones concurrentes de señales con guarda mediante la palabra clave
guarded - Atributos de señal con argumentos: Análisis de atributos de señal con argumentos de tiempo:
'stable(time)- comprobación de estabilidad de señal'delayed(time)- valor de señal retardado'last_value,'last_event,'eventen expresiones condicionales
- Funciones de conversión de tipo en condicionales: Soporte para las funciones de conversión de tipo de IEEE numeric_std en condiciones if/when:
unsigned(),signed(),to_integer(),to_unsigned(),to_signed()resize(),shift_left(),shift_right()std_logic_vector(),integer(),natural()
- Enlace de arquitectura en configuración: Soporte para la especificación de arquitectura en bloques de configuración:
- sintaxis
use entity work.Component(Architecture);
- sintaxis
- Soporte mejorado de operadores: Se agregaron
/=(distinto) y>=(mayor o igual) como operadores correctamente tokenizados - Constantes de paquete en genéricos: Los valores predeterminados de los genéricos ahora pueden referenciar constantes de paquete (identificadores), no solo literales
- Tipos personalizados en puertos: Las declaraciones de puertos ahora aceptan tipos definidos por el usuario (identificadores) además de los tipos VHDL estándar
Correcciones de errores
- Se corrigió un bucle infinito en
ParseOperation(): Se corrigió la condición del bucle while que impedía la terminación adecuada al encontrar un punto y coma - Se corrigió el regex
QUALIFIED_IDENTIFIERS: Ahora permite dígitos en el primer segmento del identificador (por ejemplo,s_axi_s2m.bvaliddondes2mcontiene un dígito) - Se corrigió el análisis de bloques anidados:
ParseBlockBody()ahora reconoce y maneja correctamente las sentencias de bloque anidadas - Se corrigió el análisis de bloques de configuración: Se agregó soporte para la sintaxis de enlace de arquitectura con paréntesis
- Se agregó un mecanismo de reserva para tokens desconocidos:
ParseSingleStatement()ahora omite con elegancia los tokens desconocidos hasta el siguiente punto y coma en lugar de provocar bucles infinitos
Correcciones en archivos de prueba
- test20.vhdl: Se corrigieron conflictos de mayúsculas/minúsculas en identificadores VHDL renombrando las constantes de la máquina de estados:
TX_DATA→TX_ST_DATA(para evitar el conflicto con la señaltx_data)RX_DATA→RX_ST_DATA(para evitar el conflicto con la señalrx_data)- Renombrados similares para
TX_IDLE,TX_START,TX_STOP,RX_IDLE,RX_START,RX_STOP
Cobertura de pruebas
- Los 43 casos de prueba ahora pasan:
- test1-10: construcciones VHDL básicas a intermedias
- test11-17: sentencias generate, diseños multientidad, procesos etiquetados
- test18: atributos de señal avanzados, señales con guarda, sentencias de bloque, configuración
- test19: generates condicionales complejos con conversiones de tipo
- test20: diseño completo estilo SoC con paquetes, records, múltiples entidades y configuración
Versión 0.12.4 (2025-12-08)
Esta versión incluye mejoras significativas en el manejo por parte del analizador de construcciones VHDL complejas, en particular en torno al análisis de sentencias concurrentes frente a secuenciales, la gestión de ámbitos y el reporte de errores mejorado.
Nuevas características
- Soporte de sentencias generate: Análisis completo de sentencias
for-generateeif-generate, incluyendo:- Sentencias generate anidadas
- Declaraciones locales de señales/constantes dentro de los bloques generate
- Ámbito de la variable iteradora (eliminada automáticamente después de que el generate finaliza)
- Soporte de procesos etiquetados: Análisis de procesos con etiquetas (por ejemplo,
my_proc : process(clk) begin ... end process my_proc;) - Soporte de bucles while: Se agregó el análisis de
while condition loop ... end loop; - Sentencias secuenciales adicionales: Soporte para las sentencias
exit,waitynull - Palabras clave extendidas: Se agregó soporte para muchas palabras clave VHDL adicionales, incluyendo
nand,nor,xnor,sll,srl,sla,sra,rol,ror,abs,rem,transport,reject,inertial,unaffected, y más - Atributos de vector: Soporte extendido para atributos de señal como
'last_value,'last_event,'event,'stable,'quiet,'active,'transaction,'delayed,'now,'path_name,'instance_name,'base,'high,'low,'left,'right,'length,'range,'reverse_range,'ascending, etc. - Análisis de bloques de configuración: Se agregó soporte para el análisis de bloques
configurationde VHDL con sentenciasforanidadas - Declaraciones de componentes: Análisis completo de declaraciones
componentdentro de los encabezados de arquitectura, incluyendo bloquesgenericyportopcionales - Instanciación de componentes: Soporte para instanciaciones de componentes con
port mapygeneric map - Declaraciones de variables de proceso: Análisis de declaraciones
variableyconstantdentro de los cuerpos de proceso antes debegin - Expresiones de agregado: Soporte para expresiones de agregado como
(others => '0')en inicializaciones de señal/constante - Análisis de llamadas a funciones: Análisis adecuado de llamadas a funciones en expresiones (por ejemplo,
conv_integer(x),clog2(N)) - Acceso indexado a señales: Análisis del acceso indexado a señales/variables como
signal(7 downto 0)osignal(i) - Declaraciones de atributos: Soporte para declaraciones y especificaciones
attribute - Especificaciones de disconnect: Análisis de especificaciones
disconnectpara señales con guarda
Reporte de errores mejorado
ParserException: Completamente reescrita con mensajes de error detallados que incluyen:- Números de línea y columna (base 1)
- Información de contexto (cerca de qué token ocurrió el error)
- Tipos de error predefinidos:
INITIALIZATION,DUPLICATE_DECLARATION,MISSING_STRUCTURE,DUPLICATE_STRUCTURE,MISSING_DECLARATION,SYNTAX_ERROR - Métodos de fábrica:
UnexpectedToken(),UndeclaredVariable(),TypeMismatch()
StreamerException: Mejorada con contexto detallado:- Descripciones de tipo legibles por humanos (por ejemplo, "keyword (e.g., 'process', 'signal', 'begin', 'end')")
- Rastrea el último token válido para una mejor ubicación del error al llegar al fin de la entrada
Cambios arquitectónicos clave
Análisis de sentencias concurrentes frente a secuenciales (
DataStructuresParser.cs)- Se agregó el método
ParseSingleStatement()para analizar exactamente UNA sentencia concurrente (usado en el contexto del cuerpo de la arquitectura) - Se agregó el método
ParseSequentialBody()para analizar TODAS las sentencias secuenciales hasta la palabra claveend(usado en cuerpos de proceso/función) - El método
Parse()ahora usaParseSingleStatement()para evitar el bucle incorrecto a través de las construcciones del cuerpo de la arquitectura
- Se agregó el método
Nombres de ámbito de arquitectura (
ArchitectureParser.cs)- Los ámbitos de arquitectura ahora usan
{entityName}_{archName}como clave - Esto permite múltiples arquitecturas con el mismo nombre para diferentes entidades (por ejemplo, tanto
AddercomoPipelineRegpueden tener arquitecturasBehavioral)
- Los ámbitos de arquitectura ahora usan
Ámbito de la variable iteradora
- Las variables iteradoras de
for-loopyfor-generateahora tienen un ámbito adecuado - Las variables se eliminan del ámbito después de que el bucle/generate finaliza
- Evita errores de "declaración duplicada" cuando se reutiliza el mismo nombre de iterador
- Las variables iteradoras de
Análisis del cuerpo de función (
FunctionParser.cs)- Ahora usa
ParseSequentialBody()en lugar deParse()para manejar correctamente múltiples sentencias en los cuerpos de función - Soporte para límites de tipo de retorno con expresiones complejas (por ejemplo,
std_logic_vector((A'length + B'length) - 1 downto 0)) - Análisis de declaraciones de variables/constantes locales antes de
begin
- Ahora usa
Mejoras del modelo Variable (
Variable.cs)- Se extendió
GetDatatype()para admitir tipos adicionales:std_ulogic,signed,unsigned,bit_vector,boolean_vector,integer_vector,positive,string,time,real - Manejo mejorado de los patrones de agregado
(others => 'X') - Soporte para expresiones de concatenación
(concat:...) - Comparación de variables sin distinción de mayúsculas/minúsculas (los identificadores VHDL no distinguen mayúsculas de minúsculas)
- Se extendió
Correcciones de errores
- Se corrigió un problema donde las etiquetas de generate se analizaban incorrectamente como asignaciones de señal
- Se corrigió un problema donde las etiquetas de instanciación de componentes causaban errores de "instancia no está en el ámbito"
- Se corrigieron errores de estructura duplicada cuando múltiples arquitecturas compartían el mismo nombre
- Se corrigió el análisis del cuerpo de función que se detenía después de la primera sentencia
- Se corrigió el análisis del cuerpo del bucle
whileque retornaba prematuramente - Se corrigió que los límites de tipo de vector no se analizaban en los parámetros de función
- Se corrigió el análisis de la expresión de retorno en funciones
Cobertura de pruebas
- Los 20 casos de prueba ahora pasan, cubriendo:
- Análisis básico de entidad/arquitectura (test1-5)
- Expresiones y operadores complejos (test6-10)
- Sentencias generate con declaraciones locales (test11-12)
- Diseños multientidad con nombres de arquitectura compartidos (test11, test17)
- Procesos etiquetados y estructuras de control anidadas (test13-16)
- Jerarquías e instanciaciones de componentes (test17-20)
8. Referencia completa de clases
Modelos
| Clase | Descripción |
|---|---|
Token |
Representa un token léxico con las propiedades Value, Type, Line y Col |
Variable |
Representa señales, puertos, variables y constantes de VHDL con las propiedades: Name, Type, Value, Size, IsPort, PortType, IsStub, CustomTypeName, RecordFields, y el evento reactivo OnValueChange. Incluye el método estático GetDatatype() para la resolución de la cadena de tipo. |
Constants |
Clase estática que contiene los tipos de token (enum TYPE), tipos de dato (enum DATATYPES), códigos de error (enum ParseExceptions), tipos de operador (enum OperatorType: ASSIGNATION, LOGIC_OPERATION, ARITH_OPERATION, COMPARATION), tipos de puerto (enum PortType: IN, OUT, INOUT, BUFFER), y patrones de regex para la clasificación de tokens |
ParserException |
Excepción personalizada con contexto de error enriquecido que incluye información de línea/columna |
ParserSkipOverflowException |
Subclase de ParserException que se lanza cuando un bucle Skip* / Parse* sobrepasa su límite de iteraciones (lleva el nombre del método ofensor y el límite); permite que la entrada patológica falle rápido en lugar de colgar el analizador |
Diagnostic |
Diagnóstico estructurado (DiagnosticSeverity + línea/columna/código/mensaje); FromException(ParserException) adapta el flujo de excepciones a los marcadores de Monaco |
Interfaces
| Interfaz | Descripción |
|---|---|
IParser |
Interfaz base con el método Parse() |
IParserBaseMethods |
Métodos para la gestión de ámbitos/variables: ExistsVariable(), GetScopes() |
IParseStructures |
Para estructuras de alto nivel (entity, architecture, package): GetName(), ParseDeclaration(), ParseBodyDeclaration() |
IParseDeclarations |
Para bloques de declaración: ParseDeclarations() |
IParseVectorStructure |
Para tipos de vector: ParseBody() |
IParseGeneric |
Para bloques genéricos: ParseStructure(), ParseAssignations(), ParseAssignationsWithComas() |
Analizadores
| Analizador | Responsabilidad |
|---|---|
Tokenizer |
Análisis léxico: convierte el código fuente VHDL en tokens |
TokenStream |
Gestión del flujo de tokens con Current, MoveNext(), Expect(), Match() |
Parser |
Orquestador principal: delega a los analizadores especializados |
EntityParser |
Analiza los bloques entity |
ArchitectureParser |
Analiza los bloques architecture, incluyendo sentencias generate e instanciaciones de componentes |
PackageParser |
Analiza los bloques package y package body |
DataStructuresParser |
Analiza sentencias secuenciales (if, case, for, while, asignaciones) |
FunctionParser |
Analiza declaraciones y cuerpos de function |
FunctionAssignationParser |
Analiza las declaraciones de parámetros de función |
GenericParser |
Analiza los bloques generic |
PortsParser |
Analiza los bloques port |
ArchitectureAssignationParser |
Analiza las declaraciones del encabezado de arquitectura (señales, constantes, atributos) |
VectorParser |
Analiza los tipos de vector (std_logic_vector, etc.) |
RangeParser |
Analiza las declaraciones range (extiende VectorParser) |
SharedLogging |
Auxiliar internal static que expone una única ILoggerFactory compartida (proveedor de consola), reutilizada por cada analizador para evitar la asignación de LoggerFactory por instancia |
Servicios
| Servicio | Responsabilidad |
|---|---|
UserTypeRegistry |
Catálogo a nivel de proceso de los nombres de tipo VHDL definidos por el usuario ya resueltos; poblado por el host a partir de los símbolos de LibraryCompiler antes del análisis, de modo que el analizador acepta los tipos declarados en paquetes/librerías como identificadores de tipo válidos |
ParseProfile |
Contadores ligeros por ejecución para las rutas calientes del lado del análisis (por ejemplo, Tokenizer.EvaluateToken), emitidos por el host cuando KMILA_PARSE_PROFILE está definido |
9. Diagramas de auditoría (2026-05-09)
Estos diagramas fueron reescritos o creados durante la auditoría entre módulos porque los
diagramas TT1 existentes modelaban un Parse() de máquina de estados única que fue reemplazado por
la delegación explícita de ParseV2() (EntityParser / ArchitectureParser /
PackageParser). También residen en Documentacion/TT1/diagrams/.
fig_4_4_dominio_analisis_codigo — Modelo de dominio: análisis de código (reescrito)
classDiagram
direction LR
class ArchivoHDL {
+String nombre
+String contenido
}
class Scope {
+String nombre
+TipoScope tipo
}
class Variable {
+String nombre
+Tipo tipo
+Object valor
+Int tamanio
+PortType direccion
}
class Diagnostico {
+Severidad severidad
+Int linea
+Int columnaInicio
+Int columnaFin
+String codigo
+String mensaje
}
ArchivoHDL "1" --> "0..*" Scope : produce
Scope "1" --> "0..*" Variable : agrupa
ArchivoHDL "1" --> "0..*" Diagnostico : genera
Variable "0..*" ..> "0..*" Variable : referencia (records, vectores)
fig_5_8_1_seq_validacion_vhdl — Secuencia de validación (reescrito)
sequenceDiagram
actor E as Estudiante
participant UI as ButtonCollapse
participant Ed as Editor.razor
participant PB as ProgramBuilder
participant Tk as Tokenizer
participant TS as TokenStream
participant Pa as Parser
E->>UI: Presiona "Validar programa"
UI->>Ed: OnBuildRequested
Ed->>PB: Build(ProjectFile)
PB->>PB: Validar extension .vhd/.vhdl
PB->>Pa: new Parser(filePath)
Pa->>Tk: ReadFile + TokenizeLine + Evaluate
Tk-->>Pa: List~Token~
Pa->>TS: new TokenStream(tokens)
PB->>Pa: ParseV2()
loop Mientras quedan tokens
Pa->>TS: Current / MoveNext
alt Token = entity
Pa->>Pa: EntityParser.ParseDeclaration
else Token = architecture
Pa->>Pa: ArchitectureParser.ParseDeclaration
else Token = package
Pa->>Pa: PackageParser.ParseDeclaration
else Token = library / use
Pa->>Pa: ParseLibrariesUsage
else Token = configuration
Pa->>Pa: ParseConfigurationBlock
end
end
Pa-->>PB: Scopes (Dictionary<string, HashSet~Variable~>)
PB-->>UI: OnBuildProgressChanged(100%)
UI-->>E: Muestra entidades y recursos detectados
fig_5_11_2_1_act_validacion_prep — Actividad de preparación (reescrito)
flowchart TD
A([Inicio: Validar programa]) --> B{Extension .vhd o .vhdl?}
B -->|No| C([Fin: archivo rechazado])
B -->|Si| D[Crear instancia de Parser con ruta del archivo]
D --> E[Tokenizer: ReadFile y eliminar comentarios]
E --> F[TokenizeLine: clasificar tokens por regex]
F --> G[Evaluate: asignar TYPE a cada token]
G --> H[Construir TokenStream sobre la lista de tokens]
H --> I([Continua en Figura 5.11.2.2])
fig_5_11_2_2_act_validacion_recorrido — Recorrido guiado por tokens (reescrito)
flowchart TD
A([TokenStream listo]) --> B[ParseV2: leer Current]
B --> C{Tipo de token?}
C -->|entity| D[EntityParser: nombre, generic, ports]
C -->|architecture| E[ArchitectureParser: nombre, entidad, header]
C -->|package| F[PackageParser: constantes, funciones, tipos]
C -->|library / use| G[ParseLibrariesUsage]
C -->|configuration| H[ParseConfigurationBlock]
C -->|otro| B
D --> I[Registrar Variables en Scopes]
E --> I
F --> I
G --> B
H --> I
I --> J{EndStream?}
J -->|No| B
J -->|Si| K{Hubo entidades / packages?}
K -->|No| L([Fin: error, sin unidades de diseno])
K -->|Si| M([Fin: Scopes disponibles + Diagnosticos])
fig_5_11_6_act_tokenizer_pipeline — Pipeline del Tokenizer (nuevo)
flowchart TD
A([Inicio: Tokenizer.ReadFile]) --> B[Leer archivo VHDL crudo]
B --> C[Eliminar lineas que comienzan con --]
C --> D[Por cada linea: TokenizeLine]
D --> E[Aplicar regex a cada fragmento]
E --> F{Patron coincide?}
F -->|KEYWORDS| G[Token.Type = KEYWORDS]
F -->|OPERATORS| H[Token.Type = OPERATORS]
F -->|LITERALS| I[Token.Type = LITERALS]
F -->|IDENTIFIERS| J[Token.Type = IDENTIFIERS]
F -->|TIME / VECTORS_ATTRIBUTES /<br/>FUNCTIONS / SEPARATORS /<br/>PARENTHESIS| K[Token.Type = otro]
F -->|Sin coincidencia| L[Token.Type = UNKNOWN<br/>+ Diagnostico critico]
G --> M[Adjuntar Line, Col]
H --> M
I --> M
J --> M
K --> M
L --> M
M --> N{Quedan lineas?}
N -->|Si| D
N -->|No| O([Fin: List~Token~ + Diagnosticos])
fig_5_11_7_act_configuration_block — Análisis de bloque de configuración (nuevo)
flowchart TD
A([Token = configuration]) --> B[ParseConfigurationBlock: leer nombre y entidad objetivo]
B --> C[Expect of, leer entityName]
C --> D[Expect is]
D --> E[ParseConfigurationBody]
E --> F{Siguiente token?}
F -->|for label : compType use| G[Registrar binding<br/>label -> entity work.X arch]
F -->|end for| H[Cerrar bloque interno]
F -->|end configuration| I[Validar nombre coincide]
F -->|otro| E
G --> E
H --> E
I --> J[Crear scope configuration_name]
J --> K[Registrar bindings como Variables<br/>en HashSet del scope]
K --> L([Fin: scope listo en Scopes])
fig_5_11_8_act_generate_scope — Ciclo de vida del ámbito de la sentencia generate (nuevo)
flowchart TD
A([Statement: for label in rango generate]) --> B[ArchitectureParser.ParseGenerateStatement]
B --> C[Crear scope hijo<br/>arch_label_generate]
C --> D[Registrar variable iteradora<br/>en el scope hijo]
D --> E[ParseSequentialBody hasta end generate]
E --> F{Statement tipo?}
F -->|signal_assignment| G[Resolver nombres en scope hijo<br/>+ scope padre]
F -->|process| H[Procesar Process anidado<br/>SyntentizeSensitiveList]
F -->|component_instantiation| I[Resolver entity ref con<br/>iterador como generic]
F -->|generate anidado| J[Recursion: nuevo scope hijo]
G --> E
H --> E
I --> E
J --> E
F -->|end generate| K[Validar nombre = label]
K --> L[Cerrar scope hijo,<br/>iterador liberado]
L --> M([Fin: bindings disponibles para Interpreter])
fig_5_11_9_act_record_types — Resolución de tipos record (nuevo)
flowchart TD
A([Declaracion: type T is record ...]) --> B[ArchitectureAssignationParser detecta record]
B --> C[Crear Variable typeDef con<br/>CustomTypeName=T y RecordFields={}]
C --> D[Por cada campo del record]
D --> E[Leer nombre del campo + tipo]
E --> F[RecordFields[name] = default por tipo]
F --> G{Mas campos?}
G -->|Si| D
G -->|No| H[Registrar tipo T en scope]
H --> I([Tipo disponible para declaraciones])
J([Asignacion: signal x : T := ...]) --> K[Crear Variable x con<br/>CustomTypeName=T]
K --> L[Copiar RecordFields del typeDef]
L --> M([Variable lista en scope])
N([Acceso: x.field <= value]) --> O[DataStructuresParser: detectar punto]
O --> P[Resolver x en Scopes]
P --> Q{Existe x.RecordFields[field]?}
Q -->|No| R[Diagnostico: campo desconocido]
Q -->|Si| S[Generar asignacion sobre<br/>RecordFields[field]]
S --> T([Operacion lista para Interpreter])
Historial de cambios
Versión 1.14.0 (2026-04-19)
- Diagnósticos estructurados — nuevo tipo
Parser.Models.DiagnosticconDiagnosticSeverity(Info / Warning / Error) y línea / columna / código / mensaje.Diagnostic.FromException(ParserException)adapta el flujo existente basado en excepciones a la nueva colección sin romper a los llamadores. - Enganche del linter — los llamadores aguas abajo (véase
Debugger.Repositories.Parser) ahora pueden ejecutar una pasada no fatal que reporta los;faltantes al final de las sentencias y el desbalance de bloquesbegin/endantes de que se ejecute el analizador completo. Aborda la queja de larga data de que el analizador aceptaba silenciosamente fuentes a las que les faltaban terminadores en tiempo de simulación. - Integración con el editor — estos diagnósticos se mapean a la API
setModelMarkersde Monaco medianteKmila.Shared/Pages/Editor.razor, de modo que los errores de sintaxis ahora se iluminan en el margen en lugar de aparecer solo en una notificación (toast). - Higiene de compilación — se agregó
<NoWarn>para la cascada de documentación XML (CS1587 / CS1591 / CS1570) causada por las listas de constantes separadas por comas enModels/Constants.cs. El proyecto compila sin advertencias sin el trabajo pesado de dividir cada constante de regex en su propia declaración.
Novedades de la v1.15 (2 de mayo de 2026)
La superficie del analizador ahora acepta:
procedure name(...) is ... end name;en el encabezado de la arquitectura (#12).- Instanciación directa de entidad
label : entity work.Sub[(arch)] port map(...)(#13). - Valores predeterminados de genéricos con expresiones aritméticas, por ejemplo
TOTAL : integer := BASE * TIMES(#16). - Los números de línea en los diagnósticos de error ahora referencian el archivo fuente del usuario (no el contador de llamadas del tokenizer) mediante la nueva sobrecarga
Tokenizer.TokenizeLineAt(text, sourceLineZeroBased)(#21).
Memoria: Tokenizer.Evaluate() ahora libera el búfer _tokens en bruto una vez que _typeDictionary está construido. GC de estación de trabajo (Workstation GC) habilitado a nivel de proyecto para dirigirse a dispositivos de poca RAM (#7).
Notas de versión completas: Documentacion/CHANGELOG_v1.15.md.
Pasada de rigurosidad (2026-05-17)
PortsParser ahora rechaza dos clases de descuidos en la declaración de puertos que antes pasaban silenciosamente. Ambas fueron reportadas por Daniel como parte de la reproducción del contador de rizo (ripple-counter) "Visible Wave" que compilaba sin problemas a pesar de errores tipográficos evidentes — véase el apéndice de Documentacion/CHANGELOG_concepts_module_2026-05-17.md y la entrada de memoria project_vhdl_parser_too_lenient.md.
Tipo de puerto desconocido → error "¿quiso decir …?"
Cuando el identificador de tipo en una declaración de puerto se captura como un IDENTIFIER (no como un KEYWORD reconocido) Y su valor sin distinción de mayúsculas está dentro de una distancia de Levenshtein 2 de cualquier nombre canónico de tipo VHDL en Constants.KNOWN_TYPE_NAMES, el analizador ahora lanza una ParserException con una pista "Did you mean '
| Token de origen | Canónico | Distancia | Comportamiento |
|---|---|---|---|
STDLOGIC |
std_logic |
1 (falta _) |
rechazado |
STD_LGIC |
std_logic |
1 (falta O) |
rechazado |
coefficient_array_t |
ninguno cercano | > 2 | aceptado como tipo definido por el usuario |
El auxiliar de Levenshtein reside en Constants.cs:LevenshteinDistance (privado, búfer rotativo de dos filas). Constants.FindTypoSuggestion(string) es el punto de entrada público — pase el identificador de origen y obtenga de vuelta el nombre canónico más cercano o null cuando el identificador parece legítimo.
Falta ; entre puertos
El bucle Parse() ahora detecta el caso en el que una declaración de puerto termina y el siguiente token es otro IDENTIFIER (en lugar de ; o )). Genera una ParserException que dice "Missing ';' before port '
Suite de pruebas negativas
Program.cs ganó una segunda pasada de pruebas para fixtures "que deben fallar". Cada entrada es un par (filename, mustContainSubstring); un PASS significa que el analizador generó la excepción esperada y el mensaje contenía la subcadena requerida. El código de salida del ejecutor es distinto de cero a menos que pasen tanto los 40 fixtures positivos COMO cada fixture negativo — de modo que las regresiones no pueden reaflojar silenciosamente la rigurosidad.
Cobertura negativa actual (raíz del Parser, junto a los test1..test40.vhdl existentes):
test_negative_unknown_type.vhdl— error tipográficoSTDLOGICen un tipo de puerto (debe contenerSTDLOGIC).test_negative_missing_port_semi.vhdl— al puerto le falta;antes del siguiente puerto (debe contenerMissing ';').test_negative_garbage_in_body.vhdl— token$extraviado en el cuerpo de la arquitectura (debe contenerUnexpected token '$').
Agregar más es una entrada en el arreglo negativeTests + un archivo test_negative_*.vhdl en la raíz del Parser.
Última actualización: 2026-08-03