Пишемо інтерпретатор для свого езотеричного мови

За основу я взяв мову Brainfuck, він настільки малий, що можна трохи розширивши отримати практично новий і досить функціональна мова програмування. І при цьому не втратити родзинку вихідного мови – Моя мова буде все так само терзати мозок програміста, як і його батько!


Отже, Brainfuck. Коротенько, ідея така, є N регістрів / осередків. У програміста є доступ до них всім але переміщення по них робляться явним чином. Тобто з осередку 2 можна перейти до осередку 7 відразу, потрібно послідовно.


“Ключові слова” мови:



Додані “ключові слова”:

Так як всі безліч ключових слів складається з ANCII символів, маємо:

/ / Шукані ключові слова
const char bf_next = >;
const char bf_prev = <;
const char bf_incr = +;
const char bf_decr = -;
const char bf_prnt = .;
const char bf_read = ,;
const char bf_wBeg = [;
const char bf_wEnd = ];

/ / Додані ключові слова
const char bf_pNum = ! ;
const char bf_rNum = $;
const char bf_fBeg = {;
const char bf_fEnd = };
const char bf_fNme = %;
const char bf_comm= (;
const char bf_call = @;
const char bf_null = ^;

Без обмеження спільності візьмемо обмежена кількість осередків, скажімо 256 і в разі спроби перейти до неприпустимої осередку будемо переходити до самої першої осередку (якщо перехід вліво) або до самої останньої (Якщо перехід вправо).

Додамо:

const unsigned long regSize = 256; / / Кількість регістрів

long reg [regSize]; / / Самі регістри
long stck [regSize]; / / Стек, у кожної функції свій стек

void resetRegisters (); / / Функція для обнулення регістрів

void printRegistres (); / / Показати стан регістрів

Тепер, скажімо маємо test.bf, як вхідний файл, в якому знаходиться код на моїй мові або на рідній Brainfuck. Інтерпретатор повинен забезпечувати “зворотну сумісність”.

Знову ж таки, без обмеження спільності, можемо зберігати весь код в деякому обмеженому масиві. Тобто інтепретатор буде працювати з файлами обмеженого розміру, скажімо так:

const unsigned long maxCodeSize = 1024000; / * максимальний розмір вхідного файлу в символах * /
unsigned long realCodeSize; / / Розмір коду у файлі realCodeSize char code [maxCodeSize]; / / Сам код

Інтерпритатор читає весь код відразу. В один символьний масив, для цього будемо використовувати функцію readCode (). Після прочитання не порожнього тексту m_realCodeSize буде містити точну кількість символів в коді, без урахування коментарів, коментарі відкидаються під час читання.

int main( int argc, char** argv )
{
welcome();
resetRegisters();
readCode( “test.bf ” );
loop ( 0, realCodeSize – 1, regSize, reg );
return 0;
}

Далі визначимо пару функцій для циклу while і копіювання стека і власне виконання функції.

bool loop( unsigned long from,
unsigned long to,
unsigned long condRegIndx,
unsigned long currReg,
long* registers );

bool runFunction( unsigned long from,
unsigned int to,
unsigned int& retValue);

void copyRegistersTo( long* source, long* destination );

Перша буде виконувати цикл і поверне true якщо цикл виконаний без проблем, тобто немає синтаксичних помилок.

Друга власне виконуватиме функцію, а повертається значення запишеться в retVal, яке в свою чергу присвоєно регістру, на якому була викликана функція. Значенням будемо вважати перший регістр стека функції після її закінчення.

До речі, про цикл while, в загальному випадку цикл може тривати нескінченно. Але, щоб не зіткнутися з проблемою зависання інтерпретатора, введемо змінну відповідає за максимальну кількість циклів.

const unsigned long maxLoopCycles = 999999;

Реалізуємо спочатку зворотну сумісність. Нехай поки наш інтерпретатор зможе виконувати тільки код Brainfuck-а.
Нам знадобляться функції:

bool makeCommand( char command, long* registers, unsigned long currReg )

unsigned long findLoopEnd( const unsigned long from )

Другий і третій параметри першої функції обов’язкові. Третій параметр потрібний для того, щоб орієнтуватися з яким осередком працювати, другий потрібен тому що регістри кожної функції відрізняються, а операції над ними однакові.

Друга функція виходячи з назви знаходить кінець циклу, тобто символ соответствуюйщій [.

Таким чином маємо інтерпретатор для мови Brainfuck.
До запису прикріпиввихідний код, Мого інтерпретатора з тестовим кодом

$[+<->]<<$>!<>>++++[++++++++++<->]<+++.++++++++++++++++++<<<!>[<-<+>>]>>.<<<!

На код вище мій інтерпретатор виведе суму двох введених чисел у вигляді а + b = c.

Вдалого … програмування!

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*