私たちは難解な言語の通訳を書いています

私は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 < maxCodeSize
char code[maxCodeSize]; //


インタープリターはすべてのコードを一度に読み取ります。 1つの文字配列では、このためにreadCode()関数を使用します。 空でないテキストを読み取った後、m_realCodeSizeにはコード内の正確な文字数が含まれます(コメントを除く)。読み取り中にコメントは破棄されます。

int main(int argc、char ** argv)
{
ようこそ();
resetRegisters();
readCode(“ test.bf”);
ループ(0、realCodeSize-1、regSize、reg);
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を返します。 構文エラーはありません。

2番目の関数は実際に関数を実行し、戻り値はretValに書き込まれます。retValは、関数が呼び出されたレジスタに割り当てられます。 戻り値は、終了後の関数スタックの最初のレジスタと見なされます。

whileループといえば、一般的な場合、ループは無期限に継続できます。 ただし、インタープリターのフリーズの問題に遭遇しないように、最大​​サイクル数を担当する変数を導入します。

const unsigned long maxLoopCycles = 999999;

まず、後方互換性を実装します。 インタープリターが今のところBrainfuckコードのみを実行できるようにします。
機能が必要になります。

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

unsigned long findLoopEnd( const unsigned long from )


最初の関数の2番目と3番目のパラメーターが必要です。 3番目のパラメーターは、操作するセルをナビゲートするために必要です。2番目は、各関数のレジスタが異なり、それらに対する操作が同じであるため、2番目が必要です。

2番目の関数は、名前に基づいて、サイクルの終わりを見つけます。 対応する文字は「[」です。

したがって、Brainfuck言語のインタープリターがあります。
インタープリターのソースコードとテストコードをレコードに添付しました

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

上記のコードに対して、私のインタープリターは、a + b = cの形式で入力された2つの数値の合計を出力します。

幸運...プログラミング!

PS
興味があれば、あとでどのように実装したかを後で説明します。

Source: https://habr.com/ru/post/J116004/


All Articles