Okay okay, if you’re reading this, you probably know about my endeavour in language making that I had in my last blog post, and you probably hated me for that. But if you didn’t know, in my last blog post I wrote a terrible C adaptation in python. And for you to understand this blog post, that blog post is required reading.

Okay, now that you’ve caught yourself up on the latest and greatest language, it’s time to explain. The year was still 2024, I wasn’t sick now at least, but I was incredibly bored, frustrated even. Also it was like in the middle of the night so I couldn’t like… Take a walk. Then I realized something. “Why not take out my frustration trough a programming language!”. So yeah… I was all of a sudden thrown into another language-making endeavour. But were do I start?

Step 1. What should the language be about? I thought about this for quite the while, actually. But then I realized: screaming. That is the peak of frustration. Just imagine, something terrible happened and you need a way to take out your frustration.

UUUUUUUUuAUUUUuAUUAUUUAUUUAUEEEEOoAUAUAOAAUuEoEOoAAeAOOOeUUUUUUUeeUUUeAAeEOeEeUUUeOOOOOOeOOOOOOOOeAAUeAUUe

And now your frustration has suddenly stopped. You feel… Relieved. That, my friend, is what I want to create.

Step 2. Okay, but what language should I write it in? C. C is the greatest programming language of all time and I don’t want to literally torture myself by using a language like python or god forbid javascript. Eugh, I’m gonna puke…

Step 3. Okay, but… How? This is also a question I thought about for a while. But then I realized. Brainfuck. Brainfuck is a programming language that operates using like shifting and output of a data pointer. Any non-technical person might not understand what I’m talking about. And the truth is… I barely know either! Just know, this is a program that prints Hello, World! in the brainfuck programming language (split into 3 different lines for your viewing pleasure):

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

So what if I make a transalation of brainfuck but replace the little funny symbols (ex. >) by existential crisis symbols (ex. A), meaning that ex. >>+<+.. could become AAeEeUU. So… I’m going to be writing a brainfuck interpreter? Oh god no…

Let’s write a brainfuck interpreter! Unlike my first language, I’m going to be going more into the “Nit and gritty” with this one. Alright, the first thing we need is a file for evaluation, let’s call that one src/scream.c (we’ll fix headers later). Okay, what now? We need to create a function to hold the evaluation, let’s call it expr for evaluate EXPRession. Then we need to create a data pointer, that is just a fact, we just need it to be a char* (e.g a string) to be able to print it later:

void expr(char *command_pointer, char *input) {
    char *dp;
}

Okay, but what should dp be? Well it needs to hold data. But what should the size of that data be. The truth is; no idea. I chose 1001 but I think whatever is okay. We need the data to be empty, e.g {0}, then we need to take some of that data into dp (I chose 1/2):

#define DATASIZE 1001

void expr(...) {
    char *data[DATASIZE] = {0};
    char *dp;
    dp = &data[DATASIZE/2];
}

Also, as to not clutter the code, let’s create a header file called, say include/scream.h, and then compile with the -I./include option. Now:

#include <scream.h>

void expr(...) {
    char *data[DATASIZE] = {0};
    char *dp;
    dp = &data[DATASIZE/2];
}

Now, brackets exist, so let’s add a bracket_flag in. It should be an int since we’re going to iterate with it later. Also, add a command variable to control command. It should be a char since every command is a char (ex. '>'). Let’s update the expr function to include all these new additions:

void expr(...) {
    int bracket_flag;
    char command;
    char *data[DATASIZE] = {0};
    char *dp;
    dp = &data[DATASIZE/2];
}

Now, let’s iterate! We need to infinitely iterate using while (command = *command_pointer), then add all of the commands! I’m not going to go trough all of the commands, I’m just going to show you the while loop:

  while (command = *command_pointer++)
    switch (command) {
    case '>':
      dp++;
      break;
    case '<':
      dp--;
      break;
    case '+':
      (*dp)++;
      break;
    case '-':
      (*dp)--;
      break;
    case '.':
      printf("%c", *dp);
      break;
    case ',': 
      *dp = *input++;
      break;
    case '[':
      if (!*dp) { 
        for (bracket_flag=1; bracket_flag; command_pointer++)
          if (*command_pointer == '[')
            bracket_flag++;
          else if (*command_pointer == ']')
            bracket_flag--;
      } 
      break;
    case ']':
      if (*dp) {
        command_pointer -= 2;  
        for (bracket_flag=1; bracket_flag; command_pointer--)
          if (*command_pointer == ']')
            bracket_flag++;
          else if (*command_pointer == '[')
            bracket_flag--;
        command_pointer++;     
      }
      break;  
    }

Oh, and let’s add a printf("\n") at the end of the function for good measure:

void expr(...) {
    int bracket_flag;
    char command;
    char *data[DATASIZE] = {0};
    char *dp;
    dp = &data[DATASIZE/2];
    while(...) {...}
    printf("\n");
}

Oh, and here’s the part where I replace all of the brainfuck instructions with scream instructions. The list below shows the instruction and the thing it was replaced with:

  • > => A
  • < => E
  • + => U
  • - => O
  • , => a
  • . => e
  • [ => u
  • ] => o

Then, let’s just add a main file to strap all of this together! But before we do that, we need to add a function prototype to include/scream.h:

#include <stdio.h>

#define DATASIZE 1001

void expr(char *command_pointer, char *input);

Now, let’s add a main file in src/main.c:

#include <stdio.h>
#include <scream.h>

#define BUF_LEN 65536

int main(int argc, char **argv) {
    if (argc <= 1) {
        printf("USAGE: scream <file>\n");
        return 1;
    }
    FILE *file_ptr;
    char buf[BUF_LEN];

    file_ptr = fopen(argv[1], "r");

    if (NULL == file_ptr) {
        printf("File can't be opened \n");
    }

    while (fgets(buf, BUF_LEN, file_ptr) != NULL) {}
	
	char *input = "";
	expr(buf, input);
	return 0;
}

Just some bootstrapping, nothing special.

Step 4. … Profit? No, not quite yet. In order to completely sell the language to people, we need some examples. And before you ask, NO. I will never write examples for this language. What I can do is take brainfuck examples from the internet. I use the “Neovim” text editor, which uses “Vim Script” as it’s scripting language, so I simply wrote a quick vim script to find and replace brainfuck instructions with screamlang instructions. It looks like this:

%s/>/A/g
%s/</E/g
%s/+/U/g
%s/-/O/g
%s/\./e/g
%s/,/a/g
%s/\[/u/g
%s/\]/o/g
%s/\n//g
%s/ //g

And magically we have a Hello World program in screamlang:

UUUUUUUUuAUUUUuAUUAUUUAUUUAUEEEEOoAUAUAOAAUuEoEOoAAeAOOOeUUUUUUUeeUUUeAAeEOeEeUUUeOOOOOOeOOOOOOOOeAAUeAUUe

After a quick Makefile my interpreter was good to go! You can check it out in the archives, or on github. And with that, I’d like to present to you, the last step of this language endeavour:

Step 5. Profit.