Créer un compilateur/interpréteur Brainfuck

Tous langages

a marqué ce sujet comme résolu.

@Eyyub : Le truc, c'est que le parser sert uniquement pour les boucles, donc c'est un peu lourd pour pas grand chose. Sinon, tu ne catch nulle part l'exception LexError, ce qui fait planter ton programme sur un caractère qui n'est pas autorisé par BF. En fait, le comportement devrait être le même que pour les espaces (ce qui permet de commenter le BF).

Concernant le parseur c'est effectivement le cas, mais j'me suis dit que puisque personne n'avait encore utilisé d'outils externes ici ce serait peut être intéressant pour les yeux de certains. :)
Pour l'exception LexError j'ai complètement oublié merci, faut que je catch Invalid_argument aussi.
Et d'accord pour le comportement, j'ai juste pris le tableau de l'article wikipedia c'était pas signifié !

+0 -0

En C# :

OperationsEnum.cs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    enum OperationsEnum
    {
        IncrementAdresse = '>',
        DecrementAdresse = '<',
        IncrementValeur = '+',
        DecrementValeur = '-',
        Sortie = '.',
        Entree = ',',
        DebutBoucle = '[',
        FinBoucle = ']'
    }

Brainfuck.cs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
    class Brainfuck
    {
        private readonly Dictionary<char, Action> _actions;
        private readonly StateMachine _stateMachine;

        public Brainfuck()
        {
            _stateMachine = new StateMachine();
            _actions = new Dictionary<char, Action>
            {
                {(char) OperationsEnum.DebutBoucle, _stateMachine.DebutBoucle},
                {(char) OperationsEnum.FinBoucle, _stateMachine.FinBoucle},
                {(char) OperationsEnum.IncrementValeur, _stateMachine.IncrementValeur},
                {(char) OperationsEnum.DecrementValeur, _stateMachine.DecrementValeur},
                {(char) OperationsEnum.IncrementAdresse, _stateMachine.IncrementAdresse},
                {(char) OperationsEnum.DecrementAdresse, _stateMachine.DecrementAdresse},
                {(char) OperationsEnum.Entree, EntreeCurrentChar},
                {(char) OperationsEnum.Sortie, SortieCurrentChar},
            };
        }

        public void Run(string bf)
        {
            char[] instructions = bf.ToCharArray().Where(b => _actions.ContainsKey(b)).ToArray();
            while (_stateMachine.InstructionPointer < instructions.Length)
            {
                Action action = _actions[instructions[_stateMachine.InstructionPointer]];
                action.Invoke();
            }
        }

        private void EntreeCurrentChar()
        {
            ConsoleKeyInfo key = Console.ReadKey();
            _stateMachine.CurrentChar = key.KeyChar;
            _stateMachine.IncrementInstructionPointer();
        }

        private void SortieCurrentChar()
        {
            Console.Write(_stateMachine.CurrentChar);
            _stateMachine.IncrementInstructionPointer();
        }
    }

StateMachine.cs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
 class StateMachine
    {
        public int InstructionPointer { get; private set; }
        private int _dataPointer;
        private readonly char[] _buf;
        private readonly Stack<int> _nested;
        private static readonly int BUFSIZE = 65535;

        public StateMachine()
        {
            InstructionPointer = 0;
            _dataPointer = 0;
            _buf = new char[BUFSIZE];
            _nested = new Stack<int>();
        }

        public char CurrentChar
        {
            get { return _buf[_dataPointer]; }
            set { _buf[_dataPointer] = value; }
        }

        public void IncrementInstructionPointer()
        {
            InstructionPointer++;
        }

        public void IncrementValeur()
        {
            CurrentChar++;
            IncrementInstructionPointer();
        }

        public void DecrementValeur()
        {
            CurrentChar--;
            IncrementInstructionPointer();
        }

        public void IncrementAdresse()
        {
            _dataPointer++;
            IncrementInstructionPointer();
        }

        public void DecrementAdresse()
        {
            _dataPointer--;
            IncrementInstructionPointer();
        }

        public void DebutBoucle()
        {
            _nested.Push(InstructionPointer);
            IncrementInstructionPointer();
        }

        public void FinBoucle()
        {
            if (CurrentChar == 0)
                IncrementInstructionPointer();
            else
                InstructionPointer = _nested.Pop();
        }
    }

Pour le lancer : Program.cs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 class Program
    {
        public const string HelloWorld = "+[>,]<[-[+.<-]]";
        static void Main(string[] args)
        {
            Brainfuck bf = new Brainfuck();
            bf.Run(HelloWorld);

            Console.ReadKey();
        }
    }

Pour le coup de la "," je ne suis pas sur, faut que je regarde encore, j'ai testé avec +[>,]<[-[+.<-]]

Je pense que j'aurais peut être du utiliser un byte[] au lieu d'un char[]. :)

+0 -0

Voici ma participation (merci à zyhou de m'avoir indiqué ce site) :

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// © CC BY-NC-SA 4.0 - 2014
// License details can be found here : http://creativecommons.org/licenses/by-nc-sa/4.0/legalcode

using System;
using System.Collections.Generic;
using System.IO;

namespace MysteryDash.Brainfuck
{
    /// <summary>
    /// Provides methods to execute or debug a brainfuck program
    /// </summary>
    public sealed class Interpreter
    {
        /// <summary>
        /// The Brainfuck Program
        /// </summary>
        public String Program { get; private set; }
        /// <summary>
        /// Program Counter
        /// </summary>
        public Int32 PC { get; private set; }
        /// <summary>
        /// Stack Used for Loops
        /// </summary>
        private Stack<Int32> LoopStack { get; set; }
        /// <summary>
        /// The Memory Array, Default Size is 30.000 Bytes
        /// </summary>
        public Byte[] Memory { get; private set; }
        /// <summary>
        /// The Memory Pointer
        /// </summary>  
        public Int32 MemoryPtr { get; private set; }
        /// <summary>
        /// The Input Stream, Input Data from ',' Instruction
        /// </summary>
        public TextReader Input { get; private set; }
        /// <summary>
        /// The Output Stream, Output Data from '.' Instruction
        /// </summary>
        public TextWriter Output { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see ref="Interpreter"/> class.
        /// </summary>
        /// <param name="Input">Input Data from ',' Instruction</param>
        /// <param name="Output">Output Data from '.' Instruction</param>
        public Interpreter(TextReader Input, TextWriter Output)
        {
            this.Input = Input;
            this.Output = Output;
        }

        /// <summary>
        /// Load a Brainfuck Program in the Interpreter
        /// </summary>
        /// <param name="BrainfuckProgram">The Brainfuck Program</param>
        /// <param name="CustomMemorySize">The Memory Array Size, Default is 30.000 Bytes</param>
        public void Load(String BrainfuckProgram, Int32 CustomMemorySize = 30000)
        {
            Program = BrainfuckProgram;
            PC = 0;
            LoopStack = new Stack<Int32>();
            Memory = new Byte[CustomMemorySize];
            MemoryPtr = 0;
        }

        /// <summary>
        /// Execute the Next Instruction, Ignore Every Non-Instruction Characters
        /// </summary>
        /// <returns>Return False if EOF</returns>
        public Boolean PerformNextInstruction()
        {
            // Check for the next instruction and ignore every non-instruction characters.
            // Catch an exception if EOF.
            try
            {
                while ("><+-.,[]".IndexOf(Program[PC]) == -1)
                {
                    PC++;
                }

                switch (Program[PC])
                {
                    case '>': // Increase Memory Pointer
                        MemoryPtr++;
                        break;
                    case '<': // Decrease Memory Pointer
                        if (MemoryPtr > 0) MemoryPtr--;
                        break;
                    case '+': // Increase Data at Memory Pointer
                        if (Memory[MemoryPtr] != 0xFF) Memory[MemoryPtr]++;
                        break;
                    case '-': // Decrease Data at Memory Pointer
                        if (Memory[MemoryPtr] != 0x0) Memory[MemoryPtr]--;
                        break;
                    case '.': // Output Data at Memory Pointer
                        Output.Write((Char)Memory[MemoryPtr]);
                        Output.Flush();
                        break;
                    case ',': // Input Data to Memory Pointer
                        Memory[MemoryPtr] = (byte)Math.Max(0, Input.Read());
                        break;
                    case '[': // Loop Start - More Infos on Wikipedia
                        if (Memory[MemoryPtr] == 0x0)
                        {
                            PC++;
                            Int32 InnerLoops = 0;
                            while (Program[PC] != ']' || InnerLoops != 0)
                            {
                                if (Program[PC] == '[')
                                    InnerLoops++;
                                else if (Program[PC] == ']' && InnerLoops > 0)
                                    InnerLoops--;
                                PC++;
                            }
                        }
                        else
                            LoopStack.Push(PC);
                        break;
                    case ']': // Loop End - More Infos on Wikipedia
                        if (Memory[MemoryPtr] != 0x0)
                            PC = LoopStack.Peek();
                        else
                            LoopStack.Pop();
                        break;
                }

                PC++; // Go to the Next Instruction
            }
            catch (IndexOutOfRangeException)
            {
                return false; // EOF
            }

            return true;
        }
    }
}
+0 -0

Question bête : quelqu'un connaît un vrai programme BrainFuck, genre un truc qui calcule des décimales de Pi ou n'importe quoi ? Ce serait pour m'amuser à tester les performances de diverses approches pour la compilation.

GuilOooo

Les décimales de Pi, visiblement ça a été fait mais je n'ai pas trouvé de source. Par contre j'ai trouvé ça qui fait pas mal de calculs pour un résultat assez chouette (ça affiche une fractale de Mandelbrot).

+0 -0

Question bête : quelqu'un connaît un vrai programme BrainFuck, genre un truc qui calcule des décimales de Pi ou n'importe quoi ? Ce serait pour m'amuser à tester les performances de diverses approches pour la compilation.

GuilOooo

Les décimales de Pi, visiblement ça a été fait mais je n'ai pas trouvé de source. Par contre j'ai trouvé ça qui fait pas mal de calculs pour un résultat assez chouette (ça affiche une fractale de Mandelbrot).

Alex

Je l'ai trouvé aussi et tenté de faire exécuter le mandelbrot.b à mon interpréteur, sans résultat (toujours rien au bout de 3 minutes). T'as réussi à afficher la fractale ?

Voici le début de ma participation. C’est un interpréteur. Les boucles ne sont pas encore gérées, car cela complique nettement les choses. Il devient indispensable de mémoriser le code du programme d’une certaine façon, et embarquer le rouleau de données et celui du code dans le rouleau de données de l’interpréteur sera acrobatique (je pense les entrelacer, une case sur deux), et risque de démolir les performances.

Bien sûr, il faut un interpréteur Brainfuck fonctionnel dont le chemin est à adapter dans le shebang.


Pour des codes en Brainfuck, d’après tcpc ce site est/était chouette (down en ce moment, mais « back soon » ?).

+0 -0

Voici ma participation en C++. Le compilateur tient en 2 fichiers (il a été "conçu" pour être intégré à un autre projet si besoin). Il permet de compiler (plutôt traduire littéralement en vérité) du Brainf*ck (classique et Extended Brainf*ck Type 1) en C ou en C++.

main.cpp

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
#include <iostream>
#include <fstream>
#include <string>

#include "bfc.hpp"

// Compiler
int main(int argc, char* argv[])
{
    std::string input_filepath = "";
    std::string output_stream_name = "stdout";
    std::string target_language = "C";
    bool extended_brainfuck = false;

    // Parse the arguments;
    for(int i(0) ; i < argc ; ++i)
    {
        std::stringstream ss(argv[i]);

        std::string arg_var("");
        std::string arg_value("");

        std::getline(ss, arg_var, '=');
        std::getline(ss, arg_value, '\n');

        if(arg_var == "input")
        {
            input_filepath = arg_value;
        }
        else if(arg_var == "output")
        {
            output_stream_name = arg_value;
        }
        else if(arg_var == "language")
        {
            target_language = arg_value;
        }
        else if(arg_var == "extended_brainfuck")
        {
            if(arg_value == "true")
                extended_brainfuck = true;
        }
    }

    if(input_filepath == "")
    {
        std::cout << "No arguments given." << std::endl
                << "Use :" << std::endl
                << "bfc" << std::endl
                << bfc::htab << "input=<input file path>" << std::endl
                << bfc::htab << "[output=<stdout or output file path>]" << std::endl
                << bfc::htab << "[language=<target language : C or C++>]" << std::endl
                << bfc::htab << "[extended_brainfuck=<true or false>]" << std::endl
                << std::endl;

        return 0;
    }

    // Default : input file and std::cout.
    std::ifstream inputfile(input_filepath.c_str());
    std::ostream* outputstream(&std::cout);

    // Check if output is a file.
    if(output_stream_name != "stdout")
        outputstream = new std::ofstream(output_stream_name);

    // Check streams states.
    if(!inputfile || !outputstream)
    {
        std::cerr << "Cannot access (file) io." << std::endl;
        std::cerr << "Compilation failed." << std::endl;

        delete outputstream;
        return 1;
    }

    // String containing BrainFuck code.
    std::string bf_code("");

    try
    {
        // Lex.
        bf_code = bfc::lex_stream(inputfile);
    }
    catch(std::exception& e)
    {
        std::cerr << e.what() << std::endl;
        std::cerr << "Compilation failed." << std::endl;

        delete outputstream;
        return 1;
    }

    // Compile.
    if(bfc::generate_output(bf_code, *outputstream, std::cerr, extended_brainfuck, target_language))
    {
        std::cout << "Compilation success !" << std::endl;

        delete outputstream;
        return 0;
    }
    else
    {
        std::cerr << "Compilation failed." << std::endl;

        delete outputstream;
        return 1;
    }

  return 0;
}

bfc.hpp

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
#ifndef BRAINFUCK_COMPILER_HPP_INCLUDED
#define BRAINFUCK_COMPILER_HPP_INCLUDED

#include <string>
#include <stack>
#include <exception>

#include <ctime>

#include <iostream>
#include <sstream>
#include <fstream>

/*
    BrainFuck Compiler Interface.
*/
namespace bfc
{
    // Useful char.
    char htab = '\t';

    // Convert T type to std::string.
    template<typename T>
    std::string to_str(T x)
    {
        std::stringstream ss("");

        ss << x;

        return ss.str();
    }

    // Custom exception class.
    class bfc_exception : public std::exception
    {
        public:
            // Ctor.
            bfc_exception(std::string what = "") : m_what(what)
            {}

            // Dtor.
            virtual ~bfc_exception(){}

            // What.
            virtual const char* what() const noexcept(true)
            {
                return m_what.c_str();
            }

        protected:
            std::string m_what;
    };

    // Lex the input stream and return a string with the BrainFuck code only.
    std::string lex_stream(std::istream& inputstream,
                           bool mode_extended_brainfuck_type_1 = false)
    {
        // BrainFuck code only stream.
        std::stringstream bf_code("");

        // Braces stack.
        std::stack<unsigned int> braces;

        // Read the stream.
        while(!inputstream.eof())
        {
            char current_char = inputstream.get();

            // Standard BrainFuck.
            switch(current_char)
            {
                case '[':
                    braces.push(inputstream.tellg());
                    bf_code << current_char;
                    break;
                case ']':
                    braces.pop();
                    bf_code << current_char;
                    break;
                case '>':
                case '<':
                case '+':
                case '-':
                case '.':
                case ',':
                    bf_code << current_char;
                    break;
                default:
                    break;
            }

            // Extended BrainFuck type 1.
            if(mode_extended_brainfuck_type_1)
            {
                switch(current_char)
                {
                    case '@':
                    case '$':
                    case '!':
                    case '}':
                    case '{':
                    case '~':
                    case '^':
                    case '&':
                    case '|':
                        break;
                    default:
                        break;
                }
            }
        }

        // Check for braces.
        if(braces.size() != 0)
            throw bfc_exception(std::string("Unclosed square brace at position : ") + to_str(braces.top()));

        return bf_code.str();
    }

    // Print the required indentations.
    void print_indentation(std::ostream& outputstream, unsigned int current_indentation_level)
    {
        for(unsigned int tab(0) ; tab < current_indentation_level ; ++tab)
            outputstream << htab;
    }

    // Parse the string containing BrainFuck code only and ouput the C or C++ code in the std::ostream and the errors in another std::ostream.
    bool generate_output(std::string bf_code,
                      std::ostream& outputstream = std::cout,
                      std::ostream& error_stream = std::cerr,
                      bool extended_brainfuck_type_1 = false,
                      std::string target_language = "C")
    {
        outputstream << "/*" << std::endl
                    << htab << "Compiled using bfc." << std::endl
                    << htab << "Time is : " << time(nullptr) << std::endl
                    << "*/" << std::endl << std::endl;

        if(target_language == "C")
        {
            outputstream << "#include <stdio>" << std::endl
                        << "#include <stdlib>" << std::endl
                        << std::endl
                        << "int main(void){" << std::endl
                        << htab << "// Memory." << std::endl
                        << htab << "const unsigned int memory_size = 30000;" << std::endl
                        << htab << "char[memory_size] memory{0};" << std::endl
                        << htab << "int ptr = 0;" << std::endl << std::endl;

            if(extended_brainfuck_type_1)
            {
                outputstream << "// For extended BrainFuck type 1." << std::endl
                        << htab << "char unique_storage_char(0);" << std::endl << std::endl;
            }
        }
        else if(target_language == "C++")
        {
            outputstream << "#include <iostream>" << std::endl
                        << "#include <vector>" << std::endl
                        << std::endl
                        << "int main(){" << std::endl
                        << htab << "// Memory." << std::endl
                        << htab << "std::vector<char> memory(30000, '\\0');" << std::endl
                        << htab << "std::vector<char>::iterator ptr(memory.begin());" << std::endl << std::endl;

            if(extended_brainfuck_type_1)
            {
                outputstream << "// For extended BrainFuck type 1." << std::endl
                        << htab << "char unique_storage_char(0);" << std::endl << std::endl;
            }
        }
        else
        {
            error_stream << "Error : target language unknown : " << target_language << std::endl;
            return false;
        }

        // For a nicer output.
        unsigned int current_indentation_level(1);

        // Used to abort compilation.
        bool compilation_finished(false);

        for(unsigned int i(0) ; i < bf_code.size() && !compilation_finished ; ++i)
        {
            print_indentation(outputstream, current_indentation_level);

            switch(bf_code.at(i))
            {
                case '[':
                    // Increase indentation level.
                    current_indentation_level++;

                    if(target_language == "C")
                    {
                        outputstream << "while(memory[ptr]){" << std::endl;
                    }
                    else if(target_language == "C++")
                    {
                        outputstream << "while(*ptr){" << std::endl;
                    }
                    break;
                case ']':
                    // Decrease indentation level.
                    current_indentation_level--;

                    // Warning : infinite loop.
                    if(i > 0 && bf_code.at(i - 1) == '[')
                        error_stream << "Warning : infinite loop (check your code for \"[]\" sequences)." << std::endl;

                    if(target_language == "C" || target_language == "C++")
                    {
                        outputstream << "}" << std::endl;
                    }
                    break;
                case '>':
                    outputstream << "// We need to be careful." << std::endl;

                    if(target_language == "C")
                    {
                        print_indentation(outputstream, current_indentation_level);
                        outputstream << "if(ptr + 1 < memory_size)" << std::endl;

                        print_indentation(outputstream, current_indentation_level);
                        outputstream << htab << "ptr++;" << std::endl;

                        print_indentation(outputstream, current_indentation_level);
                        outputstream << "else" << std::endl;

                        print_indentation(outputstream, current_indentation_level);
                        outputstream << htab << "ptr = 0;" << std::endl;
                    }
                    else if(target_language == "C++")
                    {
                        print_indentation(outputstream, current_indentation_level);
                        outputstream << "if(ptr != memory.end())" << std::endl;

                        print_indentation(outputstream, current_indentation_level);
                        outputstream << htab << "ptr++;" << std::endl,

                        print_indentation(outputstream, current_indentation_level);
                        outputstream << "else" << std::endl;

                        print_indentation(outputstream, current_indentation_level);
                        outputstream << htab << "ptr = memory.begin();" << std::endl;
                    }
                    break;
                case '<':
                    outputstream << "// We need to be careful." << std::endl;

                    if(target_language == "C")
                    {
                        print_indentation(outputstream, current_indentation_level);
                        outputstream << "if(ptr - 1 < 0)" << std::endl;

                        print_indentation(outputstream, current_indentation_level);
                        outputstream << htab << "ptr--;" << std::endl;

                        print_indentation(outputstream, current_indentation_level);
                        outputstream << "else" << std::endl;

                        print_indentation(outputstream, current_indentation_level);
                        outputstream << htab << "ptr = memory_size - 1;" << std::endl;
                    }
                    else if(target_language == "C++")
                    {
                        print_indentation(outputstream, current_indentation_level);
                        outputstream << "if(ptr != memory.begin())" << std::endl;

                        print_indentation(outputstream, current_indentation_level);
                        outputstream << htab << "ptr--;" << std::endl;

                        print_indentation(outputstream, current_indentation_level);
                        outputstream << "else" << std::endl;

                        print_indentation(outputstream, current_indentation_level);
                        outputstream << htab << "ptr = memory.begin();" << std::endl;
                    }
                    break;
                case '+':
                    if(target_language == "C")
                    {
                        outputstream << "memory[ptr]++;" << std::endl;
                    }
                    else if(target_language == "C++")
                    {
                        outputstream << "(*ptr)++;" << std::endl;
                    }
                    break;
                case '-':
                    if(target_language == "C")
                    {
                        outputstream << "memory[ptr]--;" << std::endl;
                    }
                    else if(target_language == "C++")
                    {
                        outputstream << "(*ptr)--;" << std::endl;
                    }
                    break;
                case '.':
                    if(target_language == "C")
                    {
                        outputstream << "putchar(memory[ptr]);" << std::endl;
                    }
                    else if(target_language == "C++")
                    {
                        outputstream << "std::cout.put(*ptr);" << std::endl;
                    }
                    break;
                case ',':
                    if(target_language == "C")
                    {
                        outputstream << "memory[ptr] = getchar();" << std::endl;
                    }
                    else if(target_language == "C++")
                    {
                        outputstream << "(*ptr) = std::cin.get();" << std::endl;
                    }
                    break;
                default:
                    break;
            }

            if(extended_brainfuck_type_1)
            {
                switch(bf_code.at(i))
                {
                    case '@':
                        outputstream << "exit(0);" << std::endl;
                        compilation_finished = true;
                        break;
                    case '$':
                        if(target_language == "C")
                        {
                            outputstream << "unique_storage_char = memory[ptr];" << std::endl;
                        }
                        else if(target_language == "C++")
                        {
                            outputstream << "unique_storage_char = (*ptr);" << std::endl;
                        }
                        break;
                    case '!':
                        if(target_language == "C")
                        {
                            outputstream << "memory[ptr] = unique_storage_char;" << std::endl;
                        }
                        else if(target_language == "C++")
                        {
                            outputstream << "(*ptr) = unique_storage_char;" << std::endl;
                        }
                        break;
                    case '}':
                        if(target_language == "C")
                        {
                            outputstream << "memory[ptr] >>= 1;" << std::endl;
                        }
                        else if(target_language == "C++")
                        {
                            outputstream << "(*ptr) >>= 1;" << std::endl;
                        }
                        break;
                    case '{':
                        if(target_language == "C")
                        {
                            outputstream << "memory[ptr] <<= 1;" << std::endl;
                        }
                        else if(target_language == "C++")
                        {
                            outputstream << "(*ptr) <<= 1;" << std::endl;
                        }
                        break;
                    case '~':
                        if(target_language == "C")
                        {
                            outputstream << "memory[ptr] = ~memory[ptr];" << std::endl;
                        }
                        else if(target_language == "C++")
                        {
                            outputstream << "(*ptr) = ~(*ptr);" << std::endl;
                        }
                        break;
                    case '^':
                        if(target_language == "C")
                        {
                            outputstream << "memory[ptr] = memory[ptr] ^ unique_storage_char;" << std::endl;
                        }
                        else if(target_language == "C++")
                        {
                            outputstream << "(*ptr) = (*ptr) ^ unique_storage_char;" << std::endl;
                        }
                        break;
                    case '&':
                        if(target_language == "C")
                        {
                            outputstream << "memory[ptr] = memory[ptr] & unique_storage_char;" << std::endl;
                        }
                        else if(target_language == "C++")
                        {
                            outputstream << "(*ptr) = (*ptr) & unique_storage_char;" << std::endl;
                        }
                        break;
                    case '|':
                        if(target_language == "C")
                        {
                            outputstream << "memory[ptr] = memory[ptr] | unique_storage_char;" << std::endl;
                        }
                        else if(target_language == "C++")
                        {
                            outputstream << "(*ptr) = (*ptr) | unique_storage_char;" << std::endl;
                        }
                        break;
                    default:
                        break;
                }
            }
        }

        if(target_language == "C" || target_language == "C++")
        {
            outputstream << "}" << std::endl;
        }

        return true;
    }

} // namespace bfc.

#endif // BRAINFUCK_COMPILER_HPP_INCLUDED

+0 -0

@Maëlan : je me demandais si quelqu'un allait y penser à celle là :) . Bonne chance pour les boucles en tout cas.

EDIT/PS : Si vous avez des codes BF que vous trouvez pertinents à ajouter au premier post (test/performances/fun), dites le moi (histoire de centraliser les bouts de BF intéressants).

Je l'ai trouvé aussi et tenté de faire exécuter le mandelbrot.b à mon interpréteur, sans résultat (toujours rien au bout de 3 minutes). T'as réussi à afficher la fractale ?

tcpc

Ça prend un peu de temps mais chez moi, ça marche, oui ! J'ai aussi essayé de le compiler en C avec le code de Bibibye puis avec gcc -O3, et ça va encore plus vite (le résultat est produit en à peine deux secondes !)

Bibibye : je pense que tu peux rajouter le Mandelbrot à ton post initial à titre d'exemple.

+0 -0

Ça prend un peu de temps mais chez moi, ça marche, oui ! J'ai aussi essayé de le compiler en C avec le code de Bibibye puis avec gcc -O3, et ça va encore plus vite (le résultat est produit en à peine deux secondes !)

Bibibye : je pense que tu peux rajouter le Mandelbrot à ton post initial à titre d'exemple.

Alex

Ah ben ça fonctionne chez moi aussi en fait. Fallait juste que je me montre un peu plus patient :-° :

1
2
3
real    3m56.606s
user    3m55.850s
sys 0m0.053s

Bon, passons aux choses sérieuses. Voici un code Haskell qui génère du Brainfuck pour un programme non trivial. En l'occurence le programme est donné sous forme monadique en Haskell même : c'est un programme qui donne la liste des carrés des entiers jusqu'à 42.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
import Control.Monad.State.Lazy
import Data.Char

{- BF State Monad -}

type BFCode  = String
type BFState = (BFCode, Int, [Int])

type BFGen = State BFState

runBf :: BFGen () -> String
runBf x = let (_, (code, _, _)) = runState x ("", 0, []) in code

{- BF cell allocation -}

alloc :: BFGen Int
alloc = do  (code, pos, used) <- get
            let cell = head $ filter (\x -> not (x `elem` used)) [0..]
            put (code, pos, cell : used)
            return cell

free :: Int -> BFGen ()
free x = do (code, pos, used) <- get
            put (code, pos, filter (/= x) used)
freeList :: [Int] -> BFGen ()
freeList = foldl (>>) (return ()) . map free

{- BF base functions -}

goto :: Int -> BFGen ()
goto i = do (code, pos, used) <- get
            let move = if pos < i
                        then take (i-pos) $ repeat '>'
                        else take (pos-i) $ repeat '<'
            put (code ++ move, i, used)

incr :: Int -> BFGen ()
incr i = do (code, pos, used) <- get
            put (code ++ (take i $ repeat '+'), pos, used)

decr :: Int -> BFGen ()
decr i = do (code, pos, used) <- get
            put (code ++ (take i $ repeat '-'), pos, used)

emit :: String -> BFGen ()
emit c = do (code, pos, used) <- get
            put (code ++ c, pos, used)

zero :: BFGen ()
zero = emit "[-]"

allocz :: BFGen Int
allocz = do pos <- alloc
            goto pos
            zero
            return pos

loop :: Int -> BFGen () -> BFGen ()
loop cond body = do goto cond
                    emit "["
                    body
                    goto cond
                    emit "]"

copy2 :: Int -> Int -> BFGen ()
copy2 a b = do  goto b
                zero
                tmp <- allocz
                loop a $ do
                  goto tmp
                  incr 1
                  goto b
                  incr 1
                  goto a
                  decr 1
                loop tmp $ do goto a; incr 1; goto tmp; decr 1
                free tmp

copy :: Int -> BFGen Int
copy a = do b <- alloc
            copy2 a b
            return b

iff :: Int -> BFGen () -> BFGen ()
iff c body = do tmp <- copy c
                loop tmp $ do
                  goto tmp
                  zero
                  body
                free tmp

bnot :: Int -> BFGen Int
bnot i = do neg <- allocz
            goto neg
            incr 1
            tmp <- copy i
            iff tmp $ do goto neg; zero
            free tmp
            return neg

branch :: Int -> BFGen () -> BFGen () -> BFGen ()
branch cond ba bb = do  neg_cond <- bnot cond
                        iff cond ba
                        iff neg_cond bb
                        free neg_cond


fastIncr :: Int -> Int -> BFGen ()
fastIncr pos i = if i < 42
                then do goto pos; incr i
                else do
                  a <- allocz
                  fastIncr a ix
                  count <- copy a
                  loop count $ do
                    tmp <- allocz
                    loop a $ do goto pos; incr 1; goto tmp; incr 1; goto a; decr 1
                    loop tmp $ do goto a; incr 1; goto tmp; decr 1
                    free tmp
                    goto count; decr 1
                  free a
                  free count
                  goto pos
                  incr (i - ix * ix)
  where isqrt = floor . sqrt . fromIntegral
        ix = isqrt i

i :: Int -> BFGen Int
i x = do  pos <- allocz
          fastIncr pos x
          return pos

s :: String -> BFGen [Int]
s "" = return []
s (x:xs) = do qs <- s xs
              q <- allocz
              fastIncr q $ ord x
              return (q:qs)

puts :: [Int] -> BFGen ()
puts [] = return ()
puts (x:xs) = do  goto x
                  emit "."
                  puts xs

{- BF arithmetic -}

add va vb = loop vb $ do goto va; incr 1; goto vb; decr 1
sub va vb = loop vb $ do goto va; decr 1; goto vb; decr 1
mul va vb = do branch vb
                (do tmp <- copy va
                    goto vb
                    decr 1
                    loop vb $ do
                      goto vb
                      decr 1
                      tmp2 <- copy tmp
                      add va tmp2
                      free tmp2
                    free tmp)
                (do goto va
                    zero)

leq :: Int -> Int -> Int -> BFGen ()
leq c a b = do  lc <- allocz
                iff a $ iff b $ do goto lc; incr 1
                aa <- copy a
                bb <- copy b
                loop lc $ do
                  goto aa; decr 1; goto bb; decr 1
                  goto lc; zero
                  iff aa $ iff bb $ do goto lc; incr 1
                free lc
                free bb
                goto c; zero
                qa <- bnot aa
                free aa
                iff qa $ do goto c; incr 1
                free qa
                    
printDec :: Int -> BFGen ()
printDec = printDec' 5
  where printDec' n x =
          if n == 0
            then return ()
            else do
              ten <- i 10
              q <- allocz
              r <- copy x
              c <- alloc
              leq c ten r
              loop c $ do
                goto r
                decr 10
                goto q
                incr 1
                leq c ten r
              free ten
              free c
              iff q $ printDec' (n-1) q
              free q
              fastIncr r 48
              goto r
              emit "."
              free r
                

{- Sample program -}

hello_bf = do msg <- s "Hello, world! Here is a nice list of squares:\n"
              puts msg
              freeList msg
              nl <- s "\n"
              squared <- s "^2 = "
              x <- i 42
              y <- copy x
              loop x $ do
                goto x
                decr 1
                z <- copy y
                t <- copy x
                sub z t
                st <- i 2
                loop st $ do
                  goto st; decr 1
                  what <- alloc
                  branch st
                    (return ())
                    (do puts squared
                        copy2 z t
                        mul z t)
                  printDec z
                free z
                free t
                puts nl
              free x
              free y

main :: IO ()
main = putStr $ runBf hello_bf

En l'occurence le résultat est vraiment sous-optimal (on a vu un programme qui faisait la même chose en quelques lignes), mais ça marche et on peut considérer que c'est une base pour un compilateur vers Brainfuck ^^ Un des problèmes de mon code c'est que la mémoire brainfuck n'est pas considéree comme une pile, du coup je n'ai pas d'instructions du type pop/push, ce qui rend difficile l'implémentation de fonctions telles que l'affichage d'un nombre sous forme décimale (c'est ça qui prend toute la place dans ce programme, et encore je me limite aux nombres à quatre chiffres). Une autre raison pour laquelle le code est si gros c'est qu'il n'y a aucune réutilisation des valeurs présentes dans les cases mémoire (on a souvent des constantes qu'il pourrait être judicieux de réutiliser).

Le code BF généré :

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

+0 -0

Je vais jouer aussi avec vous pour la peine. Je n'ai pas encore d'interpréteur, mais j'ai un fichier d'exemple pour vous:

1
2
3
4
[-] ++++   > [-] < [->++++++++++<] > +  >
[-] ++++++ > [-] < [->++++++++++<] > -- >
[-] [[]<->]
<.<<.

Si votre interpréteur est fonctionnel, :) devrait s'afficher à la sortie.


Je repars faire le mien.

Bon bah un compilateur vers nasm:

lexer.mll

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  open Parser
}

rule lexer = parse
 | eof    { TEof         }
 | "+"    { TPlus        }
 | "-"    { TMinus       }
 | ">"    { TSup         }
 | "<"    { TInf         }
 | "."    { TDot         }
 | ","    { TComma       }
 | "["    { TLBR         }
 | "]"    { TRBR         }
 | _      { lexer lexbuf }

parser.mly

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
%{

%}

%token TPlus TMinus
%token TSup TInf
%token TDot
%token TComma
%token TLBR TRBR
%token TEof

%start <Ast.t list> prgm

%%

prgm:
| s = sequence TEof { s }

sequence:
| a = expr s = sequence { a :: s }
| a = expr { [ a ] }

expr:
| TPlus     { Ast.Incr_val }
| TMinus    { Ast.Decr_val }
| TSup      { Ast.Incr_ptr }
| TInf      { Ast.Decr_ptr }
| TDot      { Ast.Print_word }
| TComma    { Ast.Read_word }
| TLBR TRBR { Ast.Loop [] }
| TLBR s = sequence TRBR
{ Ast.Loop s }

nasm.ml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
let increment_ptr output =
  let open Printf in
  fprintf output "mov   eax, [offset]\n";
  fprintf output "inc   eax\n";
  fprintf output "mov   [offset], eax\n"

let decrement_ptr output =
  let open Printf in
  fprintf output "mov   eax, [offset]\n";
  fprintf output "sub   eax, 1\n";
  fprintf output "mov   [offset], eax\n"

let increment_val output =
  let open Printf in
  fprintf output "mov   ecx, [offset]\n";
  fprintf output "mov   ebx, buffer\n";
  fprintf output "mov   al, [ebx + ecx]\n";
  fprintf output "inc   al\n";
  fprintf output "mov   [ebx + ecx], al\n"

let decrement_val output =
  let open Printf in
  fprintf output "mov   ecx, [offset]\n";
  fprintf output "mov   ebx, buffer\n";
  fprintf output "mov   al, [ebx + ecx]\n";
  fprintf output "sub   al, 1\n";
  fprintf output "mov   [ebx + ecx], al\n"

let read_word output =
  let open Printf in
  fprintf output "mov   ecx, 0\n";
  fprintf output "push  ecx\n";
  fprintf output "call  read\n";
  fprintf output "mov   ecx, [offset]\n";
  fprintf output "mov   ebx, buffer\n";
  fprintf output "mov   [ebx+ecx], ah\n"

let print_word output =
  let open Printf in
  fprintf output "mov   eax, 4\n";
  fprintf output "mov   ebx, 1\n";
  fprintf output "mov   ecx, [offset]\n";
  fprintf output "mov   edx, buffer\n";
  fprintf output "add   ecx, edx\n";
  fprintf output "mov   edx, 1\n";
  fprintf output "int   0x80\n"

let generate =
  let i = ref 0 in
  (fun () -> let r = !i in incr i; r)

let rec loop output node =
  let open Printf in
  let id = generate () in
  fprintf output "mov   esi, [offset]\n";
  fprintf output "mov   al, [buffer + esi]\n";
  fprintf output "cmp   al, 0\n";
  fprintf output "je    enode%d\n" id;
  fprintf output "bnode%d:\n" id;
  compute output node;
  fprintf output "mov   esi, [offset]\n";
  fprintf output "mov   al, [buffer + esi]\n";
  fprintf output "cmp   al, 0\n";
  fprintf output "jne   bnode%d\n" id;
  fprintf output "enode%d:\n" id;
and compute output = function
  | [] -> ()
  | x :: r ->
    (match x with
     | Ast.Incr_ptr -> increment_ptr output
     | Ast.Decr_ptr -> decrement_ptr output
     | Ast.Incr_val -> increment_val output
     | Ast.Decr_val -> decrement_val output
     | Ast.Read_word -> read_word output
     | Ast.Print_word -> print_word output
     | Ast.Loop l -> loop output l);
    compute output r

let eval instr output =
  let open Printf in
  fprintf output "global _start\n";
  fprintf output "section .data\n";
  fprintf output "section .bss\n";
  fprintf output "  buffer: resb 4000\n";
  fprintf output "  offset: resq 1\n";
  fprintf output "  instr:  resq 1\n";
  fprintf output "section .text\n";
  fprintf output "_start:\n";
  compute output instr;
  fprintf output "mov   ebx, 0\n";
  fprintf output "mov   eax, 1\n";
  fprintf output "int   0x80\n";

bfc.ml

1
2
3
4
5
6
7
8
let of_string str =
  Parser.prgm Lexer.lexer (Lexing.from_string str)

let of_input input =
  Parser.prgm Lexer.lexer (Lexing.from_channel input)

let () =
  Nasm.eval (of_input stdin) stdout

Ensuite:

1
2
3
4
5
ocamlbuild -use-menhir bfc.native
./bfc.native < mandelbrot.bf > mandelbrot.asm
nasm -f elf64 -g mandelbrot.asm
ld -g mandelbrot.o
./a.out

On peut faire pas mal d'optimisation comme des réductions de < et de > qui se suivent ou la suppression de code mort comme []. Bref, enjoy!

EDIT: Un petit time

1
2
3
real 18.88
user 18.67
sys 0.03

Alex : même si ton code fait une certaine taille, je pense qu'il est mieux de le poster ici (quitte à mettre une balise secret) que de l'héberger sur un service externe. Ainsi, le topic demeurera lisible aussi longtemps que ZdS durera, même si le paste ferme ou change d'adresse. :)

J'aime bien ton code, autrement, le principe est intéressant je trouve.


Suite à une discussion sur IRC, j'édite mon post précédent (celui qui contient mon code Lisp) afin d'ajouter quelques explications.


Autrement, quelqu'un a déjà tenté le compilateur inverse ? Je veux dire, générer le BrainFuck correspondant à un code écrit en Pascal (ou autre langage relativement simple) ?

+0 -0

Alex : même si ton code fait une certaine taille, je pense qu'il est mieux de le poster ici (quitte à mettre une balise secret) que de l'héberger sur un service externe. Ainsi, le topic demeurera lisible aussi longtemps que ZdS durera, même si le paste ferme ou change d'adresse. :)

GuilOooo

Pas faux. Au début, j'avais choisi d'être assez large pour permettre aux gens de poster où ils veulent, mais c'est vrai que vu la taille moyenne des codes, on peut se permettre de tout poster ici. Je vais éditer le 1er post.


A propos d'une norme Brainfuck, je ne crois pas que ça existe, le langage est assez simple pour qu'il y ait peu d'ambiguités (le coup de la mémoire initialisée à 0, toutes les sources que j'ai vu semblent être d'accord dessus).


Enfin, je me permet de poster proprement ma version OCaml ici :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
module Brainfuck =
struct
  exception Empty_code
  exception Missmatched_brackets
  type memory = Memory of int list * int * int list
  type machine = Machine of memory * string
  let empty = function code -> Machine(Memory([],0,[]), code)
  let rec run_machine = 
    let change_current_value m v =
      match m with Machine(Memory(l1, c, l2), code) ->
  Machine(Memory(l1, v, l2), code)
    in
    let next_instruction = function Machine(m, code) ->
      Machine(m, (String.sub code 1 ((String.length code) - 1)))
    in
    let move_left = function Machine(Memory(l1,c,l2), code) ->
      match l1 with
  [] -> Machine(Memory([], 0, c::l2), code)
      | h::t -> Machine(Memory(t, h, c::l2), code)
    in
    let move_right = function Machine(Memory(l1,c,l2), code) ->
      match l2 with
  [] -> Machine(Memory(c::l1, 0, []), code)
      | h::t -> Machine(Memory(c::l1, h, t), code)
    in
    let print_val_as_char =
      function Machine(Memory(l1,c,l2), _) as m ->
  let ch = try (Char.chr c) with _ -> '#' in
  print_char ch ; m
    in
    let print_val_as_int = 
      function Machine(Memory(l1,c,l2), _) as m ->
  print_int c ; m
    in
    let rec loop = 
      let rec get_rbrack s i =
  let rb_index = 
    try (String.index_from s i ']') 
    with Not_found -> raise Missmatched_brackets
  in
  let lb_index = 
    try (String.index_from s i '[') 
    with Not_found -> rb_index + 1
  in
  if lb_index < rb_index then
    get_rbrack s (rb_index + 1)
  else
    rb_index
      in
      function Machine(Memory(l1,c,l2), code) ->
  let rbrack = (get_rbrack code 1) in
  let new_code = 
    if c = 0 then 
      String.sub code (rbrack + 1) ((String.length code) - rbrack - 1)
    else 
      (String.sub code 1 (rbrack - 1))^code
  in
  Machine(Memory(l1,c,l2), new_code)
    in
    function 
    | Machine(Memory(l1,c,l2), code) as m ->
      if (String.length code) > 0 then
  try run_machine
        (match code.[0] with
      '+' -> change_current_value (next_instruction m) (c + 1)
        | '-' -> change_current_value (next_instruction m) (c - 1)
        | '<' -> move_left (next_instruction m)
        | '>' -> move_right (next_instruction m)
        | ',' -> change_current_value (next_instruction m) (Char.code((input_char stdin)))
        | '.' -> print_val_as_char (next_instruction m)
        | ';' -> change_current_value (next_instruction m) (read_int ())
        | '!' -> print_val_as_int (next_instruction m)
        | '[' -> loop m
        | ']' -> raise Missmatched_brackets
        | _ -> next_instruction m
        )
  with Empty_code -> m
      else
  raise Empty_code
end;;

let _ =
  let code = 
    "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>."
  in
  Brainfuck.run_machine (Brainfuck.empty code);;

Alex : même si ton code fait une certaine taille, je pense qu'il est mieux de le poster ici (quitte à mettre une balise secret) que de l'héberger sur un service externe. Ainsi, le topic demeurera lisible aussi longtemps que ZdS durera, même si le paste ferme ou change d'adresse. :)

GuilOooo

Pas faux. Au début, j'avais choisi d'être assez large pour permettre aux gens de poster où ils veulent, mais c'est vrai que vu la taille moyenne des codes, on peut se permettre de tout poster ici. Je vais éditer le 1er post.

Bibibye

Ok j'ai modifié mon post :-)

+0 -0

Je suis un grand fou.


Pris de mélancolie envers ma feu calculatrice TI-82 Stat, la superbe de toutes les autres, j'ai écrit un interpréteur Brainfuck en TI-BASIC.
Oui oui, en TI-BASIC.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
: DelVar YDelvar ZDelVar L2DelVar L3999->dim(L3
: 1->X
: Input ":",Str0
: For(I,1,length(Str0
: 1->P
: sub(Str0,I,1->Str1
: L3(X)+(Str1="+")-(Str1="-->L3(X
: X+(Str1=">")-(Str1="<->X
: If Str1=",
: Then
: Y+1->Y
: L1(Y->L3(X
: End
: If Str1=".
: Then
: Z+1->Z
: L3(X->L2(Z
: End
: If Str1="[" and 0=L3(X
: Then
: While P
: I+1->I
: sub(Str0,I,1
: P+(Ans="[")-(Ans="]->P
: End
: End
: If Str1="]" and L3(X
: Then
: While P
: I-1->I
: sub(Str0,I,1
: P+(Ans="]")-(Ans="[->P
: End
: End
: End
: L2

Je vous rassure, c'est normal qu'il manque des ) et des " à certains endroits, on peut faire foule de micro-optimisations en TI-BASIC.

D'ailleurs, si vous avez d'autres micro-optimisations, je suis preneur.
La moindre instruction d'économisée se ressent au niveau de la rapidité d'exécution.


Pour utiliser l'interpréteur, rien de plus simple.

Étant donné que les caractères en nombre, ça n'existe pas vraiment sur une calculatrice, à la place, la liste L1 fait office d'entrée standard.
Chaque élément de L1 sera lu dans l'ordre.

Même chose pour la sortie standard: ce sera la liste L2 à la place.
Notez que l'interpréteur tente d'afficher L2 automatiquement. Si vous n'avez écrit aucun nombre dans l'entrée standard, c'est normal qu'une erreur s'affiche comme quoi la liste est indéfinie.

Enfin, vous pouvez connaître le contenu de la mémoire à la fin de l'exécution.
La liste L3 fait office de tableau « infini » de nombres.

Je tiens à rappeler que ça reste très lent. C'est du TI-BASIC, namého.


Testé sur ma feu TI-82 Stat et fonctionnel.


EDIT: Grâce à Maëlan, l'interpréteur descend à $285$ octets dans la RAM de la calculatrice !1
C'est près du double de la plupart des implémentations en assembleur sur une vraie machine.


  1. On peut faire encore moins, mais l'interpréteur perdrait de l'ergonomie. 

+1 -0

On peut voir Brainfuck comme un jeu d'instructions d'un processeur. Et comme je n'ai plus de quoi programmer en VHDL sous la main (et que de toutes façons je ne sais plus faire), j'ai décidé de faire autrement.

J'ai décidé de simuler un processeur. Objet. En Java.

Eh bien croyez-le ou non, ça marche. C'est complètement inefficace, mais ça marche… J'arrive même à sortir la fractale !

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDEGFFEEEEDDDDDDCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAABBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDEEEFGIIGFFEEEDDDDDDDDCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAABBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDEEEEFFFI KHGGGHGEDDDDDDDDDCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAABBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDEEEEEFFGHIMTKLZOGFEEDDDDDDDDDCCCCCCCCCBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAABBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDEEEEEEFGGHHIKPPKIHGFFEEEDDDDDDDDDCCCCCCCCCCBBBBBBBBBBBBBBBBBB
AAAAAAAAAABBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDEEEEEEFFGHIJKS  X KHHGFEEEEEDDDDDDDDDCCCCCCCCCCBBBBBBBBBBBBBBBB
AAAAAAAAABBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDEEEEEEFFGQPUVOTY   ZQL[MHFEEEEEEEDDDDDDDCCCCCCCCCCCBBBBBBBBBBBBBB
AAAAAAAABBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDEEEEEFFFFFGGHJLZ         UKHGFFEEEEEEEEDDDDDCCCCCCCCCCCCBBBBBBBBBBBB
AAAAAAABBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDEEEEFFFFFFGGGGHIKP           KHHGGFFFFEEEEEEDDDDDCCCCCCCCCCCBBBBBBBBBBB
AAAAAAABBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDEEEEEFGGHIIHHHHHIIIJKMR        VMKJIHHHGFFFFFFGSGEDDDDCCCCCCCCCCCCBBBBBBBBB
AAAAAABBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDEEEEEEFFGHK   MKJIJO  N R  X      YUSR PLV LHHHGGHIOJGFEDDDCCCCCCCCCCCCBBBBBBBB
AAAAABBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDEEEEEEEEEFFFFGH O    TN S                       NKJKR LLQMNHEEDDDCCCCCCCCCCCCBBBBBBB
AAAAABBCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDEEEEEEEEEEEEFFFFFGHHIN                                 Q     UMWGEEEDDDCCCCCCCCCCCCBBBBBB
AAAABBCCCCCCCCCCCCCCCCCCCCCCCCCDDDDEEEEEEEEEEEEEEEFFFFFFGHIJKLOT                                     [JGFFEEEDDCCCCCCCCCCCCCBBBBB
AAAABCCCCCCCCCCCCCCCCCCCCCCDDDDEEEEEEEEEEEEEEEEFFFFFFGGHYV RQU                                     QMJHGGFEEEDDDCCCCCCCCCCCCCBBBB
AAABCCCCCCCCCCCCCCCCCDDDDDDDEEFJIHFFFFFFFFFFFFFFGGGGGGHIJN                                            JHHGFEEDDDDCCCCCCCCCCCCCBBB
AAABCCCCCCCCCCCDDDDDDDDDDEEEEFFHLKHHGGGGHHMJHGGGGGGHHHIKRR                                           UQ L HFEDDDDCCCCCCCCCCCCCCBB
AABCCCCCCCCDDDDDDDDDDDEEEEEEFFFHKQMRKNJIJLVS JJKIIIIIIJLR                                               YNHFEDDDDDCCCCCCCCCCCCCBB
AABCCCCCDDDDDDDDDDDDEEEEEEEFFGGHIJKOU  O O   PR LLJJJKL                                                OIHFFEDDDDDCCCCCCCCCCCCCCB
AACCCDDDDDDDDDDDDDEEEEEEEEEFGGGHIJMR              RMLMN                                                 NTFEEDDDDDDCCCCCCCCCCCCCB
AACCDDDDDDDDDDDDEEEEEEEEEFGGGHHKONSZ                QPR                                                NJGFEEDDDDDDCCCCCCCCCCCCCC
ABCDDDDDDDDDDDEEEEEFFFFFGIPJIIJKMQ                   VX                                                 HFFEEDDDDDDCCCCCCCCCCCCCC
ACDDDDDDDDDDEFFFFFFFGGGGHIKZOOPPS                                                                      HGFEEEDDDDDDCCCCCCCCCCCCCC
ADEEEEFFFGHIGGGGGGHHHHIJJLNY                                                                        TJHGFFEEEDDDDDDDCCCCCCCCCCCCC
A                                                                                                 PLJHGGFFEEEDDDDDDDCCCCCCCCCCCCC
ADEEEEFFFGHIGGGGGGHHHHIJJLNY                                                                        TJHGFFEEEDDDDDDDCCCCCCCCCCCCC
ACDDDDDDDDDDEFFFFFFFGGGGHIKZOOPPS                                                                      HGFEEEDDDDDDCCCCCCCCCCCCCC
ABCDDDDDDDDDDDEEEEEFFFFFGIPJIIJKMQ                   VX                                                 HFFEEDDDDDDCCCCCCCCCCCCCC
AACCDDDDDDDDDDDDEEEEEEEEEFGGGHHKONSZ                QPR                                                NJGFEEDDDDDDCCCCCCCCCCCCCC
AACCCDDDDDDDDDDDDDEEEEEEEEEFGGGHIJMR              RMLMN                                                 NTFEEDDDDDDCCCCCCCCCCCCCB
AABCCCCCDDDDDDDDDDDDEEEEEEEFFGGHIJKOU  O O   PR LLJJJKL                                                OIHFFEDDDDDCCCCCCCCCCCCCCB
AABCCCCCCCCDDDDDDDDDDDEEEEEEFFFHKQMRKNJIJLVS JJKIIIIIIJLR                                               YNHFEDDDDDCCCCCCCCCCCCCBB
AAABCCCCCCCCCCCDDDDDDDDDDEEEEFFHLKHHGGGGHHMJHGGGGGGHHHIKRR                                           UQ L HFEDDDDCCCCCCCCCCCCCCBB
AAABCCCCCCCCCCCCCCCCCDDDDDDDEEFJIHFFFFFFFFFFFFFFGGGGGGHIJN                                            JHHGFEEDDDDCCCCCCCCCCCCCBBB
AAAABCCCCCCCCCCCCCCCCCCCCCCDDDDEEEEEEEEEEEEEEEEFFFFFFGGHYV RQU                                     QMJHGGFEEEDDDCCCCCCCCCCCCCBBBB
AAAABBCCCCCCCCCCCCCCCCCCCCCCCCCDDDDEEEEEEEEEEEEEEEFFFFFFGHIJKLOT                                     [JGFFEEEDDCCCCCCCCCCCCCBBBBB
AAAAABBCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDEEEEEEEEEEEEFFFFFGHHIN                                 Q     UMWGEEEDDDCCCCCCCCCCCCBBBBBB
AAAAABBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDEEEEEEEEEFFFFGH O    TN S                       NKJKR LLQMNHEEDDDCCCCCCCCCCCCBBBBBBB
AAAAAABBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDEEEEEEFFGHK   MKJIJO  N R  X      YUSR PLV LHHHGGHIOJGFEDDDCCCCCCCCCCCCBBBBBBBB
AAAAAAABBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDEEEEEFGGHIIHHHHHIIIJKMR        VMKJIHHHGFFFFFFGSGEDDDDCCCCCCCCCCCCBBBBBBBBB
AAAAAAABBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDEEEEFFFFFFGGGGHIKP           KHHGGFFFFEEEEEEDDDDDCCCCCCCCCCCBBBBBBBBBBB
AAAAAAAABBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDEEEEEFFFFFGGHJLZ         UKHGFFEEEEEEEEDDDDDCCCCCCCCCCCCBBBBBBBBBBBB
AAAAAAAAABBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDEEEEEEFFGQPUVOTY   ZQL[MHFEEEEEEEDDDDDDDCCCCCCCCCCCBBBBBBBBBBBBBB
AAAAAAAAAABBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDEEEEEEFFGHIJKS  X KHHGFEEEEEDDDDDDDDDCCCCCCCCCCBBBBBBBBBBBBBBBB
AAAAAAAAAAABBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDEEEEEEFGGHHIKPPKIHGFFEEEDDDDDDDDDCCCCCCCCCCBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAABBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDEEEEEFFGHIMTKLZOGFEEDDDDDDDDDCCCCCCCCCBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAABBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDEEEEFFFI KHGGGHGEDDDDDDDDDCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAABBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDEEEFGIIGFFEEEDDDDDDDDCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBB


399396 ms

Bon OK, il lui faut quand même plus de 6 minutes 30… par contre, il ne prends que 15 Mo de RAM.

Comme du coup il y a beaucoup de classes (la plupart ne font à peu près rien), je vous ai mis le code ici : https://github.com/SpaceFox/brainfuck-vm/

À quoi sert ton truc ?

A rien. J'avais envie de m'amuser :D

Le programme fonctionne comme un processeur :

  • On crée un processeur, avec un jeu d'instructions défini (chacune d'entre elles est une classe)
  • On crée 2 mémoires (Brainfuck est une machine de Harvard)
  • On charge le programme dans la mémoire programme, qui est donc représenté par une suite d'instructions
  • On crée deux registres : le pointeur-mémoire et le pointeur-programme, tous deux initialisés à 0
  • On exécute l'instruction courante, puis on incrémente le pointeur-mémoire, jusqu'à arriver au bout de la mémoire-programme
  • Chaque instruction peut modifier l'état des registres ou des mémoires

Le programme est fonctionnel mais crade : programme en dur dans la classe CLI, aucun commentaire (cela dit, ils ne devraient pas être très importants pour commencer, il faut juste savoir qu'on part de la classe nommée CLI.java), classes limitées aux concepts réellement utilisés, etc.

J'avais une version super-optimisée en Java aussi, que j'avais fait pour ce même topic sur le SdZ. Si je la retrouve, je vous la poste et on verra la différence de perfs :D

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte