Nota del autor

Si la entrada que estás leyendo carece de imágenes, no se ve el vídeo que teóricamente lleva incrustado o el código fuente mostrado aparece sin formato, podéis conocer los motivos aquí. Poco a poco iré restableciendo la normalidad en el blog.
Este blog es un archivo de los artículos situados previamente en Lobosoft.es y ha dejado de ser actualizado. Las nuevas entradas pueden encontrarse en www.lobosoft.es. Un saludo,
Lobosoft.
Mostrando entradas con la etiqueta metaprogramación. Mostrar todas las entradas
Mostrando entradas con la etiqueta metaprogramación. Mostrar todas las entradas

miércoles, 22 de abril de 2009

Ironías de la vida

Hace tiempo “regresé” a los tiempos de la carrera al llevar a cabo un trabajo relacionado con ASN.1, ya que estaba relacionado con el análisis léxico y sintáctico de definiciones llevadas a cabo usando esta notación. Aunque las asignaturas relacionadas con este campo más formal de los lenguajes de programación no eran las que más me apasionaban, lo cierto es que llegaron a gustarme bastante en su día, y comprobé la evolución que habían sufrido herramientas de análisis sintáctico y semántico, como los clásicos lex y yacc, e incluso sus “descendientes” Flex/Bison o JFlex/Cup, para llegar a un generador de analizadores como el potente ANTLR, capaz de generar un analizador léxico, sintáctico o semántico en varios lenguajes (Java, C#...) a partir de una serie de reglas EBNF.


Así las cosas, no es de extrañar que, unos meses después investigase un poco más por mi cuenta en este campo, y me encontrase con una interesante herramienta que, de manos de Roman Ivantsof, tenemos disponible en Codeplex. Se trata de Irony.NET, un generador de compiladores/interpretes para los lenguajes definidos a partir de una gramática. Hasta aquí, nada novedoso. Pero lo interesante es que las gramáticas LALR(1) se definen directamente en C#, utilizando las clases que la propia plataforma proporciona, usando claro está notación BNF. A partir de esta definición de la gramática, puede generarse el árbol sintáctico de una entrada en dicho lenguaje. Por ejemplo, un SELECT de SQL quedaría definido así:



La distribución de la herramienta, al estar en Codeplex, es a partir de su código fuente, por lo que podemos bajar la solución completa para estudiarla y ejecutarla. Incorpora varias gramáticas definidas como ejemplo, entre las que se incluyen lenguajes tan suculentos como C#, Ruby o Python, e incluso SQL y JSON.


Si ejecutamos el proyecto de prueba Irony.GrammarExplorer, podemos “cargar” la DLL con las gramáticas definidas en el proyecto Irony.Samples como si de un plugin se tratase, así comoactivarlas y desactivarlas.



Incluso es posible escribir código en el explorador y estudiar la generación de código y del árbol de sintaxis abstracta para la entrada. tanto en forma de árbol "visual" como en XML:




Todo un descubrimiento que puede ayudarnos a mejorar nuestro conocimiento sobre la generación de compiladores e intérpretes de lenguajes, así como a crear los nuestros propios. ¿Qué tal un parser para aventuras conversaciones, como los clásicos PAWS o Inform? ;)

miércoles, 21 de enero de 2009

Editores de código fuente

Aunque la ayuda de la sintaxis coloreada, autocompletar y otras argucias de los entornos de programación y editores de código fuente nos hacen la vida más fácil, lo cierto es que cuando conocemos en profundidad un lenguaje, generalmente, terminamos por olvidar lo fácil que nos hicieron la vida y cómo se codificaba con herramientas tan rudimentarias como el bloc de notas, editores poco más avanzados que el edit de MS-DOS o con pico, para los que teníamos la suerte de poder sustituir con el mismo el uso de vi.


Sin embargo, es en momentos en los que tenemos que enfrentarnos a nuevos lenguajes (al menos nuevos en el sentido de no conocerlos en profundidad) cuando es más útil que nunca contar con un editor apropiado que nos haga más liviana la tarea. Generalmente suelo usar PSPad para editar archivos de texto (también binarios, en hexadecimal), o de código fuente cuando no tengo un editor más específico a mano. Hay bastante gente que prefiere Notepad++, un editor igualmente completo, y la verdad es que probados ambos, es difícil decantarse por uno u otro, porque sus prestaciones son similares y donde flaquea uno, el otro se hace más fuerte. Son, por tanto, herramientas complementarias igualmente potentes, y la elección de uno u otro vendrá dada más por los gustos personales del usuario que por cualquier otra razón.


Sin embargo, hay momentos en los que conviene explorar otros caminos, otras herramientas, y precisamente hoy ha sido uno de esos días. Andaba esta mañana analizando una serie de ficheros ASN.1 con una serie de especificaciones, y ni Notepad++ reconocía la sintaxis, ni la que incorpora PSPad (que viene desactivada de forma predeterminada, y hay que habilitar a través del correspondiente menú de opciones de configuración) ha terminado de convencerme. Incluso he tenido que agregar características tan básicas de la sintaxis como los caracteres que corresponden a los comentarios. Así que me he dicho: ¿habrá por ahí editores “ligeros” que incluyan ésta y otras sintaxis menos comunes? Dicho y hecho, me he puesto a buscar y he encontrado Crimson Editor, un editor llamado a ser sustituido por Emerald Editor, del que no he encontrado una versión compilada (de momento) y que, aunque tiene una interfaz de usuario un tanto espartana, cumple sobradamente con lo que podemos pedir a un editor de código fuente, aunque tiene bastantes carencias respecto a los dos que nombraba anteriormente; en particular, echo de menos la edición “directa” a sitios FTP y remotos.



Sin embargo, para mis necesidades era perfecto. Tiene una gran cantidad de lenguajes en su “base de datos” de sintaxis, y la de ASN.1 la muestra a la perfección. En cualquier caso, me resulta extraño que, por ejemplo, PSPad admita el tipo de comentarios de este lenguaje (--), pero sin embargo no lo trate adecuadamente. Habrá que seguir investigando, pero de momento el “problemilla” me ha permitido conocer este editor.


¿Alguno de vosotros había usado antes el Crimson Editor? ¿Qué editor/es de código fuente de este tipo soléis usar?

lunes, 30 de junio de 2008

Google Code Search

 codesearch_logo.gif


En los días pasamos hemos visto algunas de las herramientas que brinda Google desde su sección de investigación y desarrollo, Google Labs, como pueden ser Google Sets, un buscador de conjuntos de palabras relacionadas con aquellas que especifiquemos en las consultas, pequeños trucos y utilidades incorporadas en Google Docs, incluido el uso de funciones avanzadas como Google LookUp, o herramientas como generadores de gráficos (Google Chart Image Generator). Incluso surgen iniciativas de terceros en torno al buscador más usado del mundo, como el entorno "textual" de Google, el Google Shell. Así, el Premio Príncipe de Asturias 2008 en Comunicación y Humanidades (por más que se presente como un mal referente desde el punto de vista ético), es ciertamente una de las empresas que más apuesta en investigación tecnológica, y más abierta se muestra hacia la comunidad de desarrolladores y usuarios (algo lógico, desde el punto de vista comercial).


Para esta comunidad de desarrolladores, Google ofrece utilidades como Google Code, un repositorio de proyectos software (similar al CodePlex que apoya Microsoft, o a páginas de ejemplos, como CodeProject o las siempre presentes La web del programador, La página de El Guille y similares). Pues bien, además de éste proyecto, Google incluye un buscador de código fuente (beta) llamado Google Code Search, con interesantes funciones como el uso de expresiones regulares en las búsquedas o el filtrado por tipo de licencia. Por ejemplo, podríamos buscar códigos donde se usara una determinada función, o se incluyese una librería específica, y que además fuesen distribuidas bajo los términos de una licencia GPL. Un interesante recurso que a buen seguro será útil para los desarrolladores, sea cual sea su lenguaje de programación preferido.



gcs.PNG

martes, 6 de mayo de 2008

Despliegue de nuestro propio DSL

Hace unos días veíamos cómo crear una herramienta personalizada mediante el uso de las DSL Tools que proporciona el SDK de Visual Studio 2008. Si bien podemos desarrollar y probar nuestro DSL que a tal efecto proporciona el Experimental Hive de Visual Studio, lo cierto es que una vez desarrollado el producto, e incluso durante el proceso de desarrollo, podemos desear comprobar cómo funciona el mismo en un entorno de pre-producción. Para ello, debemos generar un proyecto de despliegue (un setup) para el proyecto DSL, y aunque no es un proceso precisamente trivial, ya que implica la vinculación de extensiones de archivos a nuestro editor DSL mediante la modificación del Registro de Windows, y la instalación de determinados archivos en ubicaciones muy específicas, lo cierto es que el propio Visual Studio proporciona un tipo de proyecto que puede facilitarnos la tarea.


En principio, como avanzamos, realizar un proyecto de instalación de un DSL no es algo sencillo, a pesar de lo que pueda parecernos inicialmente cuando empezamos a trabajar con ellos, ya que estamos hablando de la instalación de un Visual Studio Package. Para obtener el mejor rendimiento y aprovechar al máximo la capacidad del instalador deberíamos hacernos con WiX (Windows Instaler XML), un potente entorno de despliegue basado en XML, y distribuido libre de licencia por Microsoft. Existe un excelente tutorial de WiX en Internet, además de lo que podemos leer en la página oficial del producto, y también podemos usar herramientas comerciales como la Software Factories Toolkit, que al fin y al cabo está basada en WiX.


En cualquier caso, y de momento, vamos a basarnos en el proyecto de instalación para DSLs que incorpora Visual Studio, y que también se basa en WiX para crear un entorno sencillo aunque en principio limitado para la instalación de nuestros productos.


En principio, para la instalación de un diseñador DSL necesitaremos los archivos siguientes:




  • .msi del diseñador.

  • .msi del DSL Tools Redistributable, ya que si el equipo destino de la instalación no tiene instaladas las DSL Tools (a partir del SDK de Visual Studio) el diseñador no funcionaría. También es posible que necesitemos registrar una Package Load Key (PLK). En la página de VS Extensibility de Microsoft se puede encontrar más información sobre este proceso. En cualquier caso, la PLK se aplicará sobre la clase package (Shell\Package.tt), mediante el atributo VSShell::ProvideLoadKey(keynumber)]. La PLK se almacenará en el fichero de recursos VSPackage.resx.

  • setup.exe, encargado de instalar en el orden adecuado, y si son necesarios, los distintos .msi.

  • settings.ini, con la configuración necesaria para el setup.exe.

  • Archivos adicionales, como el Readme o la licencia del producto.


 


dslsetup01.PNG


Así pues, comenzaremos el trabajo de generación del instalador abriendo nuestra solución DSL (compuesta por los proyectos DSL y DSL Package), y agregando un nuevo proyecto de tipo DSL Setup. El proyecto se compone básicamente de una serie de archivos, cuya finalidad es la siguiente:

  • .dslsetup: información sobre los componentes del DSL. A partir de la misma los text templates (.tt) generarán los archivos necesarios para la compilación de WiX. En este archivo se añadirán todos los recursos necesarios para la instalación y funcionamiento del DSL (.TT's, .DLL's, etc.).

  • settins.ini: información para setup.exe. Identifica el .msi del producto, incluyendo su nombre. Sólo debe modificarse si el nombre del producto sufre algún cambio.

  • Strings.wxl: UI del wizard de instalación. Permite cambiar los lenguajes, localización, etc.

  • Product.ico: El icono del producto. Será el que Windows muestre en el Panel de Control, dentro de Añadir y Quitar Programas.


Si realizamos cualquier cambio en la definición del diseñador DSL deberemos seguir los siguientes pasos:




  1. Rebuild de los proyectos DSL y DSL Package.

  2. Regenerar los ficheros para WiX a partir de los Text Templates.

  3. Rebuild del proyecto DSL Setup.


Además de esto, para disponer del proyecto DSL en nuestro instalador deberemos hacer lo siguiente:




  1. Ejecutar el proyecto DSL para abrir el Visual Studio Experimental Hive. Una vez dentro, limpiaremos el proyecto DSL para dejarlo tal y como nos gustaría que quedase un nuevo proyecto basado en el mismo (únicamente los archivos .tt necesarios y algún fichero del modelo recién creado, por ejemplo Sample1.mydsl), y hacer un Clean Up del proyecto.

  2. Seleccionamos el proyecto en la solución.

  3. Dentro del menú Archivo (File) de Visual Studio Experimental Hive, seleccionamos la opción de Exportar Plantilla (Export Template).
    dslsetup02.PNG

  4. Copiar la plantilla de proyecto recién creada en el proyecto Setup. Podemos darle el nombre: Nombreproyecto.Code.tt).

  5. Añadir a .dslsetup la línea:




  6. Ejecutar (run) todos los Text Templates de la solución DSL para regenerar los archivos de WiX.


Tras compilar toda la solución, tendremos un instalador para nuestro DSL.

 


dslsetup03.PNG


Si lo instalamos en un equipo nuevo, podremos crear un nuevo proyecto correspondiente a nuestro DSL simplemente entrando en Visual Studio, indicando que deseamos crear un nuevo proyecto y seleccionando la plantilla de entre las que tenemos disponibles en la sección "Mis Plantillas".



dslsetup04.PNG


Aquí vemos cómo quedaría un proyecto de este tipo. Tendríamos, para el proyecto, las herramientas que diseñamos en el DSL, asociadas a sus Shapes correspondientes:


 


dslsetup05.PNG


También vemos la estructura del proyecto, idéntica a la que exportamos del Experimental Hive.


dslsetup06.PNG


Y un programa diseñado en este lenguaje podría quedar así:


 


dslsetup07.PNG


Por último, basta con ejecutar nuevamente el setup, y seleccionar la opción de eliminar el producto de nuestro equipo, si deseamos dejarlo tal y como l teníamos originariamente.

martes, 29 de abril de 2008

Generación de código con DSL Tools

Una de las posibilidades más interesantes de DSL Tools para Visual Studio es la generación de artefactos y código a partir del elementos pertenecientes al modelo de dominio que definamos para nuestro DSL. En el ejemplo de hoy usaremos el proyecto más básico de cuantos ofrece Visual Studio DSL Tools para obtener un generador de código básico que permitirá, definir un "lenguaje de programación visual" para nuestros usuarios. Obviamente, el alcance de la programación será algo limitado, máxime si tenemos en cuenta que se trata de un mero ejemplo de generación de código, pero nos permitirá vislumbrar hasta qué punto es potente y flexible esta herramienta.


En primer lugar, entramos a Visual Studio y creamos un nuevo proyecto Domain-Specific Languaje Designer, dentro de las plantillas Extensibility. Daremos un nombre a la solución, por ejemplo, MyDSLGenerator, y al pulsar en OK aparecerá un asistente para definir algunos de los parámetros de nuestro DSL. Seleccionaremos la plantilla MinimalTemplate, la extensión que tendrán los archivos de nuestro lenguaje (.mydlsg, en este ejemplo), y otras características como el espacio de nombres raíz para los proyectos de la solución. Hecho esto, pulsaremos en Finalizar, y tendremos ante nosotros el diseñador del DSL. Lo primero que nos preguntará siempre (a menos que indiquemos que no deseamos ser advertidos de ello) es que va a procederse a regenerar todos los archivos de la solución a partir de los Text Templates (archivos .tt) de la misma. Aceptamos, y nos encontraremos con algo similar a lo siguiente:



dsl1.PNG


Aunque podemos personalizar todo el DSL desde el proyecto Dsl de la solución, optaremos en esta entrada introductoria por hacer los mínimos cambios posibles. En primer lugar, hemos renombrado el nombre de los elementos del diagrama (ExampleShape, ExampleConnector, etc.).



dsl2.PNG


Lo más importante aquí va a ser definir una nueva propiedad de dominio sobre la clase xxElement (en nuestro caso, ActivityElement), ya creada por la propia plantilla del DSL. A esta propiedad podremos darle un valor, posteriormente, para cada Shape correspondiente a la clase que dibujemos en nuestro diseñador, o lo que es lo mismo, para cada objeto instanciado de la clase. Introduciremos una actividad denominada "Activity", de tipo string.



dsl21.PNG


Dentro del DSL Explorer haremos lo propio con las opciones correspondientes al Editor (Editor->Toolbox Tabs-> ActivitiesDesigner->Tools), para que aparezcan también los nombres en el Visual Studio Hive, y en la aplicación DSL una vez que la instalemos en otro equipo.



dsl3.PNG


Volvemos a generar el código del proyecto, pulsando sobre el botón Transform All Templates, y ejecutamos (F5). Aparecerá el Visual Studio Hive.


Creamos un diagrama acorde con lo especificado en nuestro DSL. Por ahora, lo único que hará es asignar una serie de propiedades a los Shapes (los rectángulos correspondientes a nuestras actividades). Estas propiedades son las que definimos anteriormente en el diseñador del DSL. Por un lado, la propiedad Name, que ya venía definida con la propia clase, y la propiedad Activity, que incluimos en ese momento.



dsl5.PNG


Para cada Shape, damos valor a las propiedades Name y Activity.



dsl6.PNG


Ahora vamos a preparar nuestro generador de código. Se tratará de un TextTemplate, de modo que añadimos un nuevo elemento al proyecto, de tipo fichero de texto, con el nombre LibraryCode.tt, y que va a permitir la generación de código a partir de los elementos existentes en nuestros diagramas. Más adelante nos quedará ver cómo llevar a cabo esta acción automáticamente cada vez que añadamos un elemento de nuestro lenguaje (archivo con extensión .mydlsg, que es la que definimos con este fin). De momento, lo generamos a mano, y le damos contenido.








using System;
using System.Collections.Generic;
using System.Text;
using LOBOSOFT.MyDSLGenerator;

namespace LOBOSOFT.Activity
{


///
/// The MainClass is the enter point for the functionality of this assembly
///
public class MainClass
{
public void MainMethod()
{
<# /* Calls to the private classes */
foreach(ActivityElement activity in this.ActivitiesModel.Elements){ #>
// Sequential caller
Class oClass = new Class();
oClass.m();


}
}

<# /* Creating classes for the Diagram Activities */
foreach(ActivityElement activity in this.ActivitiesModel.Elements)
{
#>
///
/// The Class gives functionality for managed class (test case)
///
public class Class
{
public void m()
{
o = new ();
o.MainMethod();
}
}
<#
}
#>

}

A grandes rasgos, este código se encarga de recorrer los elementos de nuestro diagrama, generando código según los valores que hemos definido para las propiedades. En primer lugar, se encuentran una serie de directivas.


<#@ template language="C#v3.5"..., por ejemplo, indica el lenguaje usado para la plantilla, ya que después de generar el código, será validado sintácticamente según las reglas del lenguaje, y compilado en una DLL cuando compilemos nuestro proyecto. El v3.5 es opcional, y sería necesario para aplicaciones que usen C# del .NET Framework 3.5 (como por ejemplo, que hagan uso de LINQ).
indica que haremos uso del archivo .mydslsg llamado Sample1. Por tanto, cada TextTemplate (.tt) irá vinculado inicialmente a un .mydslg, aunque veremos más adelante que esto podrá automatizarse.

El resto del template "escribe" el código en C# que necesitamos. Si pulsamos con el botón derecho del ratón sobre el archivo y seleccionamos la opción Run Custom Tool, o bien pulsamos sobre el botón Transform All Templates se generará el código C# asociado. En nuestro caso, el código correspondiente es el siguiente:


[csharp]
using System;
using System.Collections.Generic;
using System.Text;
using LOBOSOFT.ManagedDLLEncapsulation;

namespace LOBOSOFT.Activity
{

///
/// The MainClass is the enter point for the functionality of this assembly
///
public class MainClass
{
public void MainMethod()
{
// Sequential caller
pruebaClass opruebaClass = new pruebaClass();
opruebaClass.mprueba();

}
}

///
/// The pruebaClass gives functionality for prueba managed class (test case)
///
public class pruebaClass
{
public void mprueba()
{
prueba oprueba = new prueba();
oprueba.MainMethod();
}
}

}
[/csharp]

El código será generado e incluso compilado si hemos incluido en las referencias del proyecto las DLLs que estamos usando.

Nos quedará por ver cómo automatizar varios de estos procesos, y cómo realizar el despliegue en otro ordenador de este DSL gráfico, pero eso será en una próxima entrega.

martes, 26 de febrero de 2008

Expresiones lambda vs Delegados y métodos anónimos

En la entrada anterior vimos cómo usar las expresiones lambda para formular con una sintaxis compacta y clara una serie de ecuaciones matemáticas en el .Net Framework 3.0 (y 3.5). Avanzamos también la relación existente entre esta notación y la declaración de un delegado y un método anónimo para implementar la misma funcionalidad, y cómo, hasta cierto punto, si las expresiones lambda hubiesen aparecido en la versión anterior del framework, podrían haber suplido la función de los métodos anónimos, brindando además una mayor funcionalidad, como el uso de bloques de código como datos y el uso de árboles de expresión, aspectos en los que profundizaremos más adelante, pues dotan a C# de características propias de la metaprogramación.


El propósito de hoy, sin embargo, es complementar al artículo de ayer, en el que afirmaba la íntima relación existente entre las expresiones lambda y los métodos anónimos y delegados, como avanzaba hace un momento. Para demostrarlo, haremos uso de la excelente herramienta Reflector, de Lutz Roeder, que permite desensamblar código objeto generado para el .Net Framework y mostrarlo en varios de los lenguajes que soporta (C#, VB.Net y el propio IL, entre otros).


Si abrimos, usando Reflector, la DLL correspondiente al ejemplo de ayer, en el que implementábamos una clase que nos ofrecía la funcionalidad de cálculo del interés simple en matemáticas financieras, nos encontraremos con una serie de peculiaridades.



Estructura de la clase Financiera


Como podemos apreciar, en el ensamblado se encuentran, además de los métodos que definimos en la clase, otra serie de métodos y delegados con nombres generados automáticamente. Si comprobamos el contenido de los mismos, pulsando sobre su nombre en el árbol de exploración de Reflector, nos encontraremos con un delegado “vacío”, correspondiente a la expresión lambda que definimos con nuestra ecuación para el interés.


Delegado “Interes”


El analizador de Reflector (botón derecho, y opción analizar) nos indica las dependencias del método y por cuáles otros es usado. En la secuencia de figuras que se muestran a continuación se puede comprobar que nuestra expresión lambda ha sido convertida internamente en un método anónimo y un delegado, ambos privados.




Método que implementa nuestra funcionalidad para el interés simple
La implementación de nuestra funcionalidad inicial



El método abstracto y delegado con sus dependencias
El delegado con sus usos y dependencias

La clase ofrecerá la funcionalidad a través de un delegado público que implementa el tipo genérico System.Func. Finalmente, el código de la clase quedará:



Código de la clase, según el desensamblador


Con ésto hemos demostrado la relación existente entre las expresiones lambda y los delegados y métodos anónimos que indicábamos ayer.

Expresiones Lambda en C#

Ya he hablado en otras ocasiones sobre la incorporación de las expresiones lambda al .Net Framework a partir de su versión 3.0. Este tipo de expresiones, en las que profundizaremos hoy, proporcionan al framework el soporte necesario para el uso de LINQ como lenguaje de consulta casi, diríamos, universal. Lo primero que llama la atención al ver la implementación de las expresiones lambda en .Net es que, de haber aparecido antes, no habrían sido necesarios los métodos anónimos que se incorporaron en la anterior versión del framework (.Net 2.0). Es más, en cierto modo constituyen -entre otras mejoras- un embellecimiento del código y un (permítasenos la licencia de llamarlo así) encapsulamiento del método anónimo y del delegado que lo incluye. Esta relación, y cómo se definen las expresiones lambda, será el tema principal de la entrada de hoy.


En el cálculo del interés simple, dentro del campo de las matemáticas financieras, entran en juego una serie de ecuaciones que deseamos implementar en nuestro código.


Interés = Capital * Tiempo * Tasa de interés
Valor Futuro = Capital * (1 + Tasa * Tiempo)
Capital = Valor Futuro * (1+ Tasa * Tiempo) -1

Si deseáramos implementar estas funciones mediante el uso de métodos anónimos, deberíamos hacerlo a través de un delegado. Por ejemplo, la función que define el Interés podría implementarse como sigue:


[csharp]
private static double MiInteres(double C, int t, float i)
{
return ((C * t) * i);
}
[/csharp]

Para poder asignarla a un delegado, deberíamos tener definido un delegado con su misma firma:


[csharp]public delegate double Func(double C, int t, Single i);[/csharp]

La asignación, entonces, sería automática:


[csharp]Func miInteres1 = MiInteres;[/csharp]

Sin embargo, los métodos anónimos nos brindan un método más compacto y elegante para obtener el mismo resultado:


[csharp]Func miInteres2 = delegate(double C, int t, Single i) { return C * t * i; };[/csharp]

La definición de Func, incluido en el espacio de nombres System.Linq como tipo genérico de delegado, es la que sigue (para un ejemplo con 0, 1 y 2 argumentos):


[csharp]
public delegate TResult Func();
public delegate TResult Func(T1 arg1);
public delegate TResult Func(T1 arg1, T2 arg2);
[/csharp]

Visto esto, ¿cómo podríamos realizar la implementación de nuestras funciones financieras usando expresiones lambda? Vuelvo a incidir en la cercanía de dichas expresiones con los lenguajes funcionales y en que, debido a esta característica, su declaración será compacta y precisa. Comencemos con la misma función que nos ha ocupado hasta este momento, la del cálculo del interés simple. Recordemos que esta función estaba definida como

Interés = Capital * Tiempo * Tasa de interés

La expresión lambda equivalente será
[csharp]
public static Func Interes = (C, t, i) => (C * t * i);
[/csharp]

Como vemos, el C# de los .Net Frameworks 3.0 y 3.5 incluye mediante las expresiones lambda una sintaxis mucho más clara y concisa que el que se conseguía mediante el uso de los métodos anónimos. Una posible implementación de las ecuaciones implicadas en el cálculo del interés podría ser la siguiente:


[csharp]
public static class InteresSimple
{
public static Func Interes =
(C, t, i) => (C * t * i);

public static Func ValorFuturo =
(C, t, i) => (C * (1 + i * t));

public static Func Capital =
(VF, t, i) => (VF * Math.Pow((1 + i * t), -1));
}
[/csharp]

Entre las ventajas que nos aportará el uso de las expresiones lambda frente al de métodos anónimos y delegados se encuentra no sólo la simplicidad y limpieza sintáctica de la expresión, sino también la posiblidad de usar bloques de código como datos (algo inherente a estas expresiones e imposible de conseguir mediante los métodos anónimos), una característica en la que profundizaremos en otra ocasión.

viernes, 22 de febrero de 2008

¿Quines o Virus?

Vuelvo a la carga con otro artículo sobre los quines, que ya presenté hace un par de días en el blog, para estudiar la similitud, como ya anuncia el título de la entrada, con los virus informáticos. Una comparación que no es gratuita, y que fue lo primero que se me pasó por la cabeza cuando conocí las características de un quine.


Si la impaciencia o afán de conocimiento os hicieron ir más allá del alcance del artículo anterior e indagar un poco en el tema, bien en los enlaces recomendados que incluía en el mismo, bien realizando alguna otra búsqueda, veríais que existe una considerable cantidad de páginas que tratan el tema (sobre todo en cuanto a lo que concursos de creación de quines se refiere), aunque pocas entran en suficiente profundidad en él. Al refrescar conocimientos estos días para eswcribir estas entradas, encontré una interesante serie de artículos en español que incluyo en los enlaces recomendados de hoy. Pero veamos, en primer lugar, por qué insisto en la relación entre quines y virus.


Una de las primeras cosas que todo [interesado|aficionado | apasionado|afectado] de los virus descubre es la capacidad de propagación de éstos. Es una de las características principales de un virus: es capaz de replicarse e infectar a otras aplicaciones. Partiendo de esta premisa, tenemos que un virus es un programa que tiene la capacidad de replicarse mediante la inclusión en otros de su propio código, donde a su vez podrá nuevamente reproducirse para continuar su propagación. Por tanto, aunque no se trate exactamente de un quine (que, recordemos, reproducía como salida su propio código fuente), la similitud es tan grande que merece la pena profundizar un poco más en ella.


Si nos pertrechamos de sombrero y látigo y nos dedicamos a practicar arqueología informática, encontraremos virus que guardaban similitudes con los quines. Por ejemplo, el virus
Urphin infectaba código fuente en Pascal justo antes de ser compilado. Residente en memoria, esperaba la ejecución de TPC.EXE, el compilador de Turbo Pascal. En ese momento, incluía su propio código justo tras el BEGIN del programa, permitía el proceso de compilación y limpiaba después el código fuente .PAS de todo rastro. Así, finalizaba el proceso con un código fuente limpio y un ejecutable infectado por el virus. Como vemos, un virus de y para programadores.


Esto ocurría en tiempos remotos, cuando aún no existía un control adecuado de los procesos, que se ejecutaban en zonas compartidas de memoria. Hoy día, con modernos sistemas como Windows Vista (TM) o las últimas distros de Linux, nada de esto puede pasarnos. Además, es un método burdo y arcaico para programar virus informáticos. Nada puede pasarnos, ¿verdad? Pues la verdad es que sí. Hoy día nos encontramos rodeados de lenguajes de script e interpretados: scripts de shell en Linux, VBScript, JavaScript, Phyton, e incluso de cuarta generación, como SQL, que pueden caer víctimas de este tipo de ataque.


Si pensamos en seguridad y en SQL, inmediatamente se nos vendrá a la cabeza el método de ataque por inyección de código SQL. Pero ¿podrían existir quines en SQL? La respuesta es un rotundo sí.


[sql]SELECT REPLACE(REPLACE('SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS Quine',CHAR(34),CHAR(39)),CHAR(36),'SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS Quine') AS Quine[/sql]

El código anterior es un quine programado en SQL. Más concretamente, en T-SQL, el SQL avanzado para bases de datos SQL Server de Microsoft. Se trata de un quine clásico, simplemente devuelve una sentencia SQL que es copia de sí misma. Pero se puede ir más allá. Estudiemos el código siguiente, esta vez preparado para bases de datos MySQL:


[sql]UPDATE ContainerContents SET OldContents='%content%' WHERE TagID='%id%'[/sql]

Se trata de una sentencia de actualización en base de datos. Simplemente actualiza un atributo de la tabla ContainerContents cuando se da una condición, que el identificador sea X. Ahora, el exploit que aprovecha la vulnerabilidad del TagID, que se presenta encerrado entre comillas, para copiar su código en el campo NewContents.


[sql]%content%' WHERE TagId='%id%';

SET @a='UPDATE ContainerContents SET NewContents=concat(\'%content%\\\' WHERE TagId=\\\'%id%\\\'; SET @a=\', QUOTE(@a), \'; \', @a); %payload%; --';

UPDATE ContainerContents SET NewContents=concat('%content%\' WHERE TagId=\'%id%\'; SET @a=', QUOTE(@a), '; ', @a); %payload%; --‘[/sql]

Vemos, en primer lugar, una línea con la parte final de la sentencia SQL original. A continuación, en otra línea, se define una variable “a”, una cadena de caracteres que incluye una sentencia de actualización además de a sí misma. Es, por tanto, el quine. Por último, en la tercera línea, se actualiza el contenido del atributo NewContents para cada registro y, junto a la actualización, se define la variable “a” con su contenido (escapamos a las comillas mediante la función QUOTE), con lo que el virus se está propagando en el sistema.


Existen quines de este tipo para cualquier sistema SQL, incluso para los más robustos (y caros) como Oracle:


[sql]Apples’, NewContents=(select SUBSTR(SQL_TEXT,43,127) FROM v$sql WHERE INSTR(SQL_TEXT,’’)>0)--[/sql]

Permite la apertura de una puerta trasera en el puerto 1234, ya que netcat abrirá un socket en nuestro servidor en modo de escucha, quedando a la espera de conexiones entrantes.


Como hemos podido comprobar, no queda tan lejano el uso de quines en el código de virus informáticos, constituyendo un riesgo real, y no sólo una teoría curiosa sobre metaprogramación. Aunque profundizaremos más adelante en este tema, en los enlaces recomendados podrás encontrar más información sobre el mismo.


miércoles, 20 de febrero de 2008

Programas autorreplicantes

Desde que empecé a escribir en el blog de Lobosoft, deseaba dedicar una entrada a los quines, ya que me llamaron la atención desde siempre por sus peculiares características. Un quine, tal y como lo describe la Wikipedia, es un programa (un metaprograma, en realidad) capaz de replicarse a sí mismo. Es decir, que al ejecutarlo produce como salida una copia de su propio código fuente. Esto, que podría parecer una obviedad, no lo es tanto por la principal restricción que se les impone, a saber:



  • Un quine no puede abrir el fichero en el que está escrito (lenguajes interpretados) ni el de su código fuente (lenguajes compilados) para escribirlo en pantalla.


De este modo, la sencillez aparente que parecía subyacer en la programación de los quines desaparece por completo. Para verlo más claramente, estudiemos cómo programaríamos un quine en lenguaje C:


[c]
#include

int
main (void)
{
printf("#include \n\nint\nmain (void)\n{\n");
printf("printf(\"#include \\n\\nint\\nmain (void)\\n{\\n\");\n");
[/c]

Empezamos a programarlo y... ¡sorpresa! Parece que entramos en un bucle infinito. El programa comienza con la inclusión de los ficheros de cabecera necesarios y la declaración de la función main. A continuación, con printf escribimos en la salida estándar una cadena de caracteres con el comienzo del programa. En ese momento, hay que escribir una sentencia que escriba a la anterior, y ahí comienza nuestro ciclo sin fin.


Para resolver esta recursividad inherente a la propia escritura del quine, existen varios métodos, siendo el que veremos ahora uno de los más funcionales. Empezaremos por "escribir" todo el código de nuestro programa en un array de caracteres, y no en una cadena (string) que "envuelva" al código anterior y que, para ser escrita, necesite volver a ser incluida en otra cadena y así ad infinitum, en un equivalente programático de las muñecas rusas.


Un quine correcto y operativo, pero no muy elegante, podría ser el siguiente:
[c]
#include

int
main (void)
{
char *s1="#include %c%cint%cmain (void)%c{%c";
char *s2=" char *s%c=%c%s%c;%c char *s%c=%c%s%c;%c";
char *s3=" char n='%cn', q='%c', b='%c%c';%c";
char *sp=" printf(";
char *s4="%ss1,n,n,n,n,n);%c";
char *s5="%ss2,'1',q,s1,q,n,'2',q,s2,q,n);%ss2,'3',q,s3,q,n,'p',q,sp,q,n);%c";
char *s6="%ss2,'4',q,s4,q,n,'5',q,s5,q,n);%ss2,'6',q,s6,q,n,'7',q,s7,q,n);%c";
char *s7="%ss2,'8',q,s8,q,n,'9',q,s9,q,n);%ss2,'0',q,s0,q,n,'x',q,sx,q,n);%c";
char *s8="%ss3,b,q,b,b,n);%ss4,sp,n);%ss5,sp,sp,n);%c";
char *s9="%ss6,sp,sp,n);%ss7,sp,sp,n);%ss8,sp,sp,sp,n);%c";
char *s0="%ss9,sp,sp,sp,n);%ss0,sp,sp,n,n,n);%c return 0;%c}%c";
char *sx="--- This is an intron. ---";
char n='\n', q='"', b='\\';
printf(s1,n,n,n,n,n);
printf(s2,'1',q,s1,q,n,'2',q,s2,q,n); printf(s2,'3',q,s3,q,n,'p',q,sp,q,n);
printf(s2,'4',q,s4,q,n,'5',q,s5,q,n); printf(s2,'6',q,s6,q,n,'7',q,s7,q,n);
printf(s2,'8',q,s8,q,n,'9',q,s9,q,n); printf(s2,'0',q,s0,q,n,'x',q,sx,q,n);
printf(s3,b,q,b,b,n); printf(s4,sp,n); printf(s5,sp,sp,n);
printf(s6,sp,sp,n); printf(s7,sp,sp,n); printf(s8,sp,sp,sp,n);
printf(s9,sp,sp,sp,n); printf(s0,sp,sp,n,n,n);
return 0;
}
[/c]

Un poco críptico, sí señor, pero ayudará a desvelar un par de secretos de la programación de quines. Por un lado, si examinamos el código podremos ver que existen dos partes claramente diferenciadas. Una serie de definiciones de constantes, que constituyen, por así decirlo, el bloque de datos del programa, seguido por una serie de sentencias que serán las que se ejecuten, usando el bloque de datos para replicar su propio código. También encontramos, entre medias, una línea con un intron, que no es más que una parte de código que no aporta nada a la funcionalidad del quine y que, de no existir, no afectaría a su comportamiento.


El ejemplo de quine para C que presenta la Wikipedia es algo más sencillo, pero se basa en la misma filosofía:


[c]
#include
char*i="\\#include&ltstdio.h>",n='\n',q='"',*p=
"%s%cchar*i=%c%c%s%c,n='%cn',q='%c',*p=%c%c%s%c,*m=%c%c%s%c%c;%s%c",*m=
"int main(){return!printf(p,i+1,n,q,*i,i,q,*i,q,n,q,p,q,n,q,m,q,n,m,n);}"
;int main(){return!printf(p,i+1,n,q,*i,i,q,*i,q,n,q,p,q,n,q,m,q,n,m,n);}
[/c]

En una próxima entrada veremos cómo la programación de quines guarda una importante relación con la seguridad de los sistemas informáticos y la programación de virus (aparte, claro está, de prestarse a la celebración de concursos geek, donde resulta ganador quien escribe el quine más corto en un determinado lenguaje).


Referencias: