Reglas de Perl 6

De Wikipedia, la enciclopedia libre
Saltar a: navegación, búsqueda

Reglas de Perl 6 son expresiones regulares, coincidencia de patrones e interpretación de propósito general de Perl 6, y son una parte principal del lenguaje. Debido a que las construcciones de coincidencia de patrones han excedido, desde hace un tiempo, las capacidades formales de las expresiones regulares, la documentación de Perl 6 se refiere a ellas exclusivamente como regexes, distanciándose el término de la definición formal.

Perl 6 ofrece un superconjunto de las características de Perl 5 con respecto a las exp. reg., alojándolas en un gran entorno de trabajo llamado reglas (rules), que ofrecen las características de interpretación gramática de expresiones, así como actuar como clausura con respecto a su ámbito léxico.[1] Las Reglas son introducidas con la palabra clave rule, que tiene un uso similar a la definición de subrutinas. Reglas anónimas pueden ser introducidas con el identificador regex (o rx), o simplemente siendo usada en línea como las exp. reg. de Perl 5 vía los operadores m (coincidencia) o s (sustitución).

Historia[editar]

En Apocalipsis 5, Larry Wall enumeró 20 problemas con la "actual cultura exp. reg.". Entre estos estaban ser "demasiado compactos y 'lindos'", tenían "demasiada confianza en muy pocos metacaracteres", "poco apoyo para las capturas con nombre", "poco apoyo para las gramáticas", y "escasa integración con [el] lenguaje "real"".[2]

Entre el final de 2004 y mediados de 2005, un compilador de Perl 6 de reglas de estilo se desarrolló para la máquina virtual Parrot llamado Gramática del motor Parrot (PGE), que más tarde fue reescrito de forma más genérica, Analizador del motor gramático (Parser Grammar Engine). PGE es una combinación de tiempo de ejecución y compilador para las gramáticas Perl 6 que permite a cualquier compilador basado en parrot usar estas herramientas para el análisis, y también ofrece reglas en tiempos de ejecución.

Además de otras características de Perl 6, el soporte para capturas con nombre fue incorporada a Perl 5.10 en el 2007.[3]

Cambios desde Perl 5[editar]

Sólo hay seis características que no cambian con respecto a las exp. reg. de Perl 5:

  • Literales: caracteres de palabra (letras, números y guion bajo) coincidiendo literalmente
  • Capturando: (...)
  • Alternativas: |
  • Escapado con barra inversa: \
  • Cuantificadores de repetición: *, +, y ?, pero no {m,n}
  • Sufijos para coincidencia mínima: *?, +?, ??

Algunas de las adiciones más poderosas son:

  • La habilidad de referenciar reglas usando <nombre_de_la_regla> para construir gramáticas enteras.
  • Un puñado de operadores que permiten al programador controlar la vuelta atrás durante las coincidencias.

Los siguientes cambios mejoran considerablemente la legibilidad de expresiones regulares

  • Grupos de no-captura simplificados: [...], que es lo mismo que en Perl 5: (?:...)
  • Aserciones de código simplificadas: <?{...}>
  • Formateado extendido de las expresiones regulares (la opción /x de Perl 5) está activo por defecto.

Cambios implícitos[editar]

Algunas de las características de las expresiones regulares de Perl 5 se vuelven más poderosas en Perl 6 debido a la habilidad de encapsular las características expandidas de las reglas de Perl 6. Por ejemplo, en Perl 5, los operadores de cercanía positivos y negativos (?=...) y (?!...). En Perl 6 estas mismas características existen, pero son llamadas <before ...> y <!before ...>.

Además, como before puede encapsular reglas de forma arbitraria, puede ser usada para expresar cercanía como un predicado sintáctico para una gramática. Por ejemplo, la siguiente expresión de análisis gramatical describe el clásico lenguaje de contexto no libre  \{ a^n b^n c^n : n \ge 1 \} :

S ← &(A !b) a+ B
A ← a A? b
B ← b B? c

En reglas de Perl 6 esto sería:

rule S { <before <A> <!before b>> a+ <B> }
rule A { a <A>? b }
rule B { b <B>? c }

Naturalmente, dada la habilidad de mezclar reglas y código normal, esto puede quedar simplificado en esto:

rule S { (a+) (b+) (c+) <{$0.elems == $1.elems == $2.elems}> }

Sin embargo, esto hace uso de las aserciones, que es un concepto ligeramente diferente de las reglas de Perl 6, pero sustancialmente diferentes en teoría de análisis, creando una semántica en lugar de un predicado sintáctico. La mayor diferencia en la práctica es el rendimiento. No hay forma de que el motor de reglas conozca las condiciones en que las aserciones puedan coincidir, por lo que no se realiza ninguna optimización de este proceso.

Integración con Perl[editar]

En muchos lenguajes, las expresiones regulares son entradas como cadenas, que son entonces pasadas a las rutinas de las bibliotecas que las analizan y compilan en un estado interno. En Perl 5, las expresiones regulares comparten algo del analizador léxico con el escáner de Perl. Esto simplifica muchas aspectos del uso de las expresiones regulares, a pesar de añadir mucha complejidad al escáner. En Perl 6, las reglas son parte de la gramática del lenguaje. No existe un analizador separado para las reglas, como lo hay en Perl 5. Esto quiere decir que el código, incrustado en las reglas, es analizado al mismo tiempo que la propia regla y el código que la rodea. Por ejemplo, es posible anidar reglas y código sin reinvocar el analizador:

rule ab {
 (a.) # coincide con una "a" seguido de un carácter cualquiera
 # Entonces comprueba si el carácter era una "b"
 # Si es así, imprime un mensaje
 { $0 ~~ /b {say "encontrada la b"}/ }
}

Lo anterior es un único bloque de código Perl 6 que contiene una definición exterior de una regla, un bloque interior con código de aserción, y dentro de él, una expresión regular que contiene un nivel más de aserción.

Implementación[editar]

Identificadores[editar]

Existen distintos identificadores que se usan en conjunción con las reglas de Perl 6:

  • regex: Una exp. reg., anónima o no, que, por defecto, ignora el espacio en blanco dentro de la exp. reg.
  • token: Una exp. reg., anónima o no, que implica al modificador :ratchet.
  • rule: Una exp. reg., anónima o no, que implica a los modificadores :ratchet y :sigspace.
  • rx: Una exp. reg. anónima que toma delimitadores arbitrarios como por ejemplo // mientras que regex solo usa llaves.
  • m: Una forma de operador de exp. reg. anónima que realiza coincidencias con delimitadores arbitrarios.
  • mm: Abreviatura para m con el modificador :sigspace.
  • s: Una forma de operador de exp. reg. anónima que realiza sustitución con delimitadores arbitrarios.
  • ss: Abreviatura para s con el modificador :sigspace.
  • /.../: Colocando simplemente una exp. reg. entre barras es una abreviatura para m/.../.

Aquí hay un ejemplo de un uso típico:

token palabra { \w+ }
rule frase { <palabra> [ \, <palabra> ]* \. }
if $cadena ~~ / <frase> \n / {
  ...
}

Modificadores[editar]

Los modificadores pueden ser colocados después de cualquier identificador de exp. reg., y antes del delimitador. Si una exp. reg. tiene nombre, el modificador viene después del nombre. Los modificadores controlan la forma en que las exp. reg. son analizadas y cómo se comportan. Son siempre introducidas con un carácter : precedente.

Algunos de los modificadores más importantes son:

  • :i o :ignorecase – Realiza una coincidencia sin importar el tamaño de caja.
  • :g o :global – Realiza la coincidencia más de una vez para una cadena dada.
  • :s o :sigspace – Reemplaza el espacio en blanco en la exp. reg. con una regla de coincidencia de espacio en blanco, en lugar de simplemente ignorarlo.
  • :Perl5 – Trata la exp. reg. como una expresión regular de Perl 5.
  • :ratchet – No realizar Vuelta Atrás en la regla.

Por ejemplo:

regex adición :ratchet :sigspace { <término> \+ <expresión> }

Gramática[editar]

Una gramática puede ser definida usando el operador grammar. Una gramática es esencialmente un espacio de nombres para las reglas:

grammar Str::SprintfFormat {
 regex format_token { \%: <index>? <precision>? <modifier>? <directive> }
 token index { \d+ \$ }
 token precision { <flags>? <vector>? <precision_count> }
 token flags { <[\ +0\#\-]>+ }
 token precision_count { [ <[1-9]>\d* | \* ]? [ \. [ \d* | \* ] ]? }
 token vector { \*? v }
 token modifier { ll | <[lhmVqL]> }
 token directive { <[\%csduoxefgXEGbpniDUOF]> }
}

Esta es la gramática usada para definir la notación de formateo de cadenas de sprintf.

Fuera de este espacio de nombres, puede usar estas reglas así:

if / <Str::SprintfFormat::format_token> / { ... }

Una regla utilizada de esta forma es actualmente idéntica a la invocación de una subrutina con la semántica y efectos colaterales extras de la coincidencia de patrones (por ejemplo, las invocaciones de reglas pueden volverse hacia atrás).

Ejemplos[editar]

Aquí hay algunos ejemplos de reglas en Perl 6:

rx { a [ b | c ] ( d | e ) f : g }
rx { ( ab* ) <{ $1.size % 2 == 0 }> }

Esta última es idéntica a:

rx { ( ab[bb]* ) }

Referencias[editar]

  1. Wall, Larry (24 de junio de 2002). «Synopsis 5: Regexes and Rules».
  2. Wall, Larry (4 de junio de 2002). «Apocalypse 5: Pattern Matching».
  3. Perl 5.10 now available - Perl Buzz

Enlaces externos[editar]

  • Synopsis 05 (en inglés) - La documentación estándar sobre exp. reg. y reglas en Perl 6.
  • Perl 6 Regex Introduction (en inglés) - Suave introducción a las exp. reg. en Perl 6.