Главная » Хабрахабр » [Из песочницы] Пишем стэковую виртуальную машину на Rust’e

[Из песочницы] Пишем стэковую виртуальную машину на Rust’e

Уже несколько недель я занят разработкой своего языка программирования на Rust. Здравствуй, Хабр! Мне бы хотелось расказать о том с чем может столкнуться новичок в этом деле и о чем ему следует знать.

Так-как ein интерпретируется от и до, то его скорость исполнения оказалась не самой высокой и после того как я начал хоть что то понимать я решил начать писать свой интерпретатор который в конце концов тоже забросил. Все началось с форка ein, форкнул я его дабы изучить как строятся языки программирования.

Я прочел пару статей о VM и о том какие они бывают и решил написать простую стековую VM. Но отчаиваться еще рано!

На хабре есть отедльная статья про это, но что бы не гонять по ссылкам изложу вкратце смысл этой вещицы.

Стековая VM выполняет все операции над данными, которые хранятся в виде стека, каждая операция извлекает нужное количество ей данных для операции и после выполнения ее может "отправить" в стек новое число.

Для начала необходимо создать новый проект с помощью cargo:

cargo new habr_vm

Сперва нам необходимо создать несколько базовых операций для нашей VM:

enum Opcode { Push(i32), Add, AddAssign(i32), Sub, SubAssign(i32),
}

Это наши базовые операции, команда Push будет добавлять в стек новое число, Add и Sub будут брать из стека два числа и выполнять с ними действия(сложение и вычитание соответственно), думаю о AddAssign и SubAssign объяснять не надо.

Cледующая задача это создать саму виртуальную машину, для этого мы создадим не сложную структуру:

struct Vm { pub stack: Vec<i32>,
}

И имплементируем ее:

impl Vm //Здесь будет происходить все самое интересное pub fn run(&mut self,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) => { let mut value = self.pop(); value += n; self.stack.push(value); } Opcode::SubAssign(n) => { let mut value = self.pop(); value -= n; self.stack.push(value); } } } }
}

Дальше надо создать нашу "программу". Мы иплементировали нашу структуру, что дальше?

Вот как это должно выглядеть:

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

Раз так, то давайте уже запустим нашу программу! Все просто, не так ли?

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

Очень просто как по мне, таким образом вы можете добавить еще достаточно опкодов для нужной вам операции.

Думаю что я вполне понятно объяснил как это все написать на расте и как это работает.

Хочется добавить что вы с легкостью сможете написать свой ЯП благодаря подобному VM, вам по сути остается написать только парсер, лексер и "компилятор", а если вам охото посмотреть на уже готовый проект то можете пройти по данной ссылке.

Весь код из статьи доступен в данном репозитории

Удачи Хабр!


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

Создание пакетов для Kubernetes с Helm: структура чарта и шаблонизация

Теперь подойдём к практике с другой стороны — с точки зрения создателя чартов (т.е. Про Helm и работу с ним «в общем» мы рассказали в прошлой статье. И хотя эта статья пришла из мира эксплуатации, она получилась больше похожей на ...

[Из песочницы] Экономим на RAID-контроллере, или как накормить Варю иопсами

В наш век облачных сервисов, AWS Lambda и прочих шаред хостингов абсолютно неосязаемых вычислительных ресурсов иногда хочется немножко своего. Кроме желания, иногда бывают и потребности вдумчиво покрутить тот или иной программный продукт с минимальными затратами на платформу. Найти какие-то излишки ...