成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

然并卵:BF 科普 & BF 解釋器的 JS 實(shí)現(xiàn)

HackerShell / 3679人閱讀

摘要:最近在上做練習(xí),某道題的內(nèi)容是實(shí)現(xiàn)一個(gè)簡(jiǎn)稱語(yǔ)言解釋器等等均可。這篇文章準(zhǔn)備聊聊相關(guān)的一些知識(shí)和實(shí)現(xiàn)的細(xì)節(jié)。誕生于上世紀(jì)年代,曾運(yùn)用于早期的,想詳細(xì)了解的童鞋可以瀏覽維基百科。例如,當(dāng)某個(gè)存儲(chǔ)單元的值為時(shí),其執(zhí)行指令的結(jié)果為。

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

“腦洞大開(kāi)”的語(yǔ)言 —— BF 簡(jiǎn)介

BrainFuck(后文以簡(jiǎn)寫B(tài)F指代),單是名字就很容易讓人腦洞大開(kāi),有種不可描述的“哲學(xué)”韻味。所以如果你忍不住 google 一下相關(guān)圖片的話,你會(huì)可能搜到類似下面的圖片:

畫面是不是已經(jīng)很生動(dòng)了?

BF 字面上的含義已經(jīng)暗示了這是一種不太直觀和容易閱讀的語(yǔ)言,當(dāng)然,在當(dāng)下也不會(huì)是一種通用語(yǔ)言。她屬于 Esolang(全稱 Esoteric programming language,直譯:深?yuàn)W的編程語(yǔ)言) 的范疇。

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

BF 在當(dāng)下有什么應(yīng)用場(chǎng)景呢?

我想,對(duì)一個(gè)吃瓜群眾來(lái)說(shuō),了解了它,對(duì)寫作 逼格腦力 的提升是很有用的。BF 具有極簡(jiǎn)主義(搞設(shè)計(jì)的童鞋的不妨了解下下)和功能齊全(圖靈完全)的特點(diǎn),旨在為用戶帶來(lái)困惑和挑戰(zhàn),豐富勞動(dòng)人民的業(yè)余生活。

8 種運(yùn)算符及其操作

BF 作為一種極簡(jiǎn)的計(jì)算機(jī)語(yǔ)言,僅有8種運(yùn)算符,分別為: < > + - , . [ ],其功能對(duì)照如下表所示:

指令 含義
< 指針減一(指針左移)
> 指針加一(指針右移)
+ 指針指向的字節(jié)的值加一(當(dāng)前單元的數(shù)值+1)
- 指針指向的字節(jié)的值減一(當(dāng)前單元的數(shù)值-1)
, 輸入內(nèi)容到指針指向的單元(輸入一個(gè)字符,將其ASCII碼保存到當(dāng)前指針?biāo)竼卧?/td>
. 將指針指向的存儲(chǔ)單元的內(nèi)容作為字符輸出(將ASCII碼輸出為字符)
[ 如果指針指向的存儲(chǔ)單元為零,向后跳轉(zhuǎn)到對(duì)應(yīng)的 ] 指令處
] 如果指針指向的存儲(chǔ)單元不為零,向前跳轉(zhuǎn)到對(duì)應(yīng)的 [ 指令處

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

對(duì) BF 比較有意思的比擬可以是這樣的:

如果把機(jī)器內(nèi)存看成是一個(gè)無(wú)限長(zhǎng)的“小火車”(類似于ArrayList的數(shù)據(jù)結(jié)構(gòu)),每個(gè)車廂(存儲(chǔ)單元)里面的貨物默認(rèn)都是數(shù)字 0,列車上僅有一個(gè)列車員(數(shù)據(jù)指針);

<> 相當(dāng)于列車員在車廂間進(jìn)行移動(dòng),只有當(dāng)列車員在某節(jié)車廂時(shí),才能對(duì)車廂的貨物進(jìn)行操作;

+- 相當(dāng)于列車員對(duì)當(dāng)前所在車廂的貨物進(jìn)行增減;

, 相當(dāng)于列車在裝貨,列車員將當(dāng)前所在車廂的貨物替換為貨運(yùn)站輸入的單批次貨物(一個(gè)字符的ASCII碼);

. 會(huì)將當(dāng)前車廂里的貨物名稱(單個(gè)字符)輸出來(lái);

[] 相當(dāng)于列車員在滿足條件的兩節(jié)車廂間來(lái)回移動(dòng);

這里要注意的是,數(shù)組的每個(gè)單元都是一個(gè)字節(jié)大??;- 命令允許溢出,它可以用 255 個(gè) + 命令來(lái)代替。例如,當(dāng)某個(gè)存儲(chǔ)單元的值為 255 時(shí),其執(zhí)行指令 + 的結(jié)果為 0。類似的, 0 執(zhí)行指令 - 的結(jié)果為 255.

與通用語(yǔ)言的類比

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

BrainFuck C
< --ptr;
> ++ptr;
+ ++*ptr;
- --*ptr;
, *ptr = getchar();
. putchar(*ptr);
[ while (*ptr) {
] }
BF 解釋器的 JS 函數(shù)實(shí)現(xiàn) 代碼奉上:
function brainLuck(code, input) {             // @1
  const inputChars = input.split("");         // @2

  const codes = code.split("");               // @3
  let codeIdx = 0;

  const arr = [];                             // @4
  let arrIdx = 0;
  let outputStr = "";                         // @5

  while (codeIdx < code.length) {             // @6
    const ops = codes[codeIdx];

    const handleLeftBracket = () => {         // @7
      if (~~arr[arrIdx] === 0) {
        let cnt = 1;

        while (cnt) {
          codeIdx++;
          if (codes[codeIdx] === "[") {
            cnt += 1;
          }
          if (codes[codeIdx] === "]") {
            cnt -= 1;
          }
        }
      }
    };

    const handleRightBracket = () => {        // @8
      if (~~arr[arrIdx] !== 0) {
        let cnt = 1;

        while (cnt) {
          codeIdx--;
          if (codes[codeIdx] === "]") {
            cnt += 1;
          }
          if (codes[codeIdx] === "[") {
            cnt -= 1;
          }
        }
      }
    };

    switch (ops) {                            // @9
      case ">":
        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
}
實(shí)現(xiàn)思路闡述(與代碼中注釋的序號(hào)對(duì)應(yīng)):

(1) 我們實(shí)現(xiàn)了一個(gè)函數(shù) brainLuck 用以模擬 BF 語(yǔ)言的解釋執(zhí)行,函數(shù) brainLuck 的用例如下:

const code = ",+[-.,+]";
const input = "Parksben" + String.fromCharCode(255);

const output = brainLuck(code, input);
console.log(output); // -> "Parksben"

(2) 將輸入的字符串切割為單個(gè)字符,暫存進(jìn)數(shù)組 inputChars;

(3) 將 BF 程序切割為單個(gè)操作符,方便遍歷每個(gè)指令,用 codeIdx 作為下標(biāo)進(jìn)行遍歷;

(4) 聲明一個(gè)數(shù)組 arr 用以模擬機(jī)器內(nèi)存,過(guò)程產(chǎn)生的數(shù)值存儲(chǔ)到此數(shù)組中;

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

(6) 遍歷 BF 運(yùn)算符,對(duì)不同指令進(jìn)行相應(yīng)的操作;

(7) 方法 handleLeftBracket,用以匹配到與當(dāng)前 [ 對(duì)應(yīng)的 ](通過(guò)操作下標(biāo) codeIdx);

(8) 方法 handleRightBracket,用以匹配到與當(dāng)前 ] 對(duì)應(yīng)的 [(通過(guò)操作下標(biāo) codeIdx);

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

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

(11) 程序輸出;

延伸閱讀

Brainfuck: a Programming Language or a Joke?

丹尼爾·克里斯托法尼的一些 BF 實(shí)例

深?yuàn)W的編程語(yǔ)言 - 維基百科

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/96890.html

相關(guān)文章

  • 關(guān)于修改DOM是異步還是同步問(wèn)題

    摘要:還請(qǐng)同學(xué)跟我多多探討關(guān)于修改是異步還是同步的問(wèn)題先來(lái)看代碼上述代碼的結(jié)果完全就是同步的表現(xiàn),如果是異步的話,毫無(wú)疑問(wèn),第一個(gè)下的每個(gè)內(nèi)容都應(yīng)該是,第二個(gè)也應(yīng)該是。 回 @bf 同學(xué) 本篇文章不是筆記也不是心得,而是關(guān)于一個(gè)問(wèn)題的討論,問(wèn)題最初出現(xiàn)于https://segmentfault.com/q/1010000005630545?_ea=903562 由于 @bf 同學(xué)不方便...

    qingshanli1988 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

HackerShell

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<