Entradas para la categoría 'Artículos'

Creando un visor de XML (Parte II)

Miércoles 13 de Septiembre de 2006 a las 23:59

Este artículo es la continuación de:

Creando un visor de XML (Parte I)

POBLANDO EL TREEVIEW:

El proceso es muy similar al descrito anteriormente, salvo que ahora en vez de transformar el árbol en una cadena de texto formateada, se irán incluyendo sus nodos jerárquicamente en un TreeView.

Para poblar el TreeView también nos basaremos en dos funciones, una para inicializar las variables y cargar el documento xml, y otra que será llamada de forma recursiva.

VB.NET:
  1. Private Sub MostrarArbol(ByVal consultar As Boolean)
  2.         Dim arbol As New Xml.XmlDocument
  3.         Dim nodoRaiz As TreeNode
  4.         Dim atr As Xml.XmlAttribute
  5.  
  6.         'Utilizados solo para hacer la consulta
  7.         Dim nodosSeleccionados As Xml.XmlNodeList
  8.  
  9.         Try
  10.             arbol.LoadXml(rtxtXML.Text)
  11.  
  12.             trvXML.Nodes.Clear()
  13.             nodoRaiz = New TreeNode(arbol.DocumentElement.Name)
  14.             For Each atr In arbol.DocumentElement.Attributes
  15.                 nodoRaiz.Text &= "   " & atr.Name & "=" & atr.Value
  16.             Next
  17.             trvXML.Nodes.Add(nodoRaiz)
  18.  
  19.             If consultar Then
  20.                 nodosSeleccionados = arbol.SelectNodes(txtConsulta.Text)
  21.                 If estaSeleccionado(arbol.DocumentElement, nodosSeleccionados) Then
  22.                     nodoRaiz.ForeColor = Color.Blue
  23.                     nodoRaiz.NodeFont = fuenteNegritaArbol
  24.                 End If
  25.                 AnadirNodosAArbol(nodoRaiz, arbol.DocumentElement, nodosSeleccionados)
  26.             Else
  27.                 AnadirNodosAArbol(nodoRaiz, arbol.DocumentElement)
  28.             End If
  29.  
  30.             trvXML.ExpandAll()
  31.  
  32.         Catch ex As Exception
  33.             MsgBox("Se ha producido el siguiente error:" & vbCrLf & vbCrLf & " - " & ex.Message)
  34.         End Try
  35.  
  36.     End Sub
  37.  
  38.     Private Sub AnadirNodosAArbol(ByVal arbol As TreeNode, ByVal nodo As Xml.XmlNode, Optional ByVal nodosSeleccionados As Xml.XmlNodeList = Nothing)
  39.         Dim hijo As Xml.XmlNode
  40.         Dim atr As Xml.XmlAttribute
  41.         Dim nodoArbol As TreeNode
  42.  
  43.         For Each hijo In nodo.ChildNodes
  44.             If hijo.NodeType <> Xml.XmlNodeType.Text And hijo.NodeType <> Xml.XmlNodeType.Comment Then
  45.                 nodoArbol = New TreeNode(hijo.Name)
  46.                 If Not nodosSeleccionados Is Nothing Then
  47.                     If estaSeleccionado(hijo, nodosSeleccionados) Then
  48.                         nodoArbol.ForeColor = Color.Blue
  49.                         nodoArbol.NodeFont = fuenteNegritaArbol
  50.                     End If
  51.                 End If
  52.                 arbol.Nodes.Add(nodoArbol)
  53.                 If textoDelNodo(hijo) <> "" Then
  54.                     nodoArbol.Text &= "=" & textoDelNodo(hijo)
  55.                 End If
  56.                 For Each atr In hijo.Attributes
  57.                     nodoArbol.Text &= "   " & atr.Name & "=" & atr.Value
  58.                 Next
  59.  
  60.                 anadirNodosAArbol(nodoArbol, hijo, nodosSeleccionados)
  61.             End If
  62.         Next
  63.     End Sub

COMPLETANDO LA HERRAMIENTA:

Con esto se habrá terminado el núcleo de nuestra aplicación, habiéndola dotado de la funcionalidad básica para la que se ideó, es decir, el mostrar el xml formateado para que resulte más legible, mostrarlo mediante un árbol y permitir seleccionar nodos mediante XPath visualizando aquellos que respondan a la expresión de búsqueda resaltados.

Vayamos ahora a dotarla de ciertos elementos adicionales para completar la aplicación.

En primer lugar le añadiremos la funcionalidad de permitir ajustar las líneas para que todo el texto de una línea se muestre en pantalla, ocupando las líneas que sean necesarias para mostrarse. Esto es tan sencillo como añadir un checkBox, y establecer la propiedad WordWrap de los RichTextBox al valor de la propiedad Checked del checkBox

Le añadiremos también la funcionalidad de cargar y guardar ficheros. Con este fin se crearán dos elementos de menú y se les asociarán teclas de acceso rápido, CTRL+C y CTRL+G respectivamente. El documento que guardaremos será el xml ya formateado, no el original.

Según vayamos cargando ficheros, éstos se irán incluyendo en la lista de recientes hasta un máximo de cinco. De igual forma incluimos en la lista de ficheros recientes aquéllos documentos que guardemos. El código que realiza esta inserción es el siguiente:

VB.NET:
  1. Private Sub InsertarEnRecientes(ByVal nombreFichero As String)
  2.         Dim menu As MenuItem
  3.         Dim i As Integer
  4.         Dim encontrado As Boolean
  5.  
  6.         Try
  7.             i = 0
  8.             While i <= mnuRecientes.MenuItems.Count - 1 And Not encontrado
  9.                 'Si ya estaba lo quitamos
  10.                 If mnuRecientes.MenuItems(i).Text = nombreFichero Then
  11.                     mnuRecientes.MenuItems.RemoveAt(i)
  12.                     encontrado = True
  13.                 End If
  14.                 i = i + 1
  15.             End While
  16.             menu = New MenuItem(nombreFichero, AddressOf FichReciente_Click)
  17.             mnuRecientes.MenuItems.Add(0, menu)
  18.             If mnuRecientes.MenuItems.Count = 6 Then
  19.                 mnuRecientes.MenuItems.RemoveAt(5)
  20.             End If
  21.         Catch ex As Exception
  22.             MsgBox("Se ha producido el siguiente error:" & vbCrLf & vbCrLf & " - " & ex.Message)
  23.         End Try
  24.  
  25.     End Sub

Cuando se cierre el formulario, se guardará la lista de ficheros recientes en un fichero XML, para que dicha listas persista entre ejecuciones de la aplicación.

VB.NET:
  1. Private Sub GuardarRecientes()
  2.         Dim arbol As New Xml.XmlDocument
  3.         Dim nodo As Xml.XmlNode
  4.         Dim menu As MenuItem
  5.  
  6.         Try
  7.             nodo = arbol.CreateElement("Recientes")
  8.             arbol.AppendChild(nodo)
  9.  
  10.             For Each menu In mnuRecientes.MenuItems
  11.                 nodo = arbol.CreateElement("Fichero")
  12.                 nodo.InnerText = menu.Text
  13.                 arbol.DocumentElement.AppendChild(nodo)
  14.             Next
  15.  
  16.             arbol.Save(Application.StartupPath & "\Recientes.xml")
  17.  
  18.         Catch ex As Exception
  19.             MsgBox("Se ha producido el siguiente error:" & vbCrLf & vbCrLf & " - " & ex.Message)
  20.         End Try
  21.     End Sub

 

Primera parte de este artículo:

Creando un visor de XML (Parte I)

Creando un visor de XML (Parte I)

Martes 12 de Septiembre de 2006 a las 23:58

En este artículo se describe el proceso de desarrollo de una pequeña herramienta que permitirá formatear un documento XML haciendo que resulte más legible, mostrarlo mediante un árbol, y seleccionar nodos mediante XPath visualizando aquéllos que respondan a la expresión de búsqueda resaltados. Adicionalmente se le añadirán otras características secundarias como el guardar y cargar ficheros, una lista de archivos recientes, ajuste de línea y expansión y contracción de todos los nodos del árbol. Es una herramienta sencilla pero que puede ser bastante útil para trabajar con XML.

Debido a sus dimensiones, este artículo ha sido dividido en dos partes. Se puede consultar la segunda parte en la siguiente dirección.

El resultado final de la aplicación mostrando sus tres vistas será el siguiente:

 

(Pulsad la imagen para verla a tamaño real)
Visor
Visor XML. Texto sin formatear.

 

(Pulsad la imagen para verla a tamaño real)
Visor
Visor XML. Vista en árbol.

 

(Pulsad la imagen para verla a tamaño real)
Visor
Visor XML. Texto formateado.

 

FORMATEANDO EL DOCUMENTO XML:

El código para formatear el texto se basa en dos funciones. La primera de ellas se llama FormatearTexto y se encargará de inicializar las variables, cargar el texto introducido en el primer RichTextBox en una variable del tipo XmlDocument. Esta primera función llamará a la segunda (IndentarXML), la cual es una función recursiva que se llamará así misma por cada nodo que tenga el arbol XML.

VB.NET:
  1. Private Sub FormatearTexto(ByVal consultar As Boolean)
  2.         Dim arbol As New Xml.XmlDocument
  3.         Dim profundidad As Integer
  4.         Dim cad As String
  5.  
  6.         'Utilizados solo para hacer la consulta
  7.         Dim nodosSeleccionados As Xml.XmlNodeList
  8.         Dim inicioNodosSeleccionados As ArrayList
  9.         Dim finalNodosSeleccionados As ArrayList
  10.         Dim i As Integer
  11.  
  12.         Try
  13.             arbol.LoadXml(rtxtXML.Text)
  14.  
  15.             profundidad = 0
  16.             cad = ""
  17.             rtxtTextoFormateado.Text = ""
  18.  
  19.             If arbol.FirstChild.NodeType = Xml.XmlNodeType.XmlDeclaration Then
  20.                 cad &= arbol.FirstChild.OuterXml & vbCr
  21.             End If
  22.             If consultar Then
  23.                 nodosSeleccionados = arbol.SelectNodes(txtConsulta.Text)
  24.                 inicioNodosSeleccionados = New ArrayList
  25.                 finalNodosSeleccionados = New ArrayList
  26.                 IndentarXML(arbol.DocumentElement, cad, 0, nodosSeleccionados, inicioNodosSeleccionados, finalNodosSeleccionados)
  27.                 rtxtTextoFormateado.Text = cad
  28.                 For i = 0 To inicioNodosSeleccionados.Count - 1
  29.                     rtxtTextoFormateado.Select(CInt(inicioNodosSeleccionados(i)), CInt(finalNodosSeleccionados(i)) - CInt(inicioNodosSeleccionados(i)))
  30.                     rtxtTextoFormateado.SelectionColor = Color.Blue
  31.                     rtxtTextoFormateado.SelectionFont = fuenteNegritaRTXT
  32.                 Next
  33.             Else
  34.                 IndentarXML(arbol.DocumentElement, cad, profundidad)
  35.                 rtxtTextoFormateado.Text = cad
  36.             End If
  37.         Catch ex As Exception
  38.             MsgBox("Se ha producido el siguiente error:" & vbCrLf & vbCrLf & " - " & ex.Message)
  39.         End Try
  40.     End Sub
  41.  
  42.     Private Function IndentarXML(ByVal nodo As Xml.XmlNode, ByRef cad As String, ByVal profundidad As Integer, Optional ByVal nodosSeleccionados As Xml.XmlNodeList = Nothing, Optional ByVal inicioNodosSeleccionados As ArrayList = Nothing, Optional ByVal finalNodosSeleccionados As ArrayList = Nothing) As String
  43.         Dim hijo As Xml.XmlNode
  44.         Dim atr As Xml.XmlAttribute
  45.  
  46.         If nodo.NodeType <> Xml.XmlNodeType.Text And nodo.NodeType <> Xml.XmlNodeType.Comment Then
  47.             'cad &= New String(Chr(9), profundidad)
  48.             cad &= New String(" "c, profundidad * 7)
  49.  
  50.             If Not nodosSeleccionados Is Nothing AndAlso estaSeleccionado(nodo, nodosSeleccionados) Then
  51.                 If cad = "" Then
  52.                     inicioNodosSeleccionados.Add(0)
  53.                 Else
  54.                     inicioNodosSeleccionados.Add(cad.Length - 1)
  55.                 End If
  56.  
  57.             End If
  58.  
  59.             cad &= "<" & nodo.Name
  60.             For Each atr In nodo.Attributes
  61.                 cad &= " " & atr.Name & "=""" & atr.Value & """"
  62.             Next
  63.             cad &= ">"
  64.  
  65.             If Not nodosSeleccionados Is Nothing AndAlso estaSeleccionado(nodo, nodosSeleccionados) Then
  66.                 finalNodosSeleccionados.Add(cad.Length)
  67.             End If
  68.  
  69.             cad &= textoDelNodo(nodo)
  70.  
  71.             If tieneHijos(nodo) Then
  72.                 cad &= vbCr
  73.                 For Each hijo In nodo.ChildNodes
  74.                     IndentarXML(hijo, cad, profundidad + 1, nodosSeleccionados, inicioNodosSeleccionados, finalNodosSeleccionados)
  75.                 Next
  76.                 'cad &= New String(Chr(9), profundidad)
  77.                 cad &= New String(" "c, profundidad * 7)
  78.             End If
  79.             cad &= "</" & nodo.Name & ">" & vbCr
  80.         End If
  81.     End Function

La función "FormatearTexto" recibe un parámetro que indica si se está realizando una consulta o no. Si es así, se obtendrán todos los nodos seleccionados por la consulta y se crearán dos arrayList para almacenar las posiciones iniciales y finales de los nodos seleccionados, para poder posteriormente resaltarlos en el RichTextBox.

La función "IndentarXML" se encarga de transformar el nodo en cadena formateada y de llamarse a si misma recursivamente por cada hijo que tuviera el nodo. El parámetro profundidad se va incrementando en uno en cada nivel del árbol, y sirve para tabular correctamente el texto de cada nodo. Si se esta consultando y el nodo actual pertenece a los nodos seleccionados por la consulta XPath, entonces se marcará su posición inicial y final añadiéndolas a los arrayList.

Continuación
Creando un visor de XML (Parte II)

Coloreando el código en el editor

Lunes 4 de Septiembre de 2006 a las 23:56

Una funcionalidad muy fácil de implementar y que resulta interesante es la de colorear en el editor de código que estoy creando las palabras del script dependiendo del tipo de palabra del que se trate.

Teniendo implementado el analizador léxico desarrollar esta funcionalidad es trivial. Para empezar lanzamos el analizador léxico y recibimos la colección de palabras que componen el script. Para cada una de ellas tendremos el tipo de palabra de que se trata y su posición en el script, indicada por su línea y columna. Con esta información simplemente seleccionaremos en el control RichTextBox que contiene el código las palabras que queramos resaltar y establecemos el color deseado según el tipo de palabra.

Se ha decidido colorear las palabras reservadas y las constantes lógicas (verdadero y falso) de azul, las cadenas de caracteres de color morado y los errores de color rojo. El resto de palabras permanecerán de color negro.

Esta es la apariencia que muestra el código una vez coloreado:

 

Texto coloreado.
Texto coloreado.

 

La palabra entera no la colorea de azul porque no es un tipo valido, el tipo es "numerica".

El código empleado en VB.NET es el siguiente:

 

VB.NET:
  1. ''' <summary>
  2.     ''' Colorea las palabras del script existente en una RichTextBox.
  3.     ''' </summary>
  4.     ''' <param name="rtxt"></param>
  5.     ''' <param name="r"></param>
  6.     ''' <remarks></remarks>
  7.     Private Sub ColorearCodigo(ByVal rtxt As RichTextBox, ByVal r As ResultadoAnalizadorLexico)
  8.         Dim p As Palabra
  9.  
  10.         For Each p In r.Palabras
  11.             If p.Tipo = TipoPalabra.Palabra_Reservada Or p.Tipo = TipoPalabra.Erronea Or p.Tipo = TipoPalabra.CTE_Logica Or p.Tipo = TipoPalabra.CTE_Cadena Then
  12.                 'Quitamos 1 tanto a la línea como a la columna por que están en base 1 y el richtexbox maneja base 0
  13.                 rtxt.SelectionStart = rtxtCodigo.GetFirstCharIndexFromLine(p.Linea - 1) + p.Columna - 1
  14.                 rtxt.SelectionLength = p.Palabra.Length
  15.             End If
  16.             Select Case p.Tipo
  17.                 Case TipoPalabra.Palabra_Reservada, TipoPalabra.CTE_Logica
  18.                     rtxt.SelectionColor = Color.Blue
  19.                 Case TipoPalabra.Erronea
  20.                     rtxt.SelectionColor = Color.Red
  21.                 Case TipoPalabra.CTE_Cadena
  22.                     rtxt.SelectionColor = Color.Purple
  23.             End Select
  24.         Next
  25.     End Sub

Creando un analizador léxico (Parte II)

Domingo 27 de Agosto de 2006 a las 23:35

Este artículo es la continuación de:

Creando un analizador léxico (Parte I)

Trás definir todos los posibles tokens procederemos a la implementación del analizador léxico que los reconocerá.

El analizador antes de poder reconocer los tokens debe fraccionar el código fuente en las palabras que lo componen, teniendo en cuenta para ello los separadores (salto de línea y espacio en blanco). Además se debe tener en cuenta que los espacios en blanco dentro de una cadena no deben ser tenidos en cuenta.

Una vez separadas todas las palabras existentes en el código fuente se deben intentar reconocer cada una de ellas. Para ello nos serviremos de autómatas finitos deterministas, que desarrollaremos según lo expuesto en un artículo anterior, para los componentes léxicos más complejos. Para aquellas palabras cuyo reconocimiento es trivial, como los operadores o las palabras reservadas, simplemente compararemos con dichas elementos. Como se muestra en el siguiente fragmento de código que es utilizado para reconocer si una palabra es una constante lógica o no.

VB.NET:
  1. Private Shared Function EsConstanteLogica(ByVal palabra As String) As Boolean
  2.     Return palabra.ToUpper = "VERDADERO" Or palabra.ToUpper = "FALSO"
  3. End Function

El analizador recibe como parámetros la ruta de un fichero que contiene el script, una cadena con el script o un array de cadenas conteniendo cada una línea del script. Como salida genera una colección de palabras o componentes léxicos. Para cada uno de ellos se proporciona la siguiente información:

  • Palabra en si tal y como aparece en el script
  • Tipo de componente léxico
  • Componente sintáctico con que se corresponde y que será utilizado posteriormente por el analizador sintáctico
  • Linea y columna del script en la que aparece la palabra. Utilizado para mostrar los errores resaltándolos en el código del script y notificar en que punto se ha producido el posible error.

El analizador reconoce los siguientes componentes léxicos:

  • Identificador
  • CTE_Cadena
  • CTE_Numerica
  • CTE_Logica
  • Palabra_Reservada
  • Simbolo_Especial ",", "(" y ")"
  • Operador
  • Salto_Linea
  • Fin_Fichero
  • Erronea

La siguiente entrada del analizador léxico:

n1 "hola" "hño l!'a" "\\as" "ac\\as\"11\"22\"dd fas" c2
fin
variable 3 * a verdadero Y
fas"dfas "as"asf"
"a\aas" 1234.34
c3 c3 "AAAA BB
CC"
"fasdfs\"
numerica 3 / 456 <> != 3 O
fadvariable c3
si
falso
cadena
( , 3 )

produce la siguiente salida:

Salida del analizador léxico.
Salida del analizador léxico.

Creando un analizador léxico (Parte I)

Creando un analizador léxico (Parte I)

Domingo 27 de Agosto de 2006 a las 2:06

Este artículo versa acerca del desarrollo de un analizador léxico. Debido a su tamaño ha sido dividido en dos partes, siendo este la primera parte y esta la segunda.

La función de un analizador léxico es examinar el código fuente y reconocer las palabras o tokens que formen parte del lenguaje así como determinar si hay elementos que no pertenecen al lenguaje. Como resultado del análisis léxico se devolverá la lista de tokens que forman el código fuente.

Lo primero que debemos hacer es definir los tipos de palabras que compondrán el lenguaje así como las reglas para formar palabras

En el lenguaje que estoy creando he identificado los siguientes tipos de palabras:

  • Identificadores
  • Cadenas
  • Valores o constantes numéricas
  • Valores o constantes lógicas
  • Palabras reservadas
  • Símbolos especiales como ",", "(" y ")"
  • Operadores
  • Saltos de línea
  • Fin de fichero

Dicho lenguaje pretende ser bastante sencillo y fácil de utilizar. Por ello se utilizan palabras en castellano en vez de en ingles como la mayoría de lenguajes de programación.

Ahora pasaremos a definir las reglas de formación de cada uno de esos tipos de palabras. Hay tipos de palabras que se definen por enumeración como son los operadores, los símbolos especiales, las palabras reservadas, etc. Para definir otros tipos de tokens utilizaremos autómatas finitos deterministas como ya se explico en el artículo Autómata finito determinista para reconocer constantes numéricas.

Definiciones

  • Operadores:
    • + , -, *, /, =, !=, <, >, >=, <=, Y, O

  • Palabras reservadas:
    • Variable: para declarar variables
      Constante: para declarar constantes
      Logica: tipo de dato
      Cadena: tipo de dato
      Numerica: tipo de dato
      Si: Forma parte de la estructura condicional
      Entonces: Forma parte de la estructura Condicional
      Fin: Forma parte de la estructura Condicional e Iterativa
      Mientras: Forma parte de la estructura Iterativa

  • Símbolos especiales:
    • (, ) y ,

  • Constantes lógicas:
    • Verdadero, Falso

  • Constante cadena:
    • Secuencia de caracteres delimitados por las comillas (“) Si la cadena contiene el carácter “ o \ debe ir precedido del carácter de escape \
    A.F.D. Reconocedor de cadenas.
    A.F.D. Reconocedor de cadenas.

  • Constante numérica:
    • Una constante numérica debe estar formada por al menos un dígito, puede ir precedida o no por el signo y puede tener o no decimales. Si contiene el punto decimal debe tener al menos un dígito en la parte de los decimales.
    A.F.D. Reconocedor de ctes numéricas.
    A.F.D. Reconocedor de ctes numéricas.

  • Identificadores:
    • Una letra seguida una secuencia de 0 o más letras o dígitos o el signo _
    A.F.D. Reconocedor de identificadores.
    A.F.D. Reconocedor de identificadores.

Continuación
Creando un analizador léxico (Parte II)

Autómata finito determinista para reconocer constantes numéricas

Domingo 20 de Agosto de 2006 a las 23:06

En este breve artículo voy a explicar el proceso de creación de un sencillo autómata finito determinista para reconocer constantes numéricas. Este autómata forma parte del analizador léxico que estoy implementando para el lenguaje de script, que utilizaré en el motor de aventuras gráficas que estoy desarrollando.

Al final del artículo incluiré el código del autómata en su totalidad.

Lo primero que debemos hacer es definir lo que será una constante numérica valida. Una constante numérica debe estar formada por al menos un dígito, puede ir precedida o no por el signo y puede tener o no decimales. Si contiene el punto decimal debe tener al menos un dígito en la parte de los decimales.

Autómata finito determinista reconocedor de constantes numéricas.
Autómata finito determinista reconocedor de constantes numéricas.

Se trata de un autómata conexo ya que todos los estados son accesibles desde el inicial. Es un autómata determinista, ya que desde un estado y para una determinada entrada solo existe transición a un estado, nunca a varios estados.

Una vez definida la constante numérica formalmente mediante el diagrama de estados anterior, la implementación del autómata es muy sencilla. Debemos definir cuales serán los estados finales (aquellos marcados con un doble circulo en la imagen) y que transiciones son válidas para cada estado según las entradas que reciba y cuales no. Una vez procesados todos los caracteres que forman la palabra, la habremos reconocido como una constante numérica correcta, si no se ha producido ninguna transición no válida y si estamos en uno de los estados finales.

VB.NET:
  1. Option Explicit On
  2. Option Strict On
  3.  
  4. ''' <summary>
  5. ''' Autómata finito determinista que reconoce constantes numéricas. Pueden tener signo inicial y contener
  6. ''' el punto decimal o no. Si tiene el punto decimal debe tener al menos un digito despues. El 012 se
  7. ''' considera correcto
  8. ''' </summary>
  9. ''' <remarks></remarks>
  10. Public Class AFDCteNumerica
  11.     Private Const ESTADO_FINAL_1 As Integer = 2
  12.     Private Const ESTADO_FINAL_2 As Integer = 4
  13.  
  14.     Public Shared Function Reconocer(ByVal p As String) As Boolean
  15.         Dim estado As Integer
  16.         Dim correcto As Boolean
  17.         Dim i As Integer
  18.         Dim c As Char
  19.  
  20.         estado = 0 'estado inicial
  21.         i = 0
  22.         correcto = True
  23.         'recorremos todos los carácteres de la palabra
  24.         While correcto And i <p.Length
  25.             c = p.Chars(i)
  26.  
  27.             If Char.IsDigit(c) Then
  28.                 Select Case estado
  29.                     Case 0
  30.                         estado = 2
  31.                     Case 1
  32.                         estado = 2
  33.                     Case 2
  34.                         estado = 2
  35.                     Case 3
  36.                         estado = 4
  37.                     Case 4
  38.                         estado = 4
  39.                 End Select
  40.             ElseIf c = "."c Then
  41.                 Select Case estado
  42.                     Case 0
  43.                         correcto = False
  44.                     Case 1
  45.                         correcto = False
  46.                     Case 2
  47.                         estado = 3
  48.                     Case 3
  49.                         correcto = False
  50.                     Case 4
  51.                         correcto = False
  52.                 End Select
  53.             ElseIf c = "+"c Or c = "-"c Then
  54.                 Select Case estado
  55.                     Case 0
  56.                         estado = 1
  57.                     Case 1
  58.                         correcto = False
  59.                     Case 2
  60.                         correcto = False
  61.                     Case 3
  62.                         correcto = False
  63.                     Case 4
  64.                         correcto = False
  65.                 End Select
  66.         &