How to make a simple Brainf**k interpreter using ParseJS. [CW: Light 'profanity'.]
Tags: javascript, webdev, tutorial, watercooler
Published: 2021-12-23 14:19:26

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](https://en.wikipedia.org/wiki/Brainfuck) is an esoteric programming language (esolang\*) created by Urban Müller designed to be minimalistic.

Here's a brief summary by [Fireship](https://www.youtube.com/channel/UCsBjURrPoezykLs9EqgamOA) to get you up to speed:
{%youtube hdHjjBS4cs8%}

## 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:
```html
<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>
```

## 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](https://github.com/CalinZBaenen/ParseJS).
 - 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](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\*\):
```html
<script src="./path_to/parsejs_install/parse_string.js">
</script>
```

## 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:
```javascript
// 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(); };
```

## 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:
```html
<script src="./bf_interpreter.js">
</script>
```

And over-all, that should leave you with an HTML document that looks roughly like this:
```html
<!-- 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>
```
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.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1o4v3g3s9i97ra0lamam.png)

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...
<b><h1><center>Thanks for reading!<br/>Cheers!</center></h1></b>