Learn Rust by building a Brainfuck interpreter, part 3: how you should not build a parser

Introduction

This is the third post in a series that builds a Brainfuck interpreter in Rust.

  • In the first post, we created the first building blocks for our Brainfuck interpreter in Rust: a data structure for the tape, and a data type for the instructions. The instructions are based on Rust's enums, which allow to build powerful algebraic data types.
  • In the second post, we built an execution engine that can execute a Brainfuck program which is represented by an abstract syntax tree in the context of a tape. We used the Read and Write traits to make our execution function generic, such that we could not only read from standard input and write to standard output, but also, e.g., read from byte slices and write to a vector of bytes. This makes unit testing easy.

Currently, we can only execute programs which are given as abstract syntax trees in Rust data structures, such as this one:

// read two byte values and write their sum
vec![
    Read, Right, Read,
    Loop(vec![Dec, Left, Inc, Right]),
    Left, Write
];

This corresponds to ,>,[-<+>]<. in Brainfuck source code.

In the current post, we will find ways to transform the latter into the former, i.e., to parse Brainfuck source code and generate an abstract syntax tree.

Please note: I intentionally did this without using libraries because I wanted to build a simple parser from scratch. Since I learned a lot this way, I found it appropriate to write a blog post about the process. However, building a parser with the help of libraries that are designed for this purpose is much easier and less error-prone. In a future post in this series, we will implement a better parser using the Rust crate nom.

Read more…

Learn Rust by building a Brainfuck interpreter, part 2: the execution engine

Introduction

In the last post, we created the first building blocks for our Brainfuck interpreter in Rust:

  • A data structure for the tape, which supports four operations:

    • left and right move the data pointer,
    • get returns the u8 value that is stored in the current cell,
    • set assigns a new u8 value to the current cell.
  • A data type for the instructions. It is based on Rust's enums, which are much more powerful than enums in C or C++ because they allow to build algebraic data types:

    #[derive(Debug)]
    enum Instruction {
        Inc,                    // +
        Dec,                    // -
        Left,                   // <
        Right,                  // >
        Read,                   // ,
        Write,                  // .
        Loop(Vec<Instruction>)  // [...]
    }
    

    This definition allows to represent a Brainfuck program as an abstract syntax tree, which makes program execution simple. However, it requires a bit more work when parsing the program, as we will see in a later post in this series.

In this post, we will implement the next part of the interpreter: an execution engine which applies instructions to the state of the tape, and performs input and output.

Read more…

Learn Rust by building a Brainfuck interpreter, part 1: implement the tape and model the program as an abstract syntax tree

Motivation

For many years, C++ used to be my favourite language for performance-critical applications. I find Python much more convenient for many use cases, but I have always enjoyed employing zero-cost abstractions and writing generic code that can be compiled to optimal assembly.

However, C++ has a number of downsides, such as

  • problems that arise from undefined bahaviour in the code,1
  • all the baggage it carries due to its backwards compatibility with almost all C++ code and much of the C code that has ever been written. A consequence is that C++ is more cumbersome and error-prone to use than more modern languages, and that developers are less productive than they could be.

Rust tries to address these issues and enable excellent performance at the same time, so I decided that I should give it a try a few years ago. I started playing around with it for Advent of Code problems, enjoyed it a lot, and wondered what practice project I could try next.

Read more…

How to set up a local Kubernetes cluster and deploy a self-made microservice in less than 10 minutes

Nowadays, many server applications are not installed and run directly on physical hosts or virtual machines any more. Instead, application code is often built into container images, and run in so-called pods in a Kubernetes cluster. Kubernetes provides a standardized way to orchestrate applications and works the same way no matter where the cluster is running.

Kubernetes clusters are often hosted and managed by cloud providers. They can also be deployed on-premise though, and either be created and managed by a service provider, or with tools like Kubespray. Most clusters are long-lived, and consist of multiple nodes for redundancy.

However, sometimes a cluster that can be created and discarded quickly and easily on a single computer can be very useful:

  • A developer might want to create a cluster on their development machine for playing around with Kubernetes, exploring the newest tools, or testing their newly developed code and Kubernetes resources. If they used a cluster that is shared with others or even with production workloads instead, they might get into the way of others, or worse, break things that should better not break.
  • Another use case is automated testing of application deployments in Kubernetes, or testing of applications that interact with Kubernetes resources themselves. This works best in a dedicated cluster that is set up in a clean state just for this purpose, and thrown away after the tests.

Read more…

Getting rid of waste: manipulating calendars with Python and the ics library

In the city where I live, four different kinds of waste are collected regularly:

  • paper,
  • organic waste,
  • the "yellow bag" which is for all sorts of packaging, and
  • residual waste, which contains all the rest (except batteries, dangerous chemicals and a couple of other things, which people have to bring to collection facilities themselves).

At first sight, the days on which I have to take out the different bins and bags seem easy enough to remember: usually, everything is collected on the same day of the week. However, there are different schedules for the different kinds of waste (biweekly or every four weeks in my part of the city). Moreover, in weeks with bank holidays, the collection is often shifted to another weekday.

Fortunately, the city council provides iCalendar files (*.ical) with all waste collection dates for the current year at its website. The downloaded file can easily be imported into any calendar application. I found that the structure of the events in the file could be made more convenient though.

Read more…

New blog

Today I am starting a new blog. 🙂

I used to have a Wordpress blog at https://freininghaus.wordpress.com/. I started it when I got involved more and more with KDE and especially its file manager Dolphin.

When I stopped working on KDE because of changes in my personal life, one of the main reasons for writing blog posts regularly was gone. So I quit blogging.

I have missed writing in public though, and I have accumulated quite a few posts in various stages of completion during the past few years. And I have ideas for even more!

However, I could never motivate myself to revive my old blog, among other things because static site generators look much more attractive than platforms like Wordpress to me now. Therefore, I have finally decided to start something new. After looking at a few of the many options available, I chose Nikola, mostly because of its native suppot for Jupyter notebooks, and because I felt that I can get a result that I am happy with without investing too much effort.

I will write about my adventures in software development and other topics that I care about. I hope that this will be fun and will also help myself to structure my thoughts better and preserve them for my future self. If that turns out to be interesting for a wider audience, then this is an appreciated side effect, but not the main goal.

If you want to be updated about future posts, feel free to subscibe to the RSS feed or follow me on Twitter.