Skip to content

Instantly share code, notes, and snippets.

@nomi-san
Created January 21, 2019 04:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nomi-san/950e115322b0a32da526691a00ddaf70 to your computer and use it in GitHub Desktop.
Save nomi-san/950e115322b0a32da526691a00ddaf70 to your computer and use it in GitHub Desktop.
Calc.vm in Go
package main
import (
"fmt"
)
const (
VM_OK = 0
VM_ERROR = 1
STACK_MAX = 50
HLT = 0 // thoát
PSH = 1 // push
POP = 2 // pop
PUT = 3 // in giá trị
ADD = 4 // cộng
SUB = 5 // trừ
MUL = 6 // nhân
DIV = 7 // chia
)
type (
Value float64
Code []int
VM struct {
code Code
stack [STACK_MAX]Value
top int
ip int
}
)
var vm VM
func initVM(code Code) {
vm.top = 0
vm.ip = 0
vm.code = code
}
func nextCode() int {
code := vm.code[vm.ip]
vm.ip++
return code
}
func pushValue(val Value) {
vm.stack[vm.top] = val
vm.top++
}
func popValue() Value {
vm.top--
val := vm.stack[vm.top]
return val
}
func runVM() int {
for vm.ip < len(vm.code) {
op := nextCode()
debugVM(op)
switch op {
case HLT:
return VM_OK
case PSH:
val := Value(nextCode())
pushValue(val)
break
case POP:
popValue()
break
case PUT:
val := popValue()
fmt.Printf("-> %g\n", val)
break
case ADD:
b, a := popValue(), popValue() // a push lên trước b, nên khi pop sẽ ngược lại
pushValue(a + b)
break
case SUB:
b, a := popValue(), popValue() // tương tự
pushValue(a - b)
break
case MUL:
b, a := popValue(), popValue()
pushValue(a * b)
break
case DIV:
b, a := popValue(), popValue()
pushValue(a / b)
break
default:
fmt.Printf("unknow opcode: %d\n", op)
return VM_ERROR
}
}
return VM_ERROR
}
func debugVM(op int) {
switch op {
case HLT:
fmt.Print(">> on halt program!\n")
break
case PSH:
val := vm.code[vm.ip]
fmt.Printf(">> push %d to stack\n", val)
break
case POP:
val := vm.stack[vm.top-1]
fmt.Printf(">> pop %g from stack\n", val)
break
case PUT:
val := vm.stack[vm.top-1]
fmt.Printf(">> pop %g from stack and print it\n", val)
break
case ADD:
b, a := vm.stack[vm.top-1], vm.stack[vm.top-2]
fmt.Printf(">> add %g to %g, push %g\n", a, b, a+b)
break
case SUB:
b, a := vm.stack[vm.top-1], vm.stack[vm.top-2]
fmt.Printf(">> sub %g to %g, push %g\n", a, b, a-b)
break
case MUL:
b, a := vm.stack[vm.top-1], vm.stack[vm.top-2]
fmt.Printf(">> mul %g to %g, push %g\n", a, b, a*b)
break
case DIV:
b, a := vm.stack[vm.top-1], vm.stack[vm.top-2]
fmt.Printf(">> div %g to %g, push %g\n", a, b, a/b)
break
}
}
func main() {
// 4 + 5
code1 := []int{PSH, 4, PSH, 5, ADD, PUT, HLT}
// 100 - 52 + 88 // 35 * 8 / 7
code2 := []int{PSH, 100, PSH, 52, SUB, PSH, 88, ADD, PUT, PSH, 35, PSH, 8, MUL, PSH, 6, DIV, PUT, HLT}
initVM(code1)
if runVM() == VM_OK {
fmt.Print("code1: OK\n\n")
} else {
fmt.Print("code1: ERROR\n\n")
}
initVM(code2)
if runVM() == VM_OK {
fmt.Print("code2: OK\n\n")
} else {
fmt.Print("code2: ERROR\n\n")
}
}
$ go run main.go
>> push 4 to stack
>> push 5 to stack
>> add 4 to 5, push 9
>> pop 9 from stack and print it
-> 9
>> on halt program!
code1: OK
>> push 100 to stack
>> push 52 to stack
>> sub 100 to 52, push 48
>> push 88 to stack
>> add 48 to 88, push 136
>> pop 136 from stack and print it
-> 136
>> push 35 to stack
>> push 8 to stack
>> mul 35 to 8, push 280
>> push 6 to stack
>> div 280 to 6, push 46.666666666666664
>> pop 46.666666666666664 from stack and print it
-> 46.666666666666664
>> on halt program!
code2: OK
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment