We write the stack virtual machine on Rust'e

Hello, Habr! For several weeks I have been developing my own programming language in Rust. I would like to tell you about what a newcomer in this business may face and what he should know about.


Brief prehistory


It all started with fork ein , I forked it in order to learn how programming languages ​​are built. So, as ein is interpreted from and to, then its execution speed was not the highest, and after I started to understand at least something, I decided to start writing my own interpreter, which I eventually abandoned.


But it's too early to despair! I read a couple of articles about VMs and how they happen and decided to write a simple stackable VM.


What is a "stack virtual machine" and how does it work?


On Habré there is a detached article about it, but that would not drive through the links I will briefly outline the meaning of this thing.


A stack VM performs all operations on data that is stored as a stack, each operation retrieves the necessary amount of data for the operation, and after executing it can “send” a new number to the stack.


Getting started


First you need to create a new project using cargo:


cargo new habr_vm

First we need to create some basic operations for our VM:


enumOpcode {
      Push(i32),
      Add,
      AddAssign(i32),
      Sub,
      SubAssign(i32),
}

These are our basic operations, the Push command will add a new number to the stack, Add and Sub will take two numbers from the stack and perform actions with them (addition and subtraction, respectively), I don’t need to explain AddAssign and SubAssign.


The next task is to create the virtual machine itself, for this we will create a non-complex structure:


structVm {
    pub stack: Vec<i32>,
}

And implement it:


impl Vm {
    //Упрощаем себе жизнь тем что сокращаем писанинуpubfnpop(&mutself) -> i32 {
        self.stack.pop().unwrap()
    }
    //Здесь будет происходить все самое интересноеpubfnrun(&mutself,program: Vec<Opcode>) {
        for opcode in program { //Проверяем каждую команду в нашей программеmatch opcode {
                Opcode::Push(n) => {
                    //Просто добавляем число в наш стекself.stack.push(n);
                }
                Opcode::Add => {
                    // Берем два числа из стека и складываем их, добавляем в стек уже новое числоlet value = self.pop() + self.pop();
                    self.stack.push(value);
                }
                Opcode::Sub => {
                   // Тут то же самое что и с складыванием только наоборот let value = self.pop() - self.pop();
                    self.stack.push(value);
                }
                // Думаю следующие две операции объяснять не нужно
                Opcode::AddAssign(n) => {
                    letmut value = self.pop();
                    value += n;
                    self.stack.push(value);
                }
                Opcode::SubAssign(n) => {
                    letmut value = self.pop();
                    value -= n;
                    self.stack.push(value);
                }
            }
        }
    }
}

We and our structure, what's next? Next you need to create our "program".


Here’s how it should look:


let program = vec![
     Opcode::Push(2),//Добавляем 2 в наш стек
     Opcode::Push(4),// Добавляем 4 в наш стек
     Opcode::Sub,// Вычитаем 4 - 2
];

It's simple, isn't it? If so, then let's run our program!


letmut vm = Vm {stack: Vec::new()};
vm.run(program);
// Выводим все числа из стека, на данный момент это будет просто 2 for i in vm.stack() {
     println!("{}", i);
}
// Вывод2

It's very simple as for me, so you can add enough opcodes for the operation you need.


Conclusion


I think that I quite clearly explained how to write all this on a plant and how it works.


I would like to add that you can easily write your own YAP thanks to such a VM, all you have to do is write a parser, lexer and "compiler", and if you want to look at a ready-made project, you can follow this link .


All code from the article is available in this repository.


Good luck Habr!


Also popular now: