I was trying to create a basic interpreter in Golang. It has just a few instructions (set,jump,add,greater). I tried to run a script which counts to a hundred million and it is already 10 times slower than python. I am not sure why this is happening and would really appreciate someone helping me out.
Here is the source code of the interpreter.
package main
import (
"fmt"
"os"
"strconv"
"strings"
)
func main() {
symbol_table := make(map[string]float64)
dat, err := os.ReadFile("alu.vtl")
if (err!=nil) {
return
}
code:=string(dat)
codex := strings.Split(code, "\n")
i := 0
for {
x := codex[int(i)]
if (x=="" || (string(x[0])=="/" && string(x[1])=="/")) {
i = i + 1
if !(i < len(codex)) {
break
}
continue
}
args := strings.Split(strings.Split(x, " ")[1], ",")
switch opcode := strings.Split(x, " ")[0]; opcode {
case "set":
if err == nil {
num,err:=strconv.ParseFloat(args[1], 64)
if (err!=nil) {
fmt.Println("Ye kya krdiya")
return
}
symbol_table[args[0]] = num
} else {
symbol_table[args[0]] = symbol_table[args[1]]
}
case "jump":
if (symbol_table[args[1]]==1.0) {
i = int(symbol_table[args[0]])
continue
}
case "add":
symbol_table[args[2]] = symbol_table[args[0]]+symbol_table[args[1]]
case "greater":
res:=float64(0)
if (symbol_table[args[0]]>symbol_table[args[1]]) {
res=1
}
symbol_table[args[2]] = res
}
i = i + 1
if !(i < len(codex)) {
break
}
}
fmt.Println(symbol_table)
}
Here is the file i was trying to run
set final,10000000
set count,0
set line_jump,4
set add_count,1
add count,add_count,count
greater final,count,c
jump line_jump,c
I was very shocked when it was so slow as I was expecting it to be atleast a bit faster than python.
I would highly appreciate someone please helping me out on why this is so slow.
Finally after making the suggested changes, my interpreter is now 7x faster than python.
package main
import (
"fmt"
"os"
"strings"
"strconv"
)
// func do_nothing(x interface{}) {}
func contains_int64(a int64, list []int64) map[string]int64 {
res:=make(map[string]int64)
for i, b := range list {
if b == a {
res["index"]=int64(i)
res["contains"]=1
return res
}
}
res["contains"]=0
res["index"]=-1
return res
}
func contains_str(a string, list []string) map[string]int64 {
res:=make(map[string]int64)
for i, b := range list {
if b == a {
res["index"]=int64(i)
res["contains"]=1
return res
}
}
res["contains"]=0
res["index"]=-1
return res
}
func main() {
dat, err := os.ReadFile("alu.vtl")
const_symbol_table:=make([]int64,0)
lookup_symbol_table:=make([]string,0)
symbol_table:=make([]int64,0)
if (err!=nil) {
return
}
code:=string(dat)
codex := strings.Split(code, "\n")
bytecode:=make([][]int64,0)
var_len:=0
const_len:=0
for i := 0; i < len(codex); i++ {
args:=strings.Split(strings.Split(codex[i], " ")[1], ",")
current_byte_code:=make([]int64,0)
switch opcode:=strings.Split(codex[i], " ")[0]; opcode {
case "set":
num,err:=strconv.ParseInt(args[1],10,64)
if (err!=nil) {
fmt.Println("Unable to parse number")
return
}
contains_res:=contains_int64(num,const_symbol_table)
contains1_res:=contains_str(args[0],lookup_symbol_table)
var variable_index int;
if (contains1_res["contains"]==1) {
variable_index=int(contains1_res["index"])
} else {
lookup_symbol_table = append(lookup_symbol_table, args[0])
symbol_table = append(symbol_table, 0)
variable_index=var_len
var_len+=1
}
if (contains_res["contains"]==1) {
current_byte_code = append(current_byte_code, 0,int64(variable_index),contains_res["index"])
} else {
const_symbol_table = append(const_symbol_table, num)
current_byte_code = append(current_byte_code, 0,int64(variable_index),int64(const_len))
const_len+=1
}
bytecode = append(bytecode, current_byte_code)
case "refset":
contains_res:=contains_str(args[0],lookup_symbol_table)
contains1_res:=contains_str(args[1],lookup_symbol_table)
current_byte_code = append(current_byte_code, 1,contains_res["index"],contains1_res["index"])
bytecode = append(bytecode, current_byte_code)
case "jump":
contains_res:=contains_str(args[0],lookup_symbol_table)["index"]
contains1_res:=contains_str(args[1],lookup_symbol_table)["index"]
current_byte_code = append(current_byte_code, 2,contains_res,contains1_res)
bytecode = append(bytecode, current_byte_code)
case "equals","add","greater":
contains_res:=contains_str(args[0],lookup_symbol_table)["index"]
contains1_res:=contains_str(args[1],lookup_symbol_table)["index"]
contains2_res:=contains_str(args[2],lookup_symbol_table)["index"]
var int64_opcode int64;
if (opcode=="equals") {int64_opcode=3}
if (opcode=="greater") {int64_opcode=4}
if (opcode=="add") {int64_opcode=5}
current_byte_code = append(current_byte_code, int64_opcode,contains_res,contains1_res,contains2_res)
bytecode = append(bytecode, current_byte_code)
}
}
fmt.Println(symbol_table,const_symbol_table,bytecode)
for i := 0; i < len(bytecode); i++ {
current_byte_code:=bytecode[i]
switch opcode:=current_byte_code[0]; opcode {
case 0:
symbol_table[current_byte_code[1]]=const_symbol_table[current_byte_code[2]]
case 1:
symbol_table[current_byte_code[1]]=symbol_table[current_byte_code[2]]
case 2:
if (symbol_table[current_byte_code[1]]==1) {
i=int(const_symbol_table[current_byte_code[2]])-1
}
case 3:
if (symbol_table[current_byte_code[1]]==symbol_table[current_byte_code[2]]) {
symbol_table[current_byte_code[3]]=1
} else {
symbol_table[current_byte_code[3]]=0
}
case 4:
if (symbol_table[current_byte_code[1]]>symbol_table[current_byte_code[2]]) {
symbol_table[current_byte_code[3]]=1
} else {
symbol_table[current_byte_code[3]]=0
}
case 5:
symbol_table[current_byte_code[3]]=symbol_table[current_byte_code[1]]+symbol_table[current_byte_code[2]]
}
}
fmt.Println(symbol_table,const_symbol_table)
}
Input code
set jump_count,3
set final,1000000000
set increment,1
set is_bigger,0
set line_jump,5
add increment,jump_count,jump_count
greater final,jump_count,is_bigger
jump is_bigger,line_jump