-
Notifications
You must be signed in to change notification settings - Fork 1
/
code.nim
138 lines (97 loc) · 3.52 KB
/
code.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import
strformat, tables, strutils
type
Instructions* = seq[byte]
Opcode* = byte
# これらに振られる数値は各々ユニークであれば何でも良い
const
OpConstant*: OpCode = 0
OpAdd*: OpCode = 1
type Definition = ref object of RootObj
Name: string
OperandWidths: seq[int]
var definitions = {
OpConstant: Definition(Name: "OpConstant", OperandWidths: @[2]),
OpAdd: Definition(Name: "OpAdd", OperandWidths: @[]),
}.newTable
proc lookup*(op: byte): Definition
proc putBigEndian16(arr: var seq[byte], index: int, operand: uint16)
proc makeByte*(op: OpCode, operands: seq[int] = @[]): seq[byte]
proc insToString*(ins: Instructions): string
proc readUint16*(ins: Instructions): uint16
proc readOperands*(def: Definition, ins: Instructions): (seq[int], int)
proc fmtInstructions(self: Instructions, def: Definition, operands: seq[int]): string
# implementation
proc lookup*(op: byte): Definition =
try:
var def = definitions[Opcode(op)]
return def
except :
errorMessageWriter(fmt"opcode {op} undefined")
proc putBigEndian16(arr: var seq[byte], index: int, operand: uint16) =
if arr.len != index: arr.add(byte(0)) # FIXME:
let hex: string = toHex(int(operand), 4) # FFFE
for i in countup(0, len(hex)-1, 2):
var bc = hex[i..i+1] # FF
var c = fromHex[byte](bc) # 255
arr.add(c)
# opcodeとoperandを引数にとり、その全体をバイトコード化したものの配列を返す
proc makeByte*(op: OpCode, operands: seq[int] = @[]): seq[byte] =
try:
let def = definitions[op]
var instructionLen = 1
for i, w in def.OperandWidths:
instructionLen += w
var instruction = newSeq[byte]()
instruction.add(byte(op))
var offset = 1
for i, operand in operands:
let width = def.OperandWidths[i]
if width == 2:
instruction.putBigEndian16(offset, uint16(operand))
offset += width
return instruction
except :
errorMessageWriter(fmt"opcode {op} undefined")
proc insToString*(ins: Instructions): string =
result = ""
var
i = 0
def: Definition
while i < len(ins):
def = lookup(ins[i])
# if def != nil:
# echo fmt"Error"
# continue
let (operands, read) = readOperands(def, ins[i+1..^1])
result &= &"{i:04} {ins.fmtInstructions(def, operands)}\n"
i += 1 + read
proc fmtInstructions(self: Instructions, def: Definition, operands: seq[int]): string =
let operandCount = len(def.OperandWidths)
if len(operands) != operandCount:
return fmt"ERROR: operand len {len(operands)} does not match defined {operandCount}"
case operandCount:
of 0:
return def.Name
of 1:
return fmt"{def.Name} {operands[0]}"
else:
discard
return fmt"ERROR: unhandled operandCount for {def.Name}"
# バイナリの配列を引数にとって、uint16を返す
proc readUint16*(ins: Instructions): uint16 =
let s = toHex(ins[0]) & toHex(ins[1])
return fromHex[uint16](s)
proc readOperands*(def: Definition, ins: Instructions): (seq[int], int) =
var
# operands: array[0..def.OperandWidths.len, int]
operands = newSeq[int]()
offset = 0
for i, width in def.OperandWidths:
if width == 2:
operands.add(int(readUint16(ins[offset..^1]))) # FIXME:
offset += width
return (operands, offset)
proc main() = discard
when isMainModule:
main()