日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

然并卵:BF 科普 BF 解释器的 JS 实现

發布時間:2025/6/17 javascript 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 然并卵:BF 科普 BF 解释器的 JS 实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近在 Codewars上做練習,某道題的內容是實現一個 brainFuck(簡稱BF語言) 解釋器(c/python/js等等均可)。動手實踐的過程還是很有趣的,中間也遇到了各種各樣的問題,最終通過測試,代碼也比較接近目前的 JS 高分 solution。這篇文章準備聊聊相關的一些知識和實現的細節。

“腦洞大開”的語言 —— BF 簡介

BrainFuck(后文以簡寫BF指代),單是名字就很容易讓人腦洞大開,有種不可描述的“哲學”韻味。所以如果你忍不住 google 一下相關圖片的話,你會可能搜到類似下面的圖片:

畫面是不是已經很生動了?

BF 字面上的含義已經暗示了這是一種不太直觀和容易閱讀的語言,當然,在當下也不會是一種通用語言。她屬于 Esolang(全稱 Esoteric programming language,直譯:深奧的編程語言) 的范疇。

BF誕生于上世紀30年代,曾運用于早期的 PC(Amiga),想詳細了解的童鞋可以瀏覽 維基百科。

BF 在當下有什么應用場景呢?

我想,對一個吃瓜群眾來說,了解了它,對寫作 逼格腦力 的提升是很有用的。BF 具有極簡主義(搞設計的童鞋的不妨了解下下)和功能齊全(圖靈完全)的特點,旨在為用戶帶來困惑和挑戰,豐富勞動人民的業余生活。

8 種運算符及其操作

BF 作為一種極簡的計算機語言,僅有8種運算符,分別為: < > + - , . [ ],其功能對照如下表所示:

指令含義
<指針減一(指針左移)
>指針加一(指針右移)
+指針指向的字節的值加一(當前單元的數值+1)
-指針指向的字節的值減一(當前單元的數值-1)
,輸入內容到指針指向的單元(輸入一個字符,將其ASCII碼保存到當前指針所指單元)
.將指針指向的存儲單元的內容作為字符輸出(將ASCII碼輸出為字符)
[如果指針指向的存儲單元為零,向后跳轉到對應的 ] 指令處
]如果指針指向的存儲單元不為零,向前跳轉到對應的 [ 指令處

BF基于一個簡單的機器模型,除了八個指令,這個機器還包括:一個以字節為單位、被初始化為零的數組、一個指向該數組的指針(初始時指向數組的第一個字節)、以及用于輸入輸出的兩個字節流。

對 BF 比較有意思的比擬可以是這樣的:

  • 如果把機器內存看成是一個無限長的“小火車”(類似于Array或List的數據結構),每個車廂(存儲單元)里面的貨物默認都是數字 0,列車上僅有一個列車員(數據指針);
  • <> 相當于列車員在車廂間進行移動,只有當列車員在某節車廂時,才能對車廂的貨物進行操作;
  • +- 相當于列車員對當前所在車廂的貨物進行增減;
  • , 相當于列車在裝貨,列車員將當前所在車廂的貨物替換為貨運站輸入的單批次貨物(一個字符的ASCII碼);
  • . 會將當前車廂里的貨物名稱(單個字符)輸出來;
  • [] 相當于列車員在滿足條件的兩節車廂間來回移動;
  • 這里要注意的是,數組的每個單元都是一個字節大小;- 命令允許溢出,它可以用 255 個 + 命令來代替。例如,當某個存儲單元的值為 255 時,其執行指令 + 的結果為 0。類似的, 0 執行指令 - 的結果為 255.

    與通用語言的類比

    據此,BF的運算符與通用語言的類比如下(以C語言為例):

    BrainFuckC
    <--ptr;
    >++ptr;
    +++*ptr;
    ---*ptr;
    ,*ptr = getchar();
    .putchar(*ptr);
    [while (*ptr) {
    ]}

    BF 解釋器的 JS 函數實現

    代碼奉上:

    function brainLuck(code, input) { // @1const inputChars = input.split(''); // @2const codes = code.split(''); // @3let codeIdx = 0;const arr = []; // @4let arrIdx = 0;let outputStr = ''; // @5while (codeIdx < code.length) { // @6const ops = codes[codeIdx];const handleLeftBracket = () => { // @7if (~~arr[arrIdx] === 0) {let cnt = 1;while (cnt) {codeIdx++;if (codes[codeIdx] === '[') {cnt += 1;}if (codes[codeIdx] === ']') {cnt -= 1;}}}};const handleRightBracket = () => { // @8if (~~arr[arrIdx] !== 0) {let cnt = 1;while (cnt) {codeIdx--;if (codes[codeIdx] === ']') {cnt += 1;}if (codes[codeIdx] === '[') {cnt -= 1;}}}};switch (ops) { // @9case '>':arrIdx += 1;break;case '<':arrIdx -= 1;break;case '+':arr[arrIdx] = (~~arr[arrIdx] + 1) % 256;break;case '-':arr[arrIdx] = (~~arr[arrIdx] || 256) - 1;break;case ',':const iptChar = inputChars.shift();arr[arrIdx] = iptChar ? iptChar.charCodeAt(0) : arr[arrIdx];break;case '.':outputStr += String.fromCharCode(arr[arrIdx]);break;case '[':handleLeftBracket();break;case ']':handleRightBracket();break;}codeIdx++; // @10}return outputStr; // @11 }

    實現思路闡述(與代碼中注釋的序號對應):

    (1) 我們實現了一個函數 brainLuck 用以模擬 BF 語言的解釋執行,函數 brainLuck 的用例如下:

    const code = ',+[-.,+]'; const input = 'Parksben' + String.fromCharCode(255);const output = brainLuck(code, input); console.log(output); // -> 'Parksben'

    (2) 將輸入的字符串切割為單個字符,暫存進數組 inputChars;

    (3) 將 BF 程序切割為單個操作符,方便遍歷每個指令,用 codeIdx 作為下標進行遍歷;

    (4) 聲明一個數組 arr 用以模擬機器內存,過程產生的數值存儲到此數組中;

    (5) 用字符串 outputStr 存儲程序的輸出;

    (6) 遍歷 BF 運算符,對不同指令進行相應的操作;

    (7) 方法 handleLeftBracket,用以匹配到與當前 [ 對應的 ](通過操作下標 codeIdx);

    (8) 方法 handleRightBracket,用以匹配到與當前 ] 對應的 [(通過操作下標 codeIdx);

    (9) 用以處理不同指令的 switch 語句;

    (10) codeIdx 加一,以向前遍歷 codes;

    (11) 程序輸出;

    延伸閱讀

    Brainfuck: a Programming Language or a Joke?

    丹尼爾·克里斯托法尼的一些 BF 實例

    深奧的編程語言 - 維基百科

    總結

    以上是生活随笔為你收集整理的然并卵:BF 科普 BF 解释器的 JS 实现的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。