用 Google 表格做個(gè)虛擬機(jī)
時(shí)間:2023-06-28 02:30:01 | 來(lái)源:網(wǎng)站運(yùn)營(yíng)
時(shí)間:2023-06-28 02:30:01 來(lái)源:網(wǎng)站運(yùn)營(yíng)
用 Google 表格做個(gè)虛擬機(jī):
簡(jiǎn)評(píng):誰(shuí)能有原作者會(huì)玩?活脫脫把一個(gè)表格處理工具當(dāng)作像微處理器來(lái)運(yùn)行,感覺以后「微型計(jì)算機(jī)原理」都可以用這個(gè)做實(shí)驗(yàn)了。
我最近注意到,Google Docs 有一個(gè)叫 Apps Script 的全功能腳本系統(tǒng),它可以讓你使用JavaScript 做一些非常有用的事情:
- 運(yùn)行代碼來(lái)響應(yīng)文檔打開事件或單元格更改事件;
- 為公式制作自定義 Google Sheets 電子表格函數(shù);
- 使用像 Google 這樣的服務(wù)來(lái)翻譯文本或電子郵件;
- 使用自定義功能將新菜單項(xiàng)添加到 Google Docs 的界面中。
但,我用它做卻做了 (? ??_??)? 一些奇奇怪怪的事,看啊,Google Sheets 虛擬機(jī)竟然在生成斐波納契數(shù)列了!
運(yùn)行原理
虛擬機(jī)有 100 個(gè)單元的內(nèi)存區(qū)域,索引為 0-99,每個(gè)單元格都可以包含一個(gè)指令或一個(gè)整數(shù)值。
還有一個(gè)堆棧,它從內(nèi)存區(qū)域的底部開始,然后向上增長(zhǎng)。
下圖是當(dāng)這個(gè)虛擬機(jī)為空的時(shí)候的樣子:
注意一下事項(xiàng):
- RA,RB,RC 和 RD 是通用寄存器
- RI 是指令指針,它指向要在內(nèi)存區(qū)域執(zhí)行的下一條指令,該指示燈亮起綠色。
- RS 是堆棧指針,它指向堆棧頂部的存儲(chǔ)單元,這亮起藍(lán)色
- Output 顯示程序的輸出
- Error 顯示在解析或執(zhí)行指令時(shí)遇到的任何錯(cuò)誤
- Memory 是 100 個(gè)存儲(chǔ)單元的區(qū)域
要運(yùn)行指令,后臺(tái)的 Apps Script 會(huì)檢查
RI 的值,查看接下來(lái)要執(zhí)行的指令,它讀取
RI 指向的指令并解析它。
指令在內(nèi)存和寄存器之間操作數(shù)據(jù),操作堆?;驁?zhí)行條件判斷。
指令執(zhí)行完畢后,
RI 的值增加,指向存儲(chǔ)器中的下一個(gè)單元。
用法
下面是一個(gè)名為 Computer 的自定義菜單,其中包含一些用于控制虛擬機(jī)的命令:
- Run 將運(yùn)行當(dāng)前程序,直到它結(jié)束或遇到錯(cuò)誤
- Step 運(yùn)行一條指令,然后暫停
- Reset 清除所有寄存器和輸出字段,這使程序可以再次運(yùn)行
- Load Factorial Program 從另一個(gè) Sheet 中加載 factorial 示例
- Load Fibonacci Program 從另一個(gè) Sheet 中加載 fibonacci 示例
指令
有一些已經(jīng)實(shí)現(xiàn)的指令:
General
數(shù)學(xué)運(yùn)算
- add dst src
- sub dst src
- mul dst src
堆棧操作
跳轉(zhuǎn)和條件
- jmp target
- jl cmp1 cmp2 target
函數(shù)
其他
尋址模式
上述指令中的操作數(shù)可以采取幾種形式
Immediates (立即數(shù))是嵌入到指令中的數(shù)值,例如:7 和 123。 將值 7 復(fù)制到寄存器 ra中:
mov ra 7
Registers 寄存器尋址,例如:ra,rb,rc。將值從 rc 復(fù)制到 rb 中:
mov rb rc
Memory 指存儲(chǔ)區(qū)域的單元格內(nèi)的值,例如:$0,$10,$99。將 ra 中的值復(fù)制到第一個(gè)存儲(chǔ)單元中:
mov $0 ra
將值從最后一個(gè)存儲(chǔ)單元復(fù)制到 rd:
mov rd $99
Indirect 是指內(nèi)存單元指向的值,例如:@15,@50。因此,如果存儲(chǔ)器單元 10 包含值 20,并且存儲(chǔ)器單元 20 包含值 30,則可以將值 30 像這樣地復(fù)制:
mov ra @10
它查看存儲(chǔ)器單元 10 找到值 20 ,然后,它查看存儲(chǔ)器單元 20 找到值 30,并將該值復(fù)制到ra 中。
遞歸
還可以使用堆棧、 call 和 ret 指令進(jìn)行遞歸調(diào)用。這是一個(gè)使用遞歸來(lái)生成 5 的階乘的例子:
從
jl ra 2 50 中開始的代碼是一個(gè)函數(shù),它接受 ra 中輸入值,并將返回結(jié)果存入 rd,它會(huì)遞歸地調(diào)用它來(lái)計(jì)算 ra 中值的階乘。
一起玩啊
如果你也想玩
https://docs.google.com/spreadsheets/d/1385V2Mu2yZOMSJcSz9JrV6r8X0_JGzHZZRdPhaAdwWY/edit?usp=sharing使用工具和腳本編輯器,就可以看到應(yīng)用程序腳本代碼
原文:Google Sheets Virtual Machine
擴(kuò)展閱讀:編譯器和解釋器之間有什么區(qū)別 - 本站專欄
歡迎關(guān)注:
- 本站專欄「極光日?qǐng)?bào)」,每天為 Makers 導(dǎo)讀三篇優(yōu)質(zhì)英文文章。
- 極光 Github 項(xiàng)目:「Aurora UI」,一個(gè)通用 IM 聊天 UI 組件。