Пишемо Лари свого езотеричного мови, Вільне ПЗ, Програмні керівництва, статті

За основу я взяв мова 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>

*

*