Commit 4bf71d0d authored by morifuji.koudai's avatar morifuji.koudai

[add] 7/simpleAdd完成

parent 6b8db361
This diff is collapsed.
こんばんは。フェリーハッカソンがめっちゃたのしかったmorifujiです。
また時間が空いてしまったけど頑張ります :muscle:
[https://www.oreilly.co.jp/books/9784873117126/:embed:cite]
[記録用git](https://gitlab.com/morifuji/nand2tetris)
[vol.1](https://morimori-kochan.hatenablog.com/entry/2019/01/12/203225)
[vol.2](https://morimori-kochan.hatenablog.com/entry/2019/01/13/122457)
[vol.3](https://morimori-kochan.hatenablog.com/entry/2019/01/13/154122)
[vol.4](https://morimori-kochan.hatenablog.com/entry/2019/01/14/002915)
[vol.5](https://morimori-kochan.hatenablog.com/entry/2019/01/14/002915)
[vol.6](https://morimori-kochan.hatenablog.com/entry/2019/01/23/101650)
vol.7 **いまここ**
## 7章 バーチャルマシン
VM(バーチャルマシン)言語から機械語への変換作業を本章・次章で扱う。
### 理論
#### VM(バーチャルマシン)
抽象化されたコンピュータ。VMの実装を備えていれば、VMの実行が可能になる。すなはちVMはただのインターフェース(規約)でしかない
たとえば、Pascalなら**pコード**。Javaなら**バイトコード**
VMがある利点は下の2つ。
1. VMで記述するだけで複数のプラットフォームに同時に対応することができる
2. VMを通して多言語の相互利用が可能になる
3. モジュール性が高まる
#### スタックマシン
`オペランドとVM命令の結果をどう保存するか`がキモになる。そこで出てくるのがスタック。データ構造の一つ。
スタック=LIFOである。算術に便利。例えば以下のような算術の場合。
```
// d=(2-x)*(y+5)
// push ==> スタックに値を格納する
// pop ===> スタックから値を取り出す
push 2
push x
sub // 減算
push y
push 5
add // 加算
mult // 乗算
pop d
```
スタック構造だからこそ、前方から読み取っていけば計算ができることがわかる。キュー構造などではうまくいかない。
### 理論(PJ)
スタックベースのVMを実装する。16bitのデータ型を持ち整数・ブール値・ポインタとして使われる前提
### 実装
// This file is part of www.nand2tetris.org // This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems" // and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press. // by Nisan and Schocken, MIT Press.
// File name: projects/06/add/Add.asm // File name: projects/06/add/Add.asm
// Computes R0 = 2 + 3 (R0 refers to RAM[0]) // Computes R0 = 2 + 3 (R0 refers to RAM[0])
@2 @2
D=A D=A
@3 @3
D=D+A D=D+A
@0 @0
M=D M=D
@256
D=A
@SP
M=D
// push start constant,7
@7
D=A
@SP
A=M
M=D
// push end constant,7
// increment start
@SP
M=M+1
// increment end
// increment end
// push start constant,8
@8
D=A
@SP
A=M
M=D
// push end constant,8
// increment start
@SP
M=M+1
// increment end
// increment end
// decrement start
@SP
M=M-1
// decrement end
@SP
A=M
D=M
// 一つ目
// decrement start
@SP
M=M-1
// decrement end
@SP
A=M
M=M+D
// 計算
// increment start
@SP
M=M+1
// increment end
(END)
@END
0;JMP
import java.io.*
class CodeWriter(filePath: String) {
private var pw: PrintWriter? = null
private var fileDir: String? = null
init {
fileDir = filePath.split("/").subList(0, filePath.split("/").size - 1).joinToString("/")
// 出力
val fil = FileWriter(File(fileDir, filePath.split("/").last()))
pw = PrintWriter(BufferedWriter(fil))
pw!!.println("@256")
pw!!.println("D=A")
pw!!.println("@SP")
pw!!.println("M=D")
}
fun setFileName(fileName: String) {
// 一旦閉じて
pw!!.close()
// また再開
val fil = FileWriter(File(fileDir, fileName))
pw = PrintWriter(BufferedWriter(fil))
pw!!.println("@256")
pw!!.println("D=A")
pw!!.println("@SP")
pw!!.println("M=D")
}
/**
* 算術コードを書き込む
*/
fun writeArithmetic(command: String) {
when (command) {
"add" -> {
decrementPointer()
// 一つ目のスタック取得
pw!!.println("@SP")
pw!!.println("A=M")
pw!!.println("D=M")
pw!!.println("// 一つ目")
decrementPointer()
// 二つ目のスタック取得
pw!!.println("@SP")
pw!!.println("A=M")
pw!!.println("M=M+D")
pw!!.println("// 計算")
incrementPointer()
}
"sub" -> {
// 一つ目のスタック取得
pw!!.println("@SP")
pw!!.println("D=M")
decrementPointer()
// 二つ目のスタック取得
pw!!.println("@SP")
// 計算
pw!!.println("M=M+D")
}
"neg" -> {
}
"eq" -> {
}
"gt" -> {
}
"lt" -> {
}
"and" -> {
}
"or" -> {
}
"not" -> {
}
}
}
/**
* pushまたはpopコマンドを書き込む
*/
fun writePushPop(command: Parser.COMMAND_TYPE, segment: String, index: Int) {
if (command == Parser.COMMAND_TYPE.C_PUSH) {
if (segment == "constant") {
pw!!.println("// push start " + segment + "," + index.toString())
pw!!.println("@" + index.toString())
pw!!.println("D=A")
pw!!.println("@SP")
pw!!.println("A=M")
pw!!.println("M=D")
pw!!.println("// push end " + segment + "," + index.toString())
incrementPointer()
pw!!.println("// increment end")
return
}
throw Exception()
}
}
/**
* スタックを一つ動かす
*/
private fun incrementPointer() {
pw!!.println("// increment start")
pw!!.println("@SP")
pw!!.println("M=M+1")
pw!!.println("// increment end")
}
/**
* スタックを一つ戻す
*/
private fun decrementPointer() {
pw!!.println("// decrement start")
pw!!.println("@SP")
pw!!.println("M=M-1")
pw!!.println("// decrement end")
}
fun close() {
pw!!.println("(END)")
pw!!.println("@END")
pw!!.println("0;JMP")
pw!!.close()
}
}
\ No newline at end of file
import java.io.BufferedWriter
import java.io.FileWriter
import java.io.PrintWriter
fun main(args: Array<String>) {
val parser = Parser("/Users/civiluo-1/nand2tetris/projects/07/StackArithmetic/StackTest/StackTest.vm")
val codeWriter = CodeWriter("/Users/civiluo-1/nand2tetris/projects/07/StackArithmetic/StackTest/StackTest.asm")
while (parser.hasMoreCommands()) {
parser.advance()
if (parser.commandType() === Parser.COMMAND_TYPE.C_PUSH) {
codeWriter.writePushPop(Parser.COMMAND_TYPE.C_PUSH, parser.arg1(), Integer.parseInt(parser.arg2()))
} else if (parser.commandType() === Parser.COMMAND_TYPE.C_ARITHMETIC) {
codeWriter.writeArithmetic(parser.arg1())
} else {
throw Exception()
}
}
codeWriter.close()
}
//
//val parser = Parser("/Users/civiluo-1/nand2tetris/projects/06/rect/Rect.asm")
//
//// 出力
//val fil = FileWriter("/Users/civiluo-1/nand2tetris/projects/06/rect/Rect.hack")
//
//// シンボルテーブル
//val symbolTable = SymbolTable()
//
//// 1. 変数保存
//while (parser.hasMoreCommands()) {
// parser.advance()
// if (parser.commandType() == Parser.COMMAND_TYPE.L_COMMAND) {
// // 次の行のbinaryIndexを保存
// symbolTable.addEntry(parser.symbol(), parser.binaryIndex + 1)
// } else {
// parser.binaryIndex++
// }
//}
//
//parser.reset()
//
//// 2. 変換出力
//val pw = PrintWriter(BufferedWriter(fil))
//
//while (parser.hasMoreCommands()) {
// parser.advance()
// if (parser.commandType() === Parser.COMMAND_TYPE.NONE) {
// continue
// }
//
// if (parser.commandType() === Parser.COMMAND_TYPE.L_COMMAND) {
// continue
// }
//
// if (parser.commandType() === Parser.COMMAND_TYPE.A_COMMAND) {
//
// val symbol = parser.symbol()
//
// // シンボルに文字が含まれる場合
// val address = if (symbol.contains(Regex("""\D+"""))) {
//
// // シンボルテーブルに含まれていない場合
// if (!symbolTable.contains(symbol)) {
// // 新たに追加
// symbolTable.addEntry(symbol)
// }
//
// // シンボルテーブルからアドレスを解決
// symbolTable.getAddress(symbol)
// } else {
// // シンボルが数値の場合
// Integer.parseInt(symbol)
// }
//
// pw.println("%016d".format(Integer.toBinaryString(address).toLong()))
// continue
// }
//
// // C命令
// val binaryString = "111" + Code.comp(parser.comp()) + Code.dest(parser.dest()) + Code.jump(parser.jump())
// pw.println(binaryString)
//}
//
//pw.close()
\ No newline at end of file
import java.io.File
import java.io.InputStream
class Parser(filePath: String) {
enum class COMMAND_TYPE {
C_ARITHMETIC,
C_PUSH,
C_POP,
NONE,
}
private var inputLines = mutableListOf<String>()
private var commandIndex: Int = -1
init {
val inputStream: InputStream = File(filePath).inputStream()
val lineList = mutableListOf<String>()
inputStream.bufferedReader().useLines { lines -> lines.forEach { lineList.add(it) } }
lineList.forEach {
// コメントは除去
val formattedLine = it.split("//")[0].trim()
if (formattedLine.isEmpty()) {
return@forEach
}
this.inputLines.add(formattedLine)
}
}
// 次のコマンドを読み込む
fun advance() {
this.commandIndex++
}
fun commandType(): Parser.COMMAND_TYPE {
val command = this.inputLines[commandIndex]
if (listOf("add", "sub", "neg", "eq", "gt", "lt", "and", "or", "not").contains(command)) {
return COMMAND_TYPE.C_ARITHMETIC
}
if (command.startsWith("push")) {
return COMMAND_TYPE.C_PUSH
}
if (command.startsWith("pop")) {
return COMMAND_TYPE.C_POP
}
return COMMAND_TYPE.NONE
}
fun arg1(): String {
val command = this.inputLines[commandIndex]
if (commandType() === COMMAND_TYPE.C_ARITHMETIC) {
return command.split(" ")[0]
}
return command.split(" ")[1]
}
fun arg2(): String {
val command = this.inputLines[commandIndex]
return command.split(" ")[2]
}
fun hasMoreCommands():Boolean {
return this.inputLines.size > this.commandIndex + 1
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment