Skip to main content

Brainfuck Sommaire Présentation du langage | Implémentation | Exemples | Macro-définition Brainfuck | Commentaire | Variantes | Notes et références | Voir aussi | Menu de navigationmodifierf*ckf*cklangage PiPreuve de la Turing-complétude de Brainfuck en anglaisInterpréteur brainfuckUn autre interpréteur brainfuckEncore un autre interpréteur brainfuckBrainfuckInterpréteur Spoon

Langage de programmation exotique


langage de programmationexotiqueUrban Müller1993machine de TuringcompilateurAmigaoctetsoctetsTuring-completpointeurASCIIASCIIvariable temporairemajusculemajusculeASCIImacros-définitionsalgorithmiquelangages de programmationf*ckf*cklangage PiTuring-completorang-outanbibliothécaireDisque-mondeTerry Pratchettcodage de Huffmanfichier binaireAVRPICMIPS












Brainfuck




Un article de Wikipédia, l'encyclopédie libre.






Sauter à la navigation
Sauter à la recherche














Brainfuck.mw-parser-output .entete.informatiquebackground-image:url("//upload.wikimedia.org/wikipedia/commons/a/ae/Picto-infoboxinfo.png")

Programme "Hello World!" en Brainfuck
Programme "Hello World!" en Brainfuck

Date de première version
1993
Auteur
Urban Müller
Influencé par

P′′ (en)
FALSE (d)Voir et modifier les données sur Wikidata

A influencé

Ook, Whitespace, Spoon, SegFaultProg ...

Extension de fichier

b et bfVoir et modifier les données sur Wikidata

Brainfuck est un langage de programmation exotique, inventé par Urban Müller en 1993. Il tire son nom de l’union de deux mots anglais, brain (« cerveau ») et fuck (« niquer »), et joue sur les mots, puisque ce langage est volontairement simpliste, et parce que l'expression Brain Fuck évoque, en argot, ce qui met le cerveau dans un état de confusion par sa complexité apparente. Ce vocabulaire peu flatteur lui a d'ailleurs valu d'être écrit sous d'autres orthographes plus prudes, telles que Brainf*ck, Brainf*** ou encore BF.




Sommaire





  • 1 Présentation du langage


  • 2 Implémentation

    • 2.1 Structure du Brainfuck


    • 2.2 Instructions


    • 2.3 Entrées / Sorties

      • 2.3.1 Entrées


      • 2.3.2 Sorties




  • 3 Exemples

    • 3.1 Hello World!


    • 3.2 Remise à zéro de l'octet pointé


    • 3.3 Entrée/Sortie d'un caractère


    • 3.4 Boucle simple


    • 3.5 Manipulation de pointeur


    • 3.6 Copie d'un octet


    • 3.7 Instructions conditionnelles

      • 3.7.1 If


      • 3.7.2 If, else



    • 3.8 Opérations

      • 3.8.1 Addition


      • 3.8.2 Addition (ASCII)


      • 3.8.3 Soustraction


      • 3.8.4 Multiplication


      • 3.8.5 Multiplication (ASCII)


      • 3.8.6 Minimum




  • 4 Macro-définition Brainfuck


  • 5 Commentaire


  • 6 Variantes

    • 6.1 Ook!


    • 6.2 Spoon


    • 6.3 SegFaultProg


    • 6.4 Whitespace



  • 7 Notes et références


  • 8 Voir aussi

    • 8.1 Articles connexes


    • 8.2 Liens externes





Présentation du langage |


L'objectif de Müller était de créer un langage de programmation simple, destiné à fonctionner sur une machine de Turing, et dont le compilateur aurait la taille la plus réduite possible. Le langage se satisfait en effet de seulement huit instructions. La version 2 du compilateur originel de Müller, écrit pour l'Amiga, ne pesait lui-même que 240 octets, la version actuelle se contentant de 171 octets. Le brainfuck est pourtant un langage Turing-complet[1], ce qui signifie que, malgré les apparences, il est théoriquement possible d'écrire n'importe quel programme informatique en brainfuck.


La contrepartie est que, comme son nom ne le suggère peut-être pas pour un non-anglophone, le langage brainfuck produit des programmes difficiles à comprendre. Il suit un modèle de machine simple, consistant en un tableau d'octets initialisés à 0, d'un pointeur sur le tableau (positionné sur le premier octet du tableau) et de deux files d'octets pour les entrées et sorties.



Implémentation |



Structure du Brainfuck |


Le brainfuck utilise un tableau de 30 000 cases dans lequel il stocke des valeurs. Chacune de ces cases prend une valeur entière codée sur 8 bits, ce qui permet des valeurs entre 0 et 255 ou entre -128 et 127. Il utilise également un pointeur, c'est-à-dire une variable qui prend des valeurs entières positives indiquant l'indice de la case du tableau que l'on modifie actuellement. Par convention, on attribue en informatique l'indice 0 à la première case du tableau.


Au lancement du code Brainfuck, le pointeur est initialisé à 0 et toutes les cases du tableau sont nulles.


Dans les nouvelles implémentations du brainfuck, la taille du tableau n'est pas restreinte à 30 000 cases et celles-ci peuvent prendre des valeurs plus élevées. Le pointeur, lui, peut prendre des valeurs négatives, c'est-à-dire que le tableau peut s'étendre à gauche de la case d'indice nul.



Instructions |


Les huit instructions du langage, chacune codée par un seul caractère, sont les suivantes :




















Caract.
Signification

>​
incrémente (augmente de 1) le pointeur.

<​
décrémente (diminue de 1) le pointeur.

+​
incrémente l'octet du tableau sur lequel est positionné le pointeur (l'octet pointé).

-​
décrémente l'octet pointé.

.​
sortie de l'octet pointé (valeur ASCII).

,​
entrée d'un octet dans le tableau à l'endroit où est positionné le pointeur (valeur ASCII).

[​
saute à l'instruction après le ] correspondant si l'octet pointé est à 0.

]​
retourne à l'instruction après le [ si l'octet pointé est différent de 0.

(Alternativement, ]​ peut être défini par « retourne au [​ correspondant ». La formulation est plus courte, mais moins symétrique et moins efficace en temps. Le choix de l'une ou l'autre de ces deux syntaxes n'influe pas sur le comportement final du programme.)


(Une troisième version équivalente, quoique moins considérée, est :
[​ signifie « saute à l'instruction ]​ correspondante », et ]​ signifie « retourne à l'instruction après le [​ correspondant si l'octet pointé est différent de 0 ».)


Les programmes brainfuck peuvent être traduits en C en utilisant les substitutions suivantes, en considérant que ptr est du type unsigned char* :




















Brainfuck
C
>​
ptr++;​
< ​
ptr--;​
+​
++(*ptr);​
-​
--(*ptr);​
.​
putchar(*ptr);​
,​
(*ptr) = getchar();​
[​
while(*ptr) ​
]​


Entrées / Sorties |



Entrées |



Les différents interpréteurs de Brainfuck gèrent les entrées différemment. Prenons pour exemple le programme suivant :


,[>,] ',' : prend une première entrée, puis '[>,]': se déplace à droite, copie l'entrée et continue tant qu'elle n'est pas nulle

Celui-ci se charge d'inscrire les entrées les unes à la suite des autres dans le tableau jusqu'à ce qu'une des entrées soit 0.


Certains interpréteurs demanderont à l'utilisateur à chaque fois qu'ils rencontrent la commande "," une entrée. Par exemple, l'utilisateur rentrera 12, puis 15, puis 2, puis 36, puis 0, et obtiendra le tableau [12,15,2,36,0,0,...]


D'autres ne demanderont qu'une seule entrée à plusieurs chiffres, comme 1215236, et la découpera chiffre par chiffre pour obtenir toutes les entrées requises: 1, puis 2, puis 1, puis 5 ... Dès qu'il n'y a plus de chiffres à mettre en entrée, l'interpréteur les remplace automatiquement par des 0. Ainsi dans notre exemple, on obtiendra le tableau [1,2,1,5,2,3,6,0,0,...]. Si l'utilisateur rentre un nombre avec un 0 à l'intérieur, le programme s'arrêtera comme prévu à ce 0 sans copier le reste du nombre. Par exemple, 12150236 donnera [1,2,1,5,0,0,...]


En général, comme on vient de le faire, les entrées sont des nombres, mais peuvent être également des caractères ASCII, l'interpréteur se charge de les remplacer par leur code équivalent. Par exemple, si l'on rentre "Hello World" avec le code précédent, on obtient alors : [72,101,108,108,111,32,87,111,114,108,100,0,0,...].



Sorties |


Comme pour les entrées, les sorties peuvent soit être exprimées en ASCII, soit directement numériquement.



Exemples |



Hello World! |


Le programme suivant affiche le traditionnel « Hello World! » et une nouvelle ligne à l'écran :


++++++++++ Affecte 10 à la case 0
[ Boucle initiale qui affecte des valeurs utiles au tableau
> avance à la case 1
+++++++ affecte 7 à la case 1
> avance à la case 2
++++++++++ affecte 10 à la case 2
> avance à la case 3
+++ affecte 3 à la case 3
> avance à la case 4
+ affecte 1 à la case 4
<<<< retourne à la case 0
- enlève 1 à la case 0
] jusqu'à ce que la case 0 soit = à 0
la boucle initialise le tableau selon les valeurs suivantes:
Case : Valeur
0 : 0
1 : 70
2 : 100
3 : 30
4 : 10

>++ ajoute 2 à la case 1 (70 plus 2 = 72)
. imprime le caractère 'H' (72)
>+ ajoute 1 à la case 2 (100 plus 1 = 101)
. imprime le caractère 'e' (101)
+++++++ ajoute 7 à la case 2 (101 plus 7 = 108)
. imprime le caractère 'l' (108)
. imprime le caractère 'l' (108)
+++ ajoute 3 à la case 2 (108 plus 3 = 111)
. imprime le caractère 'o' (111)
>++ ajoute 2 à la case 3 (30 plus 2 = 32)
. imprime le caractère ' '(espace) (32)
<< revient à la case 1
+++++++++++++++ ajoute 15 à la case 1 (72 plus 15 = 87)
. imprime le caractère 'W' (87)
> repart à la case 2
. imprime le caractère 'o' (111)
+++ ajoute 3 à la case 2 (111 plus 3 = 114)
. imprime le caractère 'r' (114)
------ enlève 6 à la case 2 (114 moins 6 = 108)
. imprime le caractère 'l' (108)
-------- enlève 8 à la case 2 (108 moins 8 = 100)
. imprime le caractère 'd' (100)
> repart à la case 3
+ ajoute 1 à la case 3 (32 plus 1 = 33)
. imprime le caractère '!' (33)
> va à la case 4
. imprime le caractère 'n'(nouvelle ligne) (10)

Par souci de lisibilité, le code a été divisé en plusieurs lignes et des commentaires ont été ajoutés. Brainfuck considère comme étant des commentaires tous les caractères sauf +-<>[],.. Le code effectivement compilé peut donc se réduire à la ligne suivante :


++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.

La première ligne initialise a[0] = 10 par de simples incréments successifs à partir de 0. La boucle des lignes 2 à 4 définit de façon effective les valeurs initiales du tableau : a[1] = 70 (proche de 72, le code ASCII du caractère 'H'), a[2] = 100 (proche de 101 ou 'e'), a[3] = 30 (proche de 32, espace) et a[4] = 10 (nouvelle ligne). La boucle fonctionne en multipliant les valeurs de a[0], 10, par 7, 10, 3, et 1, qu'elle stocke dans les cellules voisines. Quand la boucle s'achève, a[0] vaut zéro. >++. déplace alors le pointeur à a[1], qui contient 70, y ajoute 2 (72 étant le code ASCII de la lettre 'H' majuscule), et l'affiche.


La ligne suivante déplace le pointeur vers a[2] et l'incrémente de 1, le résultat, 101, correspondant à 'e', qui est alors affiché.


'l' étant la septième lettre de l'alphabet après 'e', pour obtenir 'll' il faut ajouter 7 (+++++++) à a[2] et l'afficher deux fois.


'o' est la troisième lettre de l'alphabet après 'l', on incrémente donc a[2] trois fois avant d'afficher le résultat.


Le reste du programme fonctionne selon le même principe. Pour les espaces et les lettres en majuscule, ce sont d'autres cellules du tableau qui sont sélectionnées et incrémentées.



Remise à zéro de l'octet pointé |


[ boucle 
- enlever 1 à la case courante
] jusqu'à ce que la case soit à zéro

L'octet est décrémenté (boucle [ ]) jusqu'à ce que sa valeur ait atteint 0.



Entrée/Sortie d'un caractère |


, saisit un caractère de la ligne de commande dans la case courante
. imprime le caractère correspondant à la valeur de la case courante

Affiche à l'écran un caractère entré au clavier.



Boucle simple |


[,.] ou ,[.,]

Boucle affichant les caractères entrés au clavier. La fin de la saisie est ici signalée par un 0 (les implémentations peuvent différer sur ce point).



Manipulation de pointeur |


  • Enregistrer une chaîne de caractères
,[.>,]

Une version améliorée de la boucle précédente, dans laquelle les caractères saisis par l'utilisateur sont stockés dans un tableau en vue d'une utilisation future, en déplaçant le pointeur à chaque fois.


  • Utilisation de bloc de mémoire (taille quelconque, mais ne contenant pas de valeur nulle)

En notant P le pointeur, xxxx un bloc de données quelconques non nulle, et 0 un octet dont la valeur est nulle, si la mémoire est organisée de la manière suivante :


 0Pxxxx00xxxx00xxxx00xxxx00xxx ... avec les blocs xxxx numérotés de 1 à n

Alors nous pouvons nous déplacer de bloc en bloc de la manière suivante (avec le pointeur initialement sur P ) :


[-[-[>]>+<<[<]>]]

Par exemple, si P=3, à chaque exécution de la boucle principale, la mémoire sera organisée de cette façon :


 0Pxxxx00xxxx00xxxx00xxxx00xxx ... Avec P = 3
00xxxx0Pxxxx00xxxx00xxxx00xxx ... Avec P = 2
00xxxx00xxxx0Pxxxx00xxxx00xxx ... Avec P = 1
00xxxx00xxxx00xxxx0Pxxxx00xxx ... Avec P = 0

Arrivée à ce point, la boucle s'arrête, et nous sommes arrivé sur le bloc pointé. Cette technique permet de manipuler des blocs de tailles quelconques, à condition qu'ils ne contiennent pas de valeurs nulles.


  • Utilisation de bloc de mémoire (taille fixe, pouvant contenir des valeurs nulles)

En reprenant la technique précédente, mais cette fois avec des blocs de tailles constantes (par exemple 4, on obtient) :


0Pxxxx00xxxx00xxxx00xxxx00xxx ... avec les blocs xxxx numérotés de 1 à n
[-[->>>>>>+<<<<<<]] Il faut 4 (taille des blocs) + 2 (les séparateurs) décalages

Cette technique permet d'avoir des données nulles dans les blocs, mais est plus longue à écrire pour des blocs de grandes tailles.



Copie d'un octet |


On peut distinguer deux manières de copier le contenu d'un octet dans un autre : en effaçant les données de l'octet initial ou en les conservant. Le premier cas est plus simple, le second requérant une variable intermédiaire.


Pour la copie destructive d'un octet dans l'octet suivant, en supposant que le pointeur est sur l'octet à copier:


>[-]< effacer l'octet suivant et revenir sur l'octet initial (facultatif si on sait que l'octet cible est nul)
[->+<] tant qu'il n'est pas nul lui enlever 1 et ajouter un à l'octet suivant

Pour une copie conservative d'un octet (pointé au départ) dans l'octet suivant, nous allons utiliser l'octet encore après comme variable temporaire. Encore une fois, la première ligne est facultative si on sait que les deux octets suivant l'octet à copier sont nuls.


>[-]>[-]<< on efface les deux octets suivants l'octet à copier puis on revient sur lui

[>+>+<<-] on incrémente les deux octets suivants et on décrémente l'octet à copier jusqu'à ce qu'il soit vide. On a donc réalisé deux copies en le détruisant

>>[-<<+>>] on se place sur la deuxième copie et on la copie destructivement sur le premier octet.


Instructions conditionnelles |


,----------[----------------------.,----------]

Ce programme prend un caractère minuscule en entrée et le met en majuscule. La touche Entrée arrête la saisie (code 10 en Brainfuck dans la plupart des compilateurs).


Au début, on récupère le premier caractère (, ) et on lui soustrait immédiatement 10 (10 fois -). Si l'utilisateur a appuyé sur Entrée, on a 0 dans l'octet pointé et l'instruction de boucle ([) saute à la fin du programme.
Si le caractère entré n'est pas 10, on considère que c'est une lettre minuscule et on entre dans la boucle, où on va lui soustraire le nombre 22 (22 fois -), ce qui va faire 32 en tout, 32 étant la différence numérique entre la lettre minuscule et la même lettre en majuscule en code ASCII.


Le caractère est affiché, puis un nouveau caractère est récupéré, et à nouveau on lui soustrait 10. Le programme revient alors au début de la boucle : si la touche qu'a validé l'utilisateur est entrée (10), la boucle s'arrête, sinon elle se poursuit.



If |


Voici un moyen simple d'écrire un bloc « if » en Brainfuck :


>[code<]<[>]



Ce bloc d'instruction nécessite une mémoire de la forme :


1 0 n

Avec le curseur sur le « 0 ».
Il exécute le code « code » si et seulement si ndisplaystyle n est non nul, avec le curseur sur le « 0 » à l'état final comme initial.


Décomposons ce code en étapes :


">" : on met le pointeur sur n


Si n est égal à 0, la boucle ne s'exécute pas et le pointeur est toujours sur n, on revient alors en arrière ("<", on est alors sur le 2e octet) puis la boucle ne s'exécute pas puisque nous sommes sur le 0 ([>] revient à dire "va sur le premier octet nul en partant de l'octet pointé inclus").


Si n est différent de 0, la boucle s'exécute et le code aussi, le pointeur revient alors sur le 2e octet et la boucle s'arrête, puisque cet octet est égal à 0. Le pointeur est donc sur le 2e octet. On revient ensuite en arrière ("<"), donc sur le premier octet (égal à 1) puis, comme dit, la boucle [>] emmène le pointeur sur le premier octet nul suivant l'octet pointé inclus, or le premier est différent de 0 et le second égal à 0, ce qui amène le pointeur sur le deuxième octet.


Si on a besoin de faire une condition après laquelle le code s'arrête, on peut se contenter de ">[code<]" , puisque la partie "<[>]" sert uniquement à mettre le pointeur, à l'état final, sur le deuxième octet dans les deux cas.



If, else |


Ce bloc d'instruction nécessite une mémoire de la forme :


+-+-+-+
|V|C|T|
+-+-+-+
^

Ou V est la variable à tester, C est sa copie et T le Témoin du passage dans le bloc if. Dans notre exemple, le pointeur de départ est sur V et celui d'arrivée est sur C. Dans chaque block de code (if et else), le pointeur de départ et d'arrivée est sur C. C et T sont nulles après exécution.


>[-]>[-]<< Mise à zero des 2 variables suivantes (facultatif si connues pour être nulles)
[>+>+<<-] Double copie de V dans C et T
>>[-<<+>>]< Restauration de V à partir de T (T = 0) / retour sur la copie de la variable
>[-]+ Initialisation du témoin (T = 1)
< Retour sur la copie de la variable
[ Si la copie de la variable = true
code_if
[-]>-<] Destruction de la copie de la variable / destruction du témoin
> Déplacement sur le témoin
[< Si le block if ne s'est pas exécuté (témoin = 1) / Retour sur la (copie de la) variable
code_else
>-<] Destruction du témoin (dans ce cas (la copie de) la variable est déjà nulle vu que if ne s'est pas executé)
Retour sur la (copie de la) variable détruite

Soit en condensé


>[-]>[-]<<[>+>+<<-]>>[-<<+>>]>>[-]+<[ code_if [-]>-<]>[< code_else >-]<

Une manière plus simple d'exécuter un bloc If, else est la suivante :




Pour exécuter cette structure, la mémoire doit être sous cette forme :


0 1 0 n
^

avec n l'octet à tester.


[ code_if <]<<[>> code_else <<<]>>>

Les codes « code_if » et « code_else » ne doivent utiliser que les cases à droite de l'octet considéré et revenir à l'octet à la fin de leur
exécution.
Soit en totalité :


initialisation variable <<<[-]>[-]+>[-]>[ code_if <]<<[>> code_else <<<]>>>


Opérations |



Addition |


Ce bloc d'instruction nécessite une mémoire de la forme :


index 0 1
+-+-+
Variable |V|A|
+-+-+

Ou "V" est la variable de base "A" est la variable à additionner. À la fin du programme "A" est détruite et "V" contient le résultat de l'addition.


Ce code ajoute l'octet suivant (en le détruisant, il est donc remis à 0) à l'octet courant.


++>+++++++++< index0 = 2 / index1 = 8 / retour sur index 0

>[-<+>]< Détruit index1 en l'additionnant avec index0

ou


++>++++++++< index0 = 2 / index1 = 8 / retour sur index 0

>[<+>-]< Additionne index1 avec index0 en détruisant index1



Soit index[0] = 2 et index[1] = 8, « > » Se place sur index[1], « [ » débute la boucle, « - » et index[1] = 7, « < » on pointe sur index[0], « + » et index[0] = 3, « > » on pointe sur index[1], « ] » si index[1] != 0 on recommence.
À la fin, on aura bien index[1] = 0 ce qui arrête la boucle, et index[0] = 10.



Addition (ASCII) |


,>++++++[<-------->-],,[<+>-],<.>.

Ce programme additionne 2 nombres à un seul chiffre et affiche le résultat si celui-ci n'a aussi qu'un seul chiffre :


4+3


7


(Maintenant les choses vont être un peu plus compliquées. Nous allons nous référer aux octets du tableau ainsi : [0], [1], [2], etc.)


Le premier nombre est entré dans [0], et on lui soustrait 48 pour avoir sa valeur décimale (les codes ASCII pour les chiffres 0-9 sont 48-57). Cela est fait en mettant 6 dans [1] et en utilisant une boucle pour soustraire 8 de [0] autant de fois que dans [1], soit 6 × 8 = 48. C'est une méthode plus commode pour ajouter ou soustraire des grands nombres que de mettre 48 fois « - » dans le programme. Le code qui fait cela est :


>++++++[<-------->-]

>++++++ pour mettre 6 dans [1], puis on attaque la boucle, « < » pour revenir sur [0], on soustrait 8, « > » on repasse sur [1], qu'on décrémente et on retourne dans la boucle. La boucle est alors exécutée 6 fois, jusqu'à ce que [1] soit égal à 0.


Ensuite, on récupère le signe + qu'on met dans [1], puis le second chiffre qui écrase le signe +.


La boucle suivante [<+>-] ajoute effectivement le nombre de la seconde cellule dans la première cellule et remet [1] à zéro. À chaque boucle, il ajoute 1 dans [0] et retire 1 de [1] ; ainsi [1] finit par être à 0. Tout ce qui a été ajouté à [0] a été retiré de [1]. Ensuite la touche entrée est mise dans [1].


Puis le pointeur est remis sur [0], qui est affiché ([0] est maintenant a + (b + 48), puisqu'on n'a pas corrigé b ; ce qui est identique à (a + b) + 48, qui est ce que l'on veut). Le pointeur est ensuite déplacé sur [1], qui contient la touche entrée, que l'on affiche. L'exécution est terminée.



Soustraction |


Cette opération nécessite une mémoire de la forme :


index 0 1 
+-+-+
variable |V|S|
+-+-+

Ou "V" est la variable de base "S" est la variable à soustraire. À la fin du programme "S" est détruite et "V" contient le résultat de la soustraction.


++++++++>++++< V = 8 / S = 4 / retour sur V

>[-<->]< Détruit S et le soustrait a V

ou


++>++++++++< index0 = 2 / index1 = 8 / retour sur index 0

>[<->-]< Soustrait S a V en détruisant S

Soit V = 8 et S = 4, « > » Se place sur S, « [ » débute la boucle, « - » et S = 3, « < » on pointe sur V, « - » et V = 7, « > » on pointe sur S, « ] » si S != 0 on recommence.
À la fin, on aura bien S = 0 ce qui arrête la boucle, et V = 4.



Multiplication |


Cette opération nécessite une mémoire de la forme :


index 0 1 2 3 
+-+-+-+-+
variable |R|T|O|M|
+-+-+-+-+

Où "R" est le résultat, "T" est une variable temporaire, O est l'opérande et M le multiplicateur. Au début de l’exécution le pointeur est sur R et à la fin de l’exécution le pointeur est sur R.


 Initialisation
[-] R = 0
>[-] T = 0
>[-]+++ O = 0 / O = 3 (changez ici le nombre d'incrémentation pour modifier le résultat)
>[-]+++++ M = 0 / M = 5 (changez ici le nombre d'incrémentation pour modifier le résultat)

< Reviens à O
[ Tant que O différent de 0
> Passe à M
[ Tant que M différent de 0
<<+ Reviens à T / Incrémenter T
<+ Reviens à R / Incrémenter R
>>>- Passe à M / Décrémenter M
] Retour boucle
<<[>>+<<-] Reinitialise M / Détruit T
>- Décrémente O
] Retour boucle
>[-] Retourne à M / M = 0
< Retourne O déjà = 0
<[-] Retourne à T / T = 0
< Retourne à R

Soit en condensé :


[-]>[-]>[-]+++>[-]+++++<[>[<<+<+>>>-]<<[>>+<<-]>-]>[-]<<[-]<


Multiplication (ASCII) |


,>,,>>++++++++++++++++[-<+++<---<--->>>]<<[<[>>+>+<<<-]>>>[<<<+>>>-]<<-]>.

Comme le précédent, mais effectue une multiplication basée sur les caractères, pas sur des nombres enregistrés en mémoire.


Le premier nombre est entré dans [0], l'astérisque et le deuxième nombre dans [1] et les 2 nombres sont corrigés en leur soustrayant 48 (note : il y a une boucle de 16 itérations pour soustraire 3 aux deux nombres ainsi qu'ajouter 3 au futur résultat à chaque itération !).


Ensuite on entre dans la boucle de multiplication principale. L'idée de base est qu'à chaque boucle on soustrait 1 de [1] et on ajoute [0] dans le total cumulé gardé en [2] (3 * 2 = 2 + 2 + 2). En particulier : la première boucle cumule [0] dans [2] et [3], tout en remettant [0] à 0. (C'est la manière la plus simple de dupliquer un nombre.) La deuxième boucle remet [3] dans [0], en remettant à 0 [3]. Puis on décrémente [1] et on est à la fin de la boucle principale. À la sortie de cette boucle, [1] contient 0, [0] contient encore le deuxième nombre, et [2] contient le produit des 2 nombres (pour garder la valeur, il suffit de l'ajouter dans [4] à chaque itération de la boucle principale, puis de déplacer la valeur de [4] dans [1].)


Exemple : 3 * 2






































































[0][1][2][3]
3200

1re boucle : >[>+>+<<-]
3111
3022

2e boucle : >>[<<+>>-]
3121
3220
Fin boucle princ : <<<-]
2220

1re boucle : >[>+>+<<-]
2131
2042

2e boucle : >>[<<+>>-]
2141
2240
Fin boucle princ : <<<-]
1240

1re boucle : >[>+>+<<-]
1151
1062

2e boucle : >>[<<+>>-]
1161
1260
Fin boucle princ : <<<-]
0260

Ensuite, il ne reste plus qu'à ajouter 48 au produit, récupérer la touche entrée dans [3], et afficher le produit en ASCII et l'entrée qui vient juste d'être stockée.



Minimum |


Cette section présente un code permettant de calculer le minimum de deux entiers, chose plus ardue que l'on pourrait penser.


Il prend en argument une bande de la forme


n 1 0 m 0 0 0

Avec le curseur sur le ndisplaystyle n, et renvoie une bande de la forme


n' 1 0 m' M 0 0

Avec le curseur sur le Mdisplaystyle M et M=min(n,m)displaystyle M=min(n,m), n′=n−Mdisplaystyle n'=n-M et m′=m−Mdisplaystyle m'=m-M


[->> On commence une boucle sur n
>[ On teste si m est nulle ou non
>>>>>+<<<<< On remplace le 0 de la case juste après M par un 1
->+< On ajoute 1 au minimum tout en enlevant 1 à m
<]<[>] Fin du If
>>>>
>[ Cette ligne fait un If après le M : ceci revient en fait à un Else du bloc If
-<<->>>>>>> On efface le 1 en trop à la fin et on s'éloigne de la bande (ce qui permet de quitter le programme en revenant sur la place du M)
]<[>]
<<<<<< On revient sur le n (ou sur le 0 après le M sinon)
]
>[>>>>->]<< Cette ligne permet de se placer sur la case du M que ce soit m ou n le plus petit

On peut ensuite ajouter du code de mise en forme.



Ainsi le code suivant prend en argument une bande du type


n m 0 0...

avec un curseur sur le ndisplaystyle n et renvoie


0 0 0 0 M 0...

avec le curseur sur le Mdisplaystyle M.


Voici le code : (les lignes 2 et 4 sont des lignes de mise en forme, 1 et 5 des entrées sorties)


,>,
[->>+<<]+<
[->>>[>>>>>+<<<<<->+<<]<[>]>>>>>[-<<->>>>>>>]<[>]<<<<<<]>[>>>>->]<<
<<<<[-]>[-]>>[-]>
.


Macro-définition Brainfuck |


Les macros-définitions ci-dessous définissent des techniques permettant de retrouver des structures ou des instructions utilisées habituellement en algorithmique ou dans les langages de programmation. Elles facilitent la création de programmes Brainfuck. Il existe des implémentations de Brainfuck acceptant la définition de macros.


Les symboles comme a, b ou s représentent chacun un octet différent dans le tableau mémoire. Le symbole t indique un octet utilisé temporairement pour les besoins de la macro. Le symbole s représente un octet utilisé comme source et d un octet utilisé comme destination.


  • Déplacement du pointeur

La macro to(a) consiste à déplacer le pointeur dans le tableau mémoire au niveau de l'octet a. Elle s'obtient avec une série de < ou de >.


  • Ajout d'une constante

La macro addCst(n) ajoute à l'octet pointé la valeur n. Elle s'obtient avec une série de + ou de - selon le signe de n.


  • Mise à zéro d'un octet
zero(m): to(m) [-]​
  • Déplacer un octet
move(s d): to(s) [- to(d)+ to(s)]​
  • Déplacer un octet vers deux autres octets
move2(s d1 d2): to(s) [- to(d1)+ to(d2)+ to(s)]​
  • Copie d'un octet vers un autre
copy(s d t): move2(s d t) move(t s)​
  • Structure conditionnelle simple
if(a) : to(a) [​

endif(a): zero(a) ]​

  • Structure conditionnelle avec alternative
ifelse(a t): to(t)+ to(a) [ to(t)-​

else(a t) : zero(a) ] to(t) [​

endelse(t) : to(t)- ]​

  • Structure répétitive
for(s) : to(s) [​

next(s): to(s)- ]​

  • Échange de deux octets
swap(a b t): move(a t) move(b a) move(t b)​


Commentaire |


On peut noter que, dans la version initiale, comme chaque cellule du tableau est un octet, l'instruction « - » est superflue et peut-être remplacée par 255 « + ». De la même manière, les 30 000 cellules formant un tableau circulaire, « < » peut-être remplacé par 29 999 « > ». Cela réduirait le langage à six instructions.


Cependant, la taille du tableau, la taille des cellules et les possibilités de "wrapping" (i.e. que faire > sur la dernière case ramène à la première ou que + sur un octet plein le met à 0) ne font pas partie des spécifications du langage et sont laissées à la liberté des compilateurs. Ainsi, cette réduction à six instructions n'est pas toujours possible. Quand bien même, jouer sur le wrapping peut nuire à la portabilité du langage.


La seule contrainte imposée par le concepteur du langage est au moins 30 000 cellules et au moins un octet par cellule. Certaines implémentations proposent deux, quatre ou huit octets par cellule, voire aucune limitation !



Variantes |


Brainfuck a de nombreux descendants. La plupart se contentent de rendre le code encore plus inextricable (par exemple f*ckf*ck, le
langage Pi, ou bien Ook! décrit ci-dessous) ; d'autres ajoutent de réelles fonctionnalités.



Ook! |


Le langage Ook est une variante de brainfuck. C'est un langage Turing-complet, conçu pour être parfaitement lisible par un orang-outan, en référence au personnage du bibliothécaire de l'univers du Disque-monde de Terry Pratchett.
































OokBrainfuckSignification
Ook. Ook?>incrémente (augmente de 1) le pointeur.
Ook? Ook.<décrémente (diminue de 1) le pointeur.
Ook. Ook.+incrémente l'octet du tableau sur lequel est positionné le pointeur (l'octet pointé).
Ook! Ook!-décrémente l'octet pointé.
Ook! Ook..sortie de l'octet pointé (valeur ASCII).
Ook. Ook!,entrée d'un octet dans le tableau à l'endroit où est positionné le pointeur (valeur ASCII).
Ook! Ook?[saute à l'instruction après le Ook? Ook! correspondant si l'octet pointé est à 0.
Ook? Ook!]retourne à l'instruction après le Ook! Ook? si l'octet pointé est différent de 0.
Ook? Ook?fin du programme.

Hello world en Ook :


Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook! Ook! Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook? Ook. Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook? Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook? Ook. Ook. Ook! Ook. Ook. Ook? Ook! Ook. Ook? Ook?


Spoon |


Le langage spoon est équivalent au langage brainfuck mais avec des mots constitués de 0 et 1, utilisant un codage de Huffman.





























SpoonBrainfuckSignification
010>incrémente (augmente de 1) le pointeur.
011<décrémente (diminue de 1) le pointeur.
1+incrémente l'octet du tableau sur lequel est positionné le pointeur (l'octet pointé).
000-décrémente l'octet pointé.
0010110,entrée d'un octet dans le tableau à l'endroit où est positionné le pointeur (valeur ASCII).
001010.sortie de l'octet pointé (valeur ASCII).
00100[saute à l'instruction après le 0011 correspondant si l'octet pointé est à 0.
0011]retourne à l'instruction après le 00100 si l'octet pointé est différent de 0.

De plus, il possède deux instructions supplémentaires non disponibles dans le langage brainfuck :








SpoonSignification
00101110sortie de tout le tableau mémoire.
00101111fin immédiate du programme.

Hello world en spoon :


1 1 1 1 1 1 1 1 1 1 00100 010 1 1 1 1 1 1 1 010 1 1 1 1 1 1 1 1 1 1 010 1 1 1 010 1 011 011 011 011 000 0011 010 1 1 001010 010 1 001010 1 1 1 1 1 1 1 001010 001010 1 1 1 001010 010 1 1 001010 011 011 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 001010 010 001010 1 1 1 001010 000 000 000 000 000 000 001010 000 000 000 000 000 000 000 000 001010 010 1 001010 010 001010

Les espaces peuvent être supprimés :


Hello world en spoon (sans espace)


11111111110010001011111110101111111111010111010101101101101100000110101100101001010010101111111001010001010111001010010110010100110111111111111111110010100100010101110010100000000000000000000010100000000000000000000000000010100101001010010001010

Cela fait bien entendu référence à un fichier binaire (exécutable).



SegFaultProg |


Le langage Segfaultprog est une variante du brainfuck conçue par Gery DUBIEF, enrichie, extensible, destinée à être exécutée en machine virtuelle, sur de petites architectures (AVR, PIC, MIPS...). Son développement a débuté en mai 2010. Ce langage propose une simplification de la syntaxe du brainfuck (par exemple, avec l'adressage direct, et en évitant les répétitions), et rétro-compatibilité avec celui-ci. Le projet SegFaultProg (qui définit la syntaxe et les normes du langage) développe actuellement[Quand ?] la version 2 du langage.


Hello world en SegFaultProg V1


*A+H.[-]+e.+7..+3.*B+32.*A+8.-8.+3.[-]+d.

Hello World en SegFaultProg V2


*$0x00$+cH.-$3$.+$7$..>+&+$0x03$.>+c .>+$0x57$.<<.+$3$.<.-$0x08$.


Whitespace |


Article détaillé : Whitespace.

Le langage Whitespace est équivalent au Brainfuck mais n'utilise en tant qu'instructions que des tabulations, des espaces et des retours à la ligne, afin de générer un programme dont le code est invisible.



Notes et références |




  1. (en) Preuve de la Turing-complétude de Brainfuck en anglais




Voir aussi |



Articles connexes |


  • Langage de programmation exotique

  • Turing-complet


Liens externes |



  • (en) Interpréteur brainfuck


  • (en) Un autre interpréteur brainfuck


  • (en) Encore un autre interpréteur brainfuck


  • (en) Brainfuck un interpréteur en-ligne en JavaScript avec une collection des programmes


  • (fr) Interpréteur Spoon

  • Portail de la programmation informatique



Ce document provient de « https://fr.wikipedia.org/w/index.php?title=Brainfuck&oldid=158329610 ».













Menu de navigation


























(RLQ=window.RLQ||[]).push(function()mw.config.set("wgPageParseReport":"limitreport":"cputime":"0.496","walltime":"1.357","ppvisitednodes":"value":2235,"limit":1000000,"ppgeneratednodes":"value":0,"limit":1500000,"postexpandincludesize":"value":19963,"limit":2097152,"templateargumentsize":"value":3942,"limit":2097152,"expansiondepth":"value":14,"limit":40,"expensivefunctioncount":"value":3,"limit":500,"unstrip-depth":"value":0,"limit":20,"unstrip-size":"value":39231,"limit":5000000,"entityaccesscount":"value":3,"limit":400,"timingprofile":["100.00% 1165.696 1 -total"," 20.76% 241.998 1 Modèle:Infobox_Langage_de_programmation"," 10.49% 122.329 15 Modèle:Wikidata"," 6.91% 80.532 2 Modèle:Infobox/Image_optionnelle"," 6.56% 76.510 21 Modèle:Infobox/Ligne_mixte_optionnelle"," 4.61% 53.735 1 Modèle:Portail"," 3.78% 44.019 2 Modèle:Lang"," 3.38% 39.431 1 Modèle:Infobox/Titre"," 2.75% 32.053 41 Modèle:Code"," 2.30% 26.755 1 Modèle:Suivi_des_biographies"],"scribunto":"limitreport-timeusage":"value":"0.141","limit":"10.000","limitreport-memusage":"value":2835877,"limit":52428800,"cachereport":"origin":"mw1222","timestamp":"20190828181059","ttl":2592000,"transientcontent":false););"@context":"https://schema.org","@type":"Article","name":"Brainfuck","url":"https://fr.wikipedia.org/wiki/Brainfuck","sameAs":"http://www.wikidata.org/entity/Q244627","mainEntity":"http://www.wikidata.org/entity/Q244627","author":"@type":"Organization","name":"Contributeurs aux projets de Wikimu00e9dia","publisher":"@type":"Organization","name":"Wikimedia Foundation, Inc.","logo":"@type":"ImageObject","url":"https://www.wikimedia.org/static/images/wmf-hor-googpub.png","datePublished":"2003-03-11T22:09:22Z","dateModified":"2019-04-10T15:25:21Z","image":"https://upload.wikimedia.org/wikipedia/commons/b/b4/Hello_World_Brainfuck.png","headline":"langage de programmation minimaliste"(RLQ=window.RLQ||[]).push(function()mw.config.set("wgBackendResponseTime":142,"wgHostname":"mw1273"););

Popular posts from this blog

19. јануар Садржај Догађаји Рођења Смрти Празници и дани сећања Види још Референце Мени за навигацијуу

Israel Cuprins Etimologie | Istorie | Geografie | Politică | Demografie | Educație | Economie | Cultură | Note explicative | Note bibliografice | Bibliografie | Legături externe | Meniu de navigaresite web oficialfacebooktweeterGoogle+Instagramcanal YouTubeInstagramtextmodificaremodificarewww.technion.ac.ilnew.huji.ac.ilwww.weizmann.ac.ilwww1.biu.ac.ilenglish.tau.ac.ilwww.haifa.ac.ilin.bgu.ac.ilwww.openu.ac.ilwww.ariel.ac.ilCIA FactbookHarta Israelului"Negotiating Jerusalem," Palestine–Israel JournalThe Schizoid Nature of Modern Hebrew: A Slavic Language in Search of a Semitic Past„Arabic in Israel: an official language and a cultural bridge”„Latest Population Statistics for Israel”„Israel Population”„Tables”„Report for Selected Countries and Subjects”Human Development Report 2016: Human Development for Everyone„Distribution of family income - Gini index”The World FactbookJerusalem Law„Israel”„Israel”„Zionist Leaders: David Ben-Gurion 1886–1973”„The status of Jerusalem”„Analysis: Kadima's big plans”„Israel's Hard-Learned Lessons”„The Legacy of Undefined Borders, Tel Aviv Notes No. 40, 5 iunie 2002”„Israel Journal: A Land Without Borders”„Population”„Israel closes decade with population of 7.5 million”Time Series-DataBank„Selected Statistics on Jerusalem Day 2007 (Hebrew)”Golan belongs to Syria, Druze protestGlobal Survey 2006: Middle East Progress Amid Global Gains in FreedomWHO: Life expectancy in Israel among highest in the worldInternational Monetary Fund, World Economic Outlook Database, April 2011: Nominal GDP list of countries. Data for the year 2010.„Israel's accession to the OECD”Popular Opinion„On the Move”Hosea 12:5„Walking the Bible Timeline”„Palestine: History”„Return to Zion”An invention called 'the Jewish people' – Haaretz – Israel NewsoriginalJewish and Non-Jewish Population of Palestine-Israel (1517–2004)ImmigrationJewishvirtuallibrary.orgChapter One: The Heralders of Zionism„The birth of modern Israel: A scrap of paper that changed history”„League of Nations: The Mandate for Palestine, 24 iulie 1922”The Population of Palestine Prior to 1948originalBackground Paper No. 47 (ST/DPI/SER.A/47)History: Foreign DominationTwo Hundred and Seventh Plenary Meeting„Israel (Labor Zionism)”Population, by Religion and Population GroupThe Suez CrisisAdolf EichmannJustice Ministry Reply to Amnesty International Report„The Interregnum”Israel Ministry of Foreign Affairs – The Palestinian National Covenant- July 1968Research on terrorism: trends, achievements & failuresThe Routledge Atlas of the Arab–Israeli conflict: The Complete History of the Struggle and the Efforts to Resolve It"George Habash, Palestinian Terrorism Tactician, Dies at 82."„1973: Arab states attack Israeli forces”Agranat Commission„Has Israel Annexed East Jerusalem?”original„After 4 Years, Intifada Still Smolders”From the End of the Cold War to 2001originalThe Oslo Accords, 1993Israel-PLO Recognition – Exchange of Letters between PM Rabin and Chairman Arafat – Sept 9- 1993Foundation for Middle East PeaceSources of Population Growth: Total Israeli Population and Settler Population, 1991–2003original„Israel marks Rabin assassination”The Wye River Memorandumoriginal„West Bank barrier route disputed, Israeli missile kills 2”"Permanent Ceasefire to Be Based on Creation Of Buffer Zone Free of Armed Personnel Other than UN, Lebanese Forces"„Hezbollah kills 8 soldiers, kidnaps two in offensive on northern border”„Olmert confirms peace talks with Syria”„Battleground Gaza: Israeli ground forces invade the strip”„IDF begins Gaza troop withdrawal, hours after ending 3-week offensive”„THE LAND: Geography and Climate”„Area of districts, sub-districts, natural regions and lakes”„Israel - Geography”„Makhteshim Country”Israel and the Palestinian Territories„Makhtesh Ramon”„The Living Dead Sea”„Temperatures reach record high in Pakistan”„Climate Extremes In Israel”Israel in figures„Deuteronom”„JNF: 240 million trees planted since 1901”„Vegetation of Israel and Neighboring Countries”Environmental Law in Israel„Executive branch”„Israel's election process explained”„The Electoral System in Israel”„Constitution for Israel”„All 120 incoming Knesset members”„Statul ISRAEL”„The Judiciary: The Court System”„Israel's high court unique in region”„Israel and the International Criminal Court: A Legal Battlefield”„Localities and population, by population group, district, sub-district and natural region”„Israel: Districts, Major Cities, Urban Localities & Metropolitan Areas”„Israel-Egypt Relations: Background & Overview of Peace Treaty”„Solana to Haaretz: New Rules of War Needed for Age of Terror”„Israel's Announcement Regarding Settlements”„United Nations Security Council Resolution 497”„Security Council resolution 478 (1980) on the status of Jerusalem”„Arabs will ask U.N. to seek razing of Israeli wall”„Olmert: Willing to trade land for peace”„Mapping Peace between Syria and Israel”„Egypt: Israel must accept the land-for-peace formula”„Israel: Age structure from 2005 to 2015”„Global, regional, and national disability-adjusted life years (DALYs) for 306 diseases and injuries and healthy life expectancy (HALE) for 188 countries, 1990–2013: quantifying the epidemiological transition”10.1016/S0140-6736(15)61340-X„World Health Statistics 2014”„Life expectancy for Israeli men world's 4th highest”„Family Structure and Well-Being Across Israel's Diverse Population”„Fertility among Jewish and Muslim Women in Israel, by Level of Religiosity, 1979-2009”„Israel leaders in birth rate, but poverty major challenge”„Ethnic Groups”„Israel's population: Over 8.5 million”„Israel - Ethnic groups”„Jews, by country of origin and age”„Minority Communities in Israel: Background & Overview”„Israel”„Language in Israel”„Selected Data from the 2011 Social Survey on Mastery of the Hebrew Language and Usage of Languages”„Religions”„5 facts about Israeli Druze, a unique religious and ethnic group”„Israël”Israel Country Study Guide„Haredi city in Negev – blessing or curse?”„New town Harish harbors hopes of being more than another Pleasantville”„List of localities, in alphabetical order”„Muncitorii români, doriți în Israel”„Prietenia româno-israeliană la nevoie se cunoaște”„The Higher Education System in Israel”„Middle East”„Academic Ranking of World Universities 2016”„Israel”„Israel”„Jewish Nobel Prize Winners”„All Nobel Prizes in Literature”„All Nobel Peace Prizes”„All Prizes in Economic Sciences”„All Nobel Prizes in Chemistry”„List of Fields Medallists”„Sakharov Prize”„Țara care și-a sfidat "destinul" și se bate umăr la umăr cu Silicon Valley”„Apple's R&D center in Israel grew to about 800 employees”„Tim Cook: Apple's Herzliya R&D center second-largest in world”„Lecții de economie de la Israel”„Land use”Israel Investment and Business GuideA Country Study: IsraelCentral Bureau of StatisticsFlorin Diaconu, „Kadima: Flexibilitate și pragmatism, dar nici un compromis în chestiuni vitale", în Revista Institutului Diplomatic Român, anul I, numărul I, semestrul I, 2006, pp. 71-72Florin Diaconu, „Likud: Dreapta israeliană constant opusă retrocedării teritoriilor cureite prin luptă în 1967", în Revista Institutului Diplomatic Român, anul I, numărul I, semestrul I, 2006, pp. 73-74MassadaIsraelul a crescut in 50 de ani cât alte state intr-un mileniuIsrael Government PortalIsraelIsraelIsraelmmmmmXX451232cb118646298(data)4027808-634110000 0004 0372 0767n7900328503691455-bb46-37e3-91d2-cb064a35ffcc1003570400564274ge1294033523775214929302638955X146498911146498911

Кастелфранко ди Сопра Становништво Референце Спољашње везе Мени за навигацију43°37′18″ СГШ; 11°33′32″ ИГД / 43.62156° СГШ; 11.55885° ИГД / 43.62156; 11.5588543°37′18″ СГШ; 11°33′32″ ИГД / 43.62156° СГШ; 11.55885° ИГД / 43.62156; 11.558853179688„The GeoNames geographical database”„Istituto Nazionale di Statistica”проширитиууWorldCat156923403n850174324558639-1cb14643287r(подаци)