1 .
Enlaces
2 .
Historia de revisiones de esta página
Cortesía de El Rincón del programador.
Ser aficionado a la informática y no saber programar es algo que
no casa bien. Un auténtico aficionado sabrá al menos hacer pinitos en
algún lenguaje de programación, sea Java, Basic, Pascal, C o cualquier
otro. Entre los lenguajes de programación también hay modas; un cierto
lenguaje «se lleva» más que otros en ciertos momentos, lo cual es
lógico habida cuenta de que la informática evoluciona y con ella las
necesidades.
Pocos imaginan, sin embargo, la inmensa variedad de
lenguajes
de programación que hay disponibles. Los nombres que ahora mismo me
vienen a la cabeza sin consultar ninguna fuente de información son
COBOL, ALGOL, APL, BASIC, RPG, Forth, Fortran, Lisp, PL/I, Logo, C,
Pascal, Perl, Python, TCL, Ada, Java, ensamblador... y he omitido
deliberadamente nombrar variantes como Visual Basic, RPG III,
Scheme (un derivado de Lisp), C++ o Delphi.
Cuando llegamos al ensamblador, el tema de las variantes se
convierte en locura. Cada modelo de microprocesador tiene su propio
ensamblador, y existen miles y miles de modelos: Z80, PIC-16, 8051,
8086, 6809, 6502... A veces, como en el caso del 80x86 de
Intel, hay varios, incluso multitud de dialectos: el dialecto
oficial de Intel, el dialecto oficial del proyecto GNU
(formato
AT&T), el dialecto del ensamblador gratuito
NASM...
Para liar aún más la madeja existen personas que inventan su
propio lenguaje ensamblador, el de un procesador que no existe. El
ejemplo más notable quizá sea el de
Donald
Ervin Knuth,
matemático y escritor de una serie de tratados sobre informática
famosos en todo el mundo. Existen simuladores de los dos lenguajes
ensambladores que ha inventado, que corresponden a los procesadores
imaginarios llamados MIX y MMIX.
Ahí no queda todo. Hay gente que no ve razón en que el
lenguaje a inventar sea un lenguaje ensamblador; simplemente
inventan un lenguaje nuevo. Las razones son muy variadas; está
claro por ejemplo que
Sun Microsystems tenía razones
poderosas para inventar el Java. Pero no todo el mundo necesita
razones poderosas; aquí vamos a tratar precisamente sobre los
lenguajes de programación que han sido inventados por puro
entretenimiento. ¿Cómo?, se preguntarán muchos. ¿Hay gente capaz
de eso? La respuesta es sí, y no pocos. No menos sorprendente es
el hecho de que existen intérpretes de la mayoría de esos
lenguajes, y en algunos casos incluso compiladores.
Uno de los primeros lenguajes esotéricos (al menos que yo tenga
referencia, pues fue creado en 1972), y quizá de los más extendidos,
es el
INTERCAL.
Su diseño se fundamenta en la pretensión de crear un lenguaje
totalmente distinto a cualquier otro en todo, aunque sin olvidar
desde luego el sentido del humor. En él, tenemos que pedir por
favor la ejecución de ciertas sentencias; en lugar del conocido
«go to»
(ir a) para saltar a otra instrucción, tenemos que escribir
«come from» (venir desde) en el lugar de destino, aunque
esto es una extensión posterior a la primera especificación.
Podemos pedir que se abstenga de ejecutar ciertas sentencias,
por ejemplo:
PLEASE ABSTAIN FROM CALCULATING evita que se ejecute
la orden CALCULATE. Cuando
llegamos al capítulo sobre la precedencia de operadores se nos
explica que no la hay, porque precisamente el objetivo en el
diseño del lenguaje era que no hubiera ningún precedente.
Como resultado de esta regla, cuando necesitamos concatenar dos
operaciones juntas hay que agrupar los operandos por pares
mediante un equivalente a los paréntesis. El nombre completo del
lenguaje, según los autores, es
«Lenguaje Compilado Carente de Acrónimo Pronunciable», cuya
abreviatura es, «por razones obvias», INTERCAL. Podemos ver el
aspecto que tiene un programa escrito en INTERCAL en la
figura 1.
La función de este programa, extraído del manual de INTERCAL, es
leer dos enteros de 32 bits, tratándolos como enteros con signo
en formato de complemento a dos, y escribir su valor absoluto.
Figura 1: Programa en lenguaje INTERCAL.
DO (5) NEXT
(5) DO FORGET #1
PLEASE WRITE IN :1
DO .1 <- 'V":1~'#32768$#0'"$#1'~#3
DO (1) NEXT
DO :1 <- "'V":1~'#65535$#0'"$#65535'
~'#0$#65535'"$"'V":1~'#0$#65535'"
$#65535'~'#0$#65535'"
DO :2 <- #1
PLEASE DO (4) NEXT
(4) DO FORGET #1
DO .1 <- "'V":1~'#65535$#0'"$":2~'#65535
$#0'"'~'#0$#65535'"$"'V":1~'#0
$#65535'"$":2~'#65535$#0'"'~'#0$#65535'"
DO (1) NEXT
DO :2 <- ":2~'#0$#65535'"
$"'":2~'#65535$#0'"$#0'~'#32767$#1'"
DO (4) NEXT
(2) DO RESUME .1
(1) PLEASE DO (2) NEXT
PLEASE FORGET #1
DO READ OUT :1
PLEASE DO .1 <- 'V"':1~:1'~#1"$#1'~#3
DO (3) NEXT
PLEASE DO (5) NEXT
(3) DO (2) NEXT
PLEASE GIVE UP
Los programas en INTERCAL, desde luego, no son fáciles de
escribir. De todas formas no es el lenguaje esotérico en el que
más cuesta escribir un programa. Por ejemplo, en lenguaje
Piet
es imposible escribir un programa: hay que
dibujarlo. Vemos en la figura 2
un ejemplo de un programa en lenguaje Piet.

El programa de la figura 2 se limita a escribir la conocida
frase «Hello, world!» («¡Hola, mundo!»). Hay que reconocer, sin embargo,
que hemos hecho abuso del significado de la palabra escribir
en este contexto. Diseñar el programa
es algo que en Piet no es una tarea demasiado difícil. Quien busque
algo en lo que sea verdaderamente difícil programar, puede intentar usar
Malbolge.
Según la procedencia del nombre que menciona el
autor, el lenguaje se debería llamar Malebolge (el octavo círculo
del infierno de Dante), aunque seguramente el
nombre fue recortado a causa de una limitación del sistema operativo para el
que fue originariamente escrito (MS-DOS). Esta alusión al infierno puede
dar una somera idea de la complicación del lenguaje, aunque obtendremos una
idea más aproximada conociendo la dificultad que supuso para
Andrew Cooke
escribir un programa en Malbolge que simplemente escribiera «Hello, world»
(digamos que lo hizo por métodos de tipo «ensayo y error», y ni siquiera
consiguió uniformidad en las mayúsculas y minúsculas ni signos de
puntuación: el programa escribía «HEllO WORld»). En la
figura 3
vemos el programa que consiguió la hazaña.
Figura 3: Programa en lenguaje Malbolge.
(=<`$9]7<5YXz7wT.3,+O/o'K%$H"'~D|#z@b=`{^Lx8%$Xmrkpohm-kNi;g
sedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543s+O<oLm
No hay que desesperarse por no entender nada. Esa es justo la intención que el
inventor del lenguaje tenía. De hecho, el cripticismo buscado por el autor le
resta cierto interés al lenguaje: está deliberadamente encriptado, razón
por la cual Cooke propone un «Malbolge normalizado», que es lo que queda después
de la fase de desencriptación. No hay que dejarse llevar por la idea, sin embargo,
de que esto le reste dificultad al lenguaje. Se puede (si es que se puede)
escribir un programa en Malbolge normalizado y después aplicar la fase final de
encriptación para obtener un programa válido en Malbolge. La
figura 4 muestra el aspecto del programa «Hello world» en
Malbolge normalizado.
Figura 4: Programa en lenguaje Malbolge normalizado.
jpp<jp<pop<<jo*<popp<o*p<pp<pop<pop<jijoj/o<vvjpopoopo<ojo/o
vooooooooooooooooooooooooooooooooooooooooooooooooooo*p<v*<*
Aunque resulta algo más legible que antes, sigue siendo complicado de
descifrar sin una descripción de qué significa cada símbolo (y aun con ella).
En el fichero de la distribución de Malbolge existe una descripción completa del
lenguaje.
Pero de entre todos los lenguajes esotéricos hay uno que llama la atención por
su exquisita simplicidad y potencia. Se llama
Brainfuck,
que en inglés suena tan mal como en español su traducción de Jodecerebros, con perdón.
Debido a lo ofensivo del nombre, no es tan fácil buscar referencias en WWW usando
buscadores ya que hay muchas variaciones del nombre para ocultar su carácter
ofensivo: Brainf*ck, Brainf***, Brainfork, BF... La intención de su creador,
Urban Müller, era la de crear
un lenguaje para el cual se pudiera escribir el compilador más corto del
mundo.
A pesar del nombre,
escribir un programa en Brainfuck no es tan difícil como cabe pensar. Está
demostrado que es un lenguaje Turing-completo, lo que expresado de forma
más simple significa que se puede codificar cualquier algoritmo con él.
Existen únicamente ocho instrucciones, cada una
de las cuales está asociada a un símbolo. Hay un resumen en la
tabla 1
Existe un puntero de programa, que
representa la posición en la que se está ejecutando actualmente el código,
como en cualquier otro lenguaje imperativo (bueno, hay excepciones), y un
puntero de datos, que es una característica propia de Brainfuck
y que sirve precisamente para manipular los datos. El puntero de datos
apunta a la posición cero de una zona de memoria, inicialimente rellena
de ceros. No se considera correcto un programa si intenta decrementar el
puntero de datos cuando éste está en la posición cero. Usualmente se
considera que el contenido de cada posición de memoria es un byte sin
signo (un número de 0 a 255). Al incrementar uno de estos bytes cuando su
valor era 255, generalmente pasa a valer 0. Al decrementarlo cuando su
valor era 0, generalmente pasa a valer 255.
Decimos «generalmente» porque según la implementación puede haber versiones
del lenguaje que adopten otros convenios.
Tabla 1: Instrucciones del lenguaje Brainfuck.
| Instrucción |
Descripción |
Equivalente C |
| - |
Restar 1 al contenido de la celda de memoria actualmente apuntada por
el puntero de datos. |
--*p; |
| + |
Sumar 1 al contenido de la celda de memoria actualmente apuntada por
el puntero de datos. |
++*p; |
| < |
Decrementar el puntero de datos en una unidad. Es un error ejecutar
esta instrucción cuando el puntero de datos tiene el valor 0. |
--p; |
| > |
Incrementar el puntero de datos en una unidad. |
++p; |
| [ |
Si el contenido de la celda de memoria a la que apunta el puntero
de datos es cero, buscar el correspondiente «]» y colocar
el puntero de instrucción inmediatamente después. Es posible
anidarlos. No se considera
un programa válido aquél en el que no hay un balance correcto entre
los «[» y los «]». |
while(*p){ |
| ] |
Colocar el puntero de programa en el «[» anterior
correspondiente. |
} |
| , |
Introducir un carácter desde entrada estándar y colocarlo en la
celda apuntada por el valor actual del puntero de datos. |
*p=getchar(); |
| . |
Escribir el carácter ASCII correspondiente al valor de la celda
actual en la salida estándar. |
putchar(*p); |
Aquellos que sepan C pueden valerse de las equivalencias aproximadas
que se dan en la tabla 1 para entender un poco mejor
las acciones que cada instrucción realiza. Con tal sencillez estructural,
mal puede sorprendernos la facilidad con la que se puede escribir un
intérprete, y hasta un compilador de Brainfuck. Pero antes de entrar en
detalles respecto al intérprete, analizaremos un poco el lenguaje y
veremos algunas construcciones comunes.
Por ejemplo, la secuencia de instrucciones [-] se usa a
menudo en los programas Brainfuck, y sirve para poner a cero la celda de
memoria actual: equivale en C a la instrucción
«while(*p){--*p;}», es decir, mientras la celda
de memoria actual sea distinta de cero, decrementarla, lo cual obviamente
tiene como efecto ponerla a cero.
Si queremos mover el valor actual una posición a la derecha
(aquí entendemos que «izquierda» implica disminuir el
puntero de datos y «derecha» aumentarlo), utilizaremos el
siguiente programa: [>+<-]. Esto va incrementando el
byte de la derecha de la posición inicial y decrementando el actual,
hasta que éste es cero. Como resultado, al byte situado a la derecha de
la posición inicial se le suma lo que hubiera en dicha posición, que
acaba siendo cero. Suponiendo que a la derecha hubiera un cero, habremos
acabado moviendo el byte de esa posición un lugar a la derecha.
Copiar un valor es un problema más complicado; asumiendo que
las dos posiciones situadas a la derecha de la actual sean cero, se
procederá de la siguiente forma: primero, usaremos
[>+>+<<-], que tendrá el efecto de copiar el
valor en la posición actual a la posición de su derecha y a la siguiente
más a la derecha, y poner a cero la posición actual; después iremos dos
posiciones a la derecha usando >>, tras lo cual
usaremos una versión modificada del fragmento mover:
[<<+>>-], es decir, mover el byte de la
posición p (siendo p la posición del puntero de datos)
a la posición p-2. Al terminar, retrocederemos otra vez dos posiciones
usando <<, aunque dependiendo de la aplicación que
queramos darle este último paso puede ser innecesario.
Si no estamos seguros de si están a cero las dos posiciones de la
derecha de la actual, siempre podemos asegurarnos usando el siguiente
fragmento: >[-]>[-]<<. Normalmente,
sin embargo, no necesitaremos ejecutar este código, ya que estará
a cero al comenzar.
Juntando todo esto, nos damos cuenta de que si al empezar tenemos
en la posición p el valor a, en la posición p+1 el valor 0 y en la
posición p+2 el valor 0, tras ejecutar el siguiente fragmento de
código acabaremos teniendo en p el valor a, en p+1 el valor a, y en
p+2 el valor 0:
[>+>+<<-]>>[<<+>>-]<<
¿Confuso? Considerando cada parte por separado, se ve claramente
que simplemente estamos construyendo fragmentos cada vez más grandes
mediante los bloques básicos que anteriormente hemos considerado.
Multiplicar un byte por una constante es sencillo: basta con utilizar
el programa de mover, pero en lugar de incrementar una vez la variable de
la derecha, la incrementamos tantas veces como haga falta. Por ejemplo,
para multiplicar el byte actual por 7 podemos utilizar esto:
[>+++++++<-], que deja el resultado a la derecha del
byte actual, y éste a cero.
Multiplicar dos bytes entre sí requiere algo más de esfuerzo. La idea
es sumar el segundo sobre el byte a su derecha tantas veces como diga el
primero. Veamos cómo hacemos esto. Primero fijémonos en que la operación
de copiar puede ser usada también para sumar, puesto que si el valor en la
posición de la derecha de la actual no es cero, se le sumará el contenido
del byte actual. Así pues, si llamamos c a la operación
copiar, con este código resolveremos el problema: [>c<-],
es decir, ir a la derecha, sumar el byte que hay allí al siguiente, ir a la
izquierda, decrementar y continuar hasta que éste sea cero. Si se desea que
no se pierda el primer multiplicando, habrá que empezar copiándolo a un
lugar seguro.
El código completo queda así:
[>
[>+>+<<-]
>>
[<<+>>-]
<<
<-]
Veamos ahora un programa simple que imprime la «respuesta a la
Gran Pregunta de la Vida, el Universo y Todo lo demás» (según Douglas
Adams, escritor y humorista británico fallecido hace pocos años). Dicha
respuesta es 42. El siguiente programa calcula el código ASCII del número 4 y lo
imprime, y a continuación calcula el código ASCII del número 2 y
lo imprime: +++++++[>+++++++<-]>+++.--.. El código ASCII del dígito
4 es 52 = 7×7+3, por tanto primero multiplicamos 7×7, y luego sumamos
3 al resultado y lo imprimimos. Después restamos 2 a lo que quedaba, ya que el
código ASCII del dígito 2 es 50 = 52-2. Lo imprimimos, y ya lo tenemos.
Dejamos al cuidado del lector el resto del aprendizaje del lenguaje Brainfuck,
para centrarnos en una forma de elaborar un intérprete de dicho lenguaje. Esta es
una tarea realmente sencilla, como veremos enseguida; la única parte que presenta
alguna complicación (poca, realmente) es llevar el balance de qué
«]» corresponde con un «[» y
viceversa. Precisamos de dos memorias,
compuestas por sendos arrays (o arreglos, según
algunos traductores): la de programa y la de datos, llamadas respectivamente
mp y md. También necesitaremos dos
variables: p y d, que serán los punteros de programa
y datos, respectivamente.
He aquí un esquema del algoritmo principal del intérprete:
Leer el programa en la memoria de programa, mp,
guardando en la variable pfin la posición siguiente
a la última usada, que indicará fin de programa.
Poner a cero todos los elementos de la memoria de datos.
Hacer p = 0, d = 0.
Comienzo del bucle (1):
Si p = pfin, fin de programa: ir a la etiqueta (4).
Si la instrucción mp[p] es «-», hacer md[d] = md[d] - 1.
Si la instrucción mp[p] es «+», hacer md[d] = md[d] + 1.
Si la instrucción mp[p] es «<», hacer d = d - 1.
Si la instrucción mp[p] es «>», hacer d = d + 1.
Si la instrucción mp[p] es «,», leer un carácter y guardarlo en md[d].
Si la instrucción mp[p] es «.», escribir el carácter que hay en md[d].
Si la instrucción mp[p] es «[» y md[d] es cero, hacer lo siguiente:
Hacer nivel = 0.
Comienzo del bucle (2):
Si mp[p] es «[», hacer nivel = nivel + 1.
Si mp[p] es «]», hacer nivel = nivel - 1.
Hacer p = p + 1.
Si nivel = 0, ir al comienzo del bucle (1).
Ir al comienzo del bucle (2).
Si la instrucción mp[p] es «]», hacer lo siguiente:
Hacer nivel = 1.
Comienzo del bucle (3):
Hacer p = p - 1.
Si mp[p] es «]», hacer nivel = nivel + 1.
Si mp[p] es «[», hacer nivel = nivel - 1.
Si nivel = 0, ir al comienzo del bucle (1).
Ir al comienzo del bucle (3).
Hacer p = p + 1.
Ir al comienzo del bucle (1).
Etiqueta (4): fin de programa.
El intérprete recién descrito asume que los programas son correctos, es decir,
que tienen un balance correcto de «[» y
«]» y que el programa nunca utiliza la instrucción
«<» cuando d = 0, ni la
instrucción «>» cuando d está en la
última posición disponible de md. También asume que el lenguaje
efectúa correctamente el «salto» de 255 a 0 al incrementar, y de
0 a 255 al decrementar. Si esto no fuera así, habrá que poner condiciones
adicionales, convirtiéndose la operación de incrementar en la siguiente:
Si md[d] = 255, hacer md[d] = 0; si no, hacer md[d] = md[d] + 1.
y la de decrementar, similarmente:
Si md[d] = 0, hacer md[d] = 255; si no, hacer md[d] = md[d] - 1.
Durante el desarrollo de un programa Brainfuck es fácil equivocarse de forma
que no cumpla los requisitos arriba expuestos.
Para evitar sorpresas es aconsejable incluir en el intérprete comprobaciones en lugares
estratégicos: comprobar antes de decrementar d que éste no es cero,
y antes de incrementarlo que no está ya en el límite derecho; en los bucles que
buscan el «[» y «]»
correspondientes a su pareja, hay que comprobar que no llegamos a p = 0
o a p = pfin sin encontrar la pareja correspondiente, o en caso
contrario detener la ejecución. Con esas precauciones el intérprete debería ser
seguro frente a cualquier programa Brainfuck por mal construido que esté.
Ya para terminar, una pregunta: ¿cuál es la longitud del programa Brainfuck
más corto capaz de guardar en la posición 0 el valor 111 (decimal) dejando el resto
de la memoria de datos con ceros? Mandad las soluciones a
inforecre@wanadoo.es;
publicaré las mejores soluciones en el próximo artículo.
Enlaces
Por ahora la mayoría de las páginas enlazadas desde aquí están en inglés, ya
que el tema parece que todavía no es muy conocido en nuestro país. Esperemos que
con el tiempo la situación cambie.
Sobre lenguajes esotéricos en general
El índice maestro donde encontrar referencias sobre lenguajes esotéricos
es sin duda el Esoteric Languages Webring Index:
http://b.webring.com/hub?ring=esolang
La página por excelencia de los lenguajes experimentales, mantenida por Chris Pressey:
Cat's Eye, http://www.catseye.mb.ca/
Es de destacar la sección dedicada a temas esotéricos
sobre lenguajes de programación:
http://www.catseye.mb.ca/esoteric/
Eric Steven Raymond es el autor
de un compilador de INTERCAL, el C-INTERCAL.
Su página llamada The Retrocomputing Museum contiene una selección
de joyas del esoterismo en programación. Brainfuck tiene ocho
instrucciones, pero ¿cuál es el mínimo número de
instrucciones que debe tener un lenguaje para ser Turing-completo? ¡Una! Hay
en esta página dos ejemplos, que llevan el concepto del RISC un paso más lejos:
OISC (One Instruction Set Computing) y URISC (Ultimate RISC).
Otra de las joyas presentes en este museo es el kvikkalkul, un
lenguaje pretendidamente utilizado en los submarinos nucleares suecos en la
década de 1950, aunque más probablemente sea una broma. El lenguaje sólo
soporta números en coma flotante sin parte entera.
También destacamos el MIXAL, que es el lenguaje ensamblador del procesador
MIX de Knuth, mencionado en el texto, y un lenguaje de programación Klingon
llamado var´aq. Hay muchas otras perlas que invitamos a descubrir.
http://www.tuxedo.org/~esr/retro/
La Enciclopedia de Lenguajes Estúpidos contiene una lista bastante
exhaustiva de lenguajes esotéricos, sus características, el nombre de su
creador, el año de creación y la página principal. Varios de los enlaces
disponibles aquí han sido obtenidos gracias a esa página. El lenguaje
Brainfuck concretamente aparece listado como Brainfork.
http://www.kraml.at/stupid/
Grupos de noticias y listas de correo relacionados con lenguajes
esotéricos:
alt.lang.intercal
comp.lang.misc
Lista de correo de Cat's Eye
Archivo de la lista de correo de Cat's Eye
Selección de lenguajes esotéricos concretos
El lenguaje Whenever, cuyas instrucciones no
se ejecutan en un orden preestablecido sino aleatorio:
http://www.dangermouse.net/esoteric/whenever.html
Las instrucciones del lenguaje Wierd son cambios
de dirección en cadenas de símbolos. Esta es la especificación
del lenguaje:
http://www.catseye.mb.ca/esoteric/wierd/doc/wierdspec.txt
El lenguaje Piet mencionado en el texto, cuyas
instrucciones son colores:
http://www.dangermouse.net/esoteric/piet.html
Descripción del lenguaje nihilista Sartre,
otro lenguaje pensado con buen humor. Es bastante llamativa
la definición de la instrucción condicional IF.
http://www.catseye.mb.ca/esoteric/sartre/index.html
Sobre Brainfuck
He aquí un intérprete y depurador de Brainfuck escrito por el
autor de este artículo (en inglés), suministrado en forma de código
fuente en C. El código debería ser sumamente portable; compila
perfectamente con gcc tanto en Windows como en Linux. El
intérprete, además, realiza primero una pasada de optimización
del código para que se ejecute más rápido. El depurador contiene
funciones avanzadas hasta ahora no presentes en ningún programa
similar.
http://perso.wanadoo.es/p.gimeno/files/brfd10.zip
Una completa guía acerca de los bloques con los que construir
programas en Brainfuck:
http://home.planet.nl/~faase009/Ha_bf_intro.html
La demostración formal de que Brainfuck es Turing-completo:
http://home.planet.nl/~faase009/Ha_bf_Turing.html
Un intérprete de Brainfuck disponible en línea, escrito en JavaScript:
http://home.planet.nl/~faase009/Ha_bf_online.html
Propuestas de normalización del Brainfuck:
http://www.muppetlabs.com/~breadbox/bf/standards.html
y otra con cierto sentido del humor:
http://esoteric.sange.fi/ENSI/brainfuck-1.0.txt
Existen numerosos programas escritos en lenguaje Brainfuck;
entre ellos destacamos un
programa
para averiguar si un número es primo, varios
intérpretes y
compiladores
de Brainfuck escritos precisamente en Brainfuck, y un programa para
calcular
PI, aunque éste último requiere una extensión del lenguaje que
permita que cada celda pueda almacenar números de 16 bits en vez de 8.
He aquí una biblioteca de programas escritos en Brainfuck. Destacamos
el programa SORT.BF, que lee una entrada, la ordena mediante el método de
la burbuja e imprime el resultado.
http://esoteric.sange.fi/brainfuck/bf-source/prog/
Otros enlaces indirectamente relacionados con lenguajes esotéricos
Una colección del programa Hello, World escrito en
gran variedad de lenguajes, incluyendo muchos esotéricos, entre
ellos BrainFuck e INTERCAL:
http://www.latech.edu/~acm/HelloWorld.shtml
99 Bottles of Beer es una canción popular inglesa y
estadounidense, al estilo de la canción popular española cuya letra
empieza así: Un elefante se balanceaba sobre la tela de
una araña... La versión en inglés requiere contar del 99 al
cero durante la canción. Este es un ejercicio de programación
indudablemente más complicado que el de Hello, World, y
por ello los programas tienden a ser más largos pero a la vez más
interesantes. He aquí una página dedicada a los programas que
imprimen la letra completa de la canción 99 Bottles of Beer
en diferentes lenguajes de programación; destacamos el escrito en
A+ ya que es capaz de imprimir las versiones europea y
americana. Por supuesto no faltan versiones Brainfuck ni INTERCAL del
programa.
http://99-bottles-of-beer.ls-la.net/
Los quines son programas capaces de reproducirse a sí
mismos. No tienen, sin embargo, nada que ver con los virus: a
diferencia de éstos, el requisito que han de cumplir los quines
es que la salida del programa sea su propio código fuente, sin
utilizar ningún fichero externo. Pensando un poco sobre el tema
vemos enseguida que la tarea no es trivial, y que se parece al
problema del huevo o la gallina. Hay ejemplos en muchos
lenguajes, entre ellos INTERCAL y Brainfuck.
http://www.nyx.net/~gthompso/quine.htm
Lista exhaustiva de lenguajes de programación, antiguos y modernos:
http://ftp.wustl.edu/doc/misc/lang-list.txt
La Galería de los Descifradores CSS es una página creada para
defender que un programa de ordenador puede ser acogido dentro de
la ley de libertad de expresión, ya que al parecer un juez
estadounidense declaró ilegal un programa escrito en lenguaje C
que descifraba los sectores encriptados de los discos DVD, que
utilizan un sistema criptográfico denominado CSS. Hay ejemplos
en muchos otros lenguajes (entre ellos, cómo no, Brainfuck), y
otras muchas formas de expresar el programa original: versiones
recitadas del programa en formato MP3, descripciones detalladas
del algoritmo paso a paso que pueden ser utilizadas para
rehacerlo, y muchas otras divertidas maneras de convertir el
algoritmo a formas que sí están claramente protegidas por la
libertad de expresión. Dando vueltas a la tuerca, lleva el tema
a extremos que rayan el ridículo, como la existencia de números
primos ilegales.
http://www.cs.cmu.edu/~dst/DeCSS/Gallery/
Historia de revisiones de esta página
- 2002-12-22: Primera versión.
- 2002-12-23: Añadido enlace a biblioteca de
programas Brainfuck y otros arreglos menores.
- 2003-01-03: Añadidos enlaces a las páginas
personales de Ian Stewart y Juan M. R. Parrondo, y otros
arreglos menores.
- 2003-01-14: Corregido el enlace de las 99 botellas
de cerveza y su comentario correspondiente, y otros arreglos menores.