DEV Community

Calin Baenen
Calin Baenen

Posted on

How to make a simple Brainf**k interpreter using ParseJS. [CW: Light 'profanity'.]

Hello. I'm Calin Baenen, and I'm going to teach you how to use the library I made, ParseJS, effectively for the reason it was made.

To follow along, I expect you already have basic knowledge of general programming, and at the very least; entry-level knowledge about JavaScript.
Knowing HTML (outside of the <script>) tag isn't required, though, that knowledge could help your interpreter look prettier.

What is Brainfuck?

[If you know what BF is, you can skip this section.]

Brainfuck is an esoteric programming language (esolang*) created by Urban MΓΌller designed to be minimalistic.

Here's a brief summary by Fireship to get you up to speed:

Getting started.

Okay. Now that we know what Brainfuck is, we can actually get to implementing it.

But, before we do any actual work on the BF interpreter, we must first set up a simple HTML page, so we actually have a way to interface with our project.
So, create an HTML file (.html) and call it whatever, and write the following:

<h1>Input Brainfuck Code:</h1>
<textarea style="width:35vw; height:25vh;" id="i"></textarea>
<button id="r">RUN!</button>
<h1>Output:</h1>
<textarea disabled="true"
    style="width:35vw; height:25vh;" id="o"></textarea>
Enter fullscreen mode Exit fullscreen mode

Adding ParseJS.

So, up to this point we've just created two boxes, one for input and another for output.
Now we actually need ParseJS. - There's two main recommended ways of integrating PJS into your project:

  • Downloading the src folder from ParseJS' GitHub repo.
  • Using the Content Delivery Network (CDN) URL to be served the file, without keeping ParseJS on your drive.

(The CDN URL is: https://cdn.jsdelivr.net/gh/CalinZBaenen/ParseJS@main/src/parse_string.js.)

Making the interpreter.

Now, if you've visited the repo and looked at the ReadMe, you'll have a rough idea of how to use this library.
If you haven't, you can make rough assumptions about how ParseJS works using context clues. - But to be nice, I'll leave in some helpful comments.

So, now that we have (know how to install*) PJS, we can now include it by prepending the following (adding the following to the beginning of the HTML*):

<script src="./path_to/parsejs_install/parse_string.js">
</script>
Enter fullscreen mode Exit fullscreen mode

Making the interpreter.

Now it's time to make the actual interpreter.
Make a new JavaScript file (.js) called bf_interpreter.js in the same directory as your project_name.html file.

Now, here's the code.
Things will be explained in comments within the code, so my "DEV voice" will be silent until the code ends:

// Creates a list of keywords for `parse_string`
// to look for.
const keywords = [
    Symbol.for('.'),
    Symbol.for(','),  // `Symbol.for(desc)` is similar to
    Symbol.for('+'),  // `Symbol(desc)`, except symbols
    Symbol.for('-'),  // generated by the `for` method
    Symbol.for('>'),  // aren't unique.
    Symbol.for('<'),  // I.e. Symbol('x') != Symbol('x'), but
    Symbol.for('['),  // Symbol.for('y') == Symbol.for('y').
    Symbol.for(']')
];

// Gets the input and output `textarea`s, and the run button.
const i = document.getElementById('i');
const o = document.getElementById('o');
const btn = document.getElementById('r');

function interpret_bf() {
    o.value = ""; // Clear the output textarea.
    // Extracts the keywords we defined above.
    const tokens = parse_string(i.value, keywords, false);

    const b = [0];  // The array of bytes.
    let p = 0;      // Pointer.
    for(const tok of tokens) {
        // Ensure the pointer is always at a valid position.
        while(p >= b.length) b.push(0);
        if(p < 0) p = 0;

        switch(tok) {
            case keywords[0]:   // Print.
                // Converts byte to character.
                o.value += String.fromCharCode( b[p] );
                break;

            case keywords[1]:   // Get char input.
                // Gets a string from `prompt`,
                // and makes sure the data is a valid
                // string.
                const c = ((
                    prompt("Enter a character.") ?? '\0'
                )[0] ?? '\0').charCodeAt(0);
                b[p] = c;
                break;

            case keywords[2]:   // Increment current byte.
                b[p]++;
                if(b[p] > 255) b[p] = 0;  // Byte overflow.
                break;

            case keywords[3]:   // Decrement current byte.
                b[p]--;
                if(b[p] < 0) b[p] = 255;  // Byte underflow.
                break;

            case keywords[4]:   // Move pointer right.
                p++; break;
            case keywords[5]:   // Move pointer left.
                p--; break;
        }
    }
}

btn.onclick = ()=>{ interpret_bf(); };
Enter fullscreen mode Exit fullscreen mode

The final step. . .

Now. - All we have to do is get this JS file into our HTML page and the job is (mostly) finished!

So, all we have to do is append the following to the end of our HTML:

<script src="./bf_interpreter.js">
</script>
Enter fullscreen mode Exit fullscreen mode

And over-all, that should leave you with an HTML document that looks roughly like this:

<!-- The `src` here could be the CDN URL. -->
<script src="./parse_string.js">
</script>

<h1>Input Brainfuck Code:</h1>
<textarea style="width:35vw; height:25vh;" id="i"></textarea>
<h1>Output:</h1>
<textarea disabled="true"
    style="width:35vw; height:25vh;" id="o"></textarea>

<script src="./bf_interpreter.js">
</script>
Enter fullscreen mode Exit fullscreen mode

When you load the page in your web-browser of choice, the page should look similar to the following screenshot:
Screenshot of the HTML project.

As a test program, try doing ,.. - It takes a character from the user then immediately prints it.
So if the interpreter was made correctly, running this and entering E should make E display in the output.

But wait... aren't you forgetting something?

Yes. - Yes I am.
I purposefully didn't add [ and ] (loop operators) because:

  1. I was too lazy.
  2. It's a challenge to implement loops without making the code way less beginner friendly.
  3. It gives you a challenge that you can try for yourself!

Conclusion.

Well, this wraps up this tutorial.
Hopefully this taught you about, and inspired you to use ParseJS!

As always...

Thanks for reading!
Cheers!

Top comments (4)

Collapse
 
foxy4096 profile image
Foxy4096

Well it really fucked my brain

πŸ§ πŸ–•

Collapse
 
calinzbaenen profile image
Calin Baenen

How did you do that triangle thing?

Collapse
 
foxy4096 profile image
Foxy4096

Oh I just found it on here dev.to/p/editor_guide
Code

{% details summary %} content {% enddetails %}
{% spoiler summary %} content {% endspoiler %}
{% collapsible summary %} content {% endcollapsible %}

Thread Thread
 
calinzbaenen profile image
Calin Baenen

Ah. I see.