Hi, this is dangomushi, who wants you to extend your winter vacation.
How many times do you make it? How many times do you do this? Aside from that, I made it again. This time, I tried to speed up the execution speed by taking advantage of the previous reflection. Specifically, I feel that I focused on designing the virtual language of the VM. By the way, in order to distinguish it from other bytecodes, I call this language "las bytecode". The name is lapis lazuli. For the extension "~ .la", please guess from the grammar and the recent boom in naming your own language. One theory is that it has something to do with the author's birthstone. Also, I finished it again in 5 days from 12/30 to 1/4, so the code is in a state of thread konjac past spaghetti (personally behind the scenes, but in how many days I made my own language that can be announced to others It was also a challenge to see if I could do it. I am a junior high school student, so I hope you can overlook the cleanliness etc.). If I have time, I would like to explain the program itself in the next article.
Task
"Dangomushi" is displayed on the console
Last las bytecode
println_dangomushi
Can I call this a machine language? ?? At that time, it was called "assembly". And this is this one.
This las bytecode
main:
msg "dangomushi"
mov eax, 0
ret
call main
It became like an assembly at once (laughs). Then, it is commentary.
First line, "main:" This means that "it's the main function from here". To cut a long story short is the label in the assembly.
Second line, "msg" This means "I'll output to the console". Originally, it was a different label and various things, but in the case of the author, it was "Huh ?! Why! I don't understand!", So I summarized it.
Third line, "mov eax 0" This is probably the most puzzling part of the assembler. To explain, here we are processing return. Normally it is the "return 0" part. I think it's puzzling for assembler lovers to use "eax", but I don't know. I think I was tired at that time. So eax points to where you store the returned value. In short, it is a variable of the value to be returned.
Fourth line, "ret" This means that the main function is over. Well, I have nothing to explain. Let's go next, next.
Fifth line, last "call main" This indicates that "I will call the main function". This is where I was most worried and far from the assembler. Personally, I wanted Main to be called automatically, but for some reason it didn't work, and I gave up because I had a lot of eyes to keep going around the same place.
Dear readers, thank you for your patience. This is Hello world, the main subject. First, from the code. By the way, we have the same for gitohab. Probably the name is "lapis lazuli".
The language you created this time will be executed in two steps.
2, execution Execute the compiled las bytecode on a dedicated execution program (virtual machine).
Code 1 (main.py, line 83)
main.py
import sys, os, re, glob
#TODO:Main /kernel
class Main:
def __init__(self):
pass
#TODO:data =All data
def run(self, dick, lis):
valts = []
i = 0
case = 0
name = sys.argv[1]
file = open(name, encoding="utf-8")
conf = open(name.split(".")[0]+".las", "a", encoding="utf_8")
data = file.readlines()
file.close()
valts.append(data)
valts = [e for inner_list in valts for e in inner_list]
for data in valts:
data = data.replace("\n", "")
if data.endswith(":") and data.startswith(" while") is False:
data = data.split(" ")[1].replace("()", "")
if data == "main:":
pass
else:
data = data.replace(":", "") + "():"
conf.write("\n{}".format(data))
elif data.startswith(" "):
data = data.replace(" ", "").replace(";", "")
if data.startswith("return"):
conf.write("\n mov {}, {}".format("eax", data.split(" ")[1]))
conf.write("\n ret\n")
elif data.startswith("use"):
conf.write("\n call {}".format(data.split(" ")[1]))
elif "put" in data:
conf.write("\n msg {}".format(data.split(":")[1]))
elif data.startswith("int"):
datav = data.split(" ")[1]
datanum = data.split(" ")[3]
conf.write("\n mov {}, {}".format(datav, datanum))
elif "+" in data:
data = data.replace(" ", "")
val = data.split("=")[0]
data2 = data.split("=")[1].split("+")[0]
data3 = data.split("=")[1].split("+")[1]
conf.write("\n add {}, {}, {}".format(val, data2, data3))
elif "-" in data:
data = data.replace(" ", "")
val = data.split("=")[0]
data2 = data.split("=")[1].split("-")[0]
data3 = data.split("=")[1].split("-")[1]
conf.write("\n sub {}, {}, {}".format(val, data2, data3))
conf.write("\ncall main")
conf.close()
if __name__ == '__main__':
file_list = glob.glob("*las")
for file in file_list:
os.remove(file)
f = open(sys.argv[1].split(".")[0]+".las", "x", encoding="utf_8")
f.close()
dick = {}
lis = []
omega = Main()
omega.run(dick, lis)
There's not much you can do, so there's very little code. Next is the virtual machine code.
Code 2 (run.py, line 75)
run.py
import sys
class Run:
def run(self):
file = open(sys.argv[1], encoding="utf-8")
data = file.readlines()
dick = {}
lis = []
lisf = []
i = 0
for data in data:
data = data.replace("\n", "")
if data.startswith(" "):
lis.append("{};".format(data.replace(" ", "")))
elif data.endswith(":") and data.startswith("while") is False:
func = data.replace(":", "")
lisf.append(func)
elif data.startswith("call"):
dick = dict(zip(lisf, "".join(lis).split("ret;")))
self.test(dick, func, i)
file.close()
def test(self, dick, f, i):
lis = dick[f].split(";")
lisf = f
for data in lis:
data = data.split(";")
data = [a for a in data if a != '']
for data in data:
if data.endswith("()"):
self.test(dick, data.split(" ")[1], i)
else:
if data.startswith("mov"):
data1 = data.split(", ")
datas = data1[0].split(" ")[1]
if datas == "eax":
dick[lisf] = "".join(data1[1:])
else:
dick[datas] = data1[1]
elif data.startswith("call"):
func = data.split(" ")[1]
self.test(dick, func, i)
elif data.startswith("msg"):
if ' "' in data.split("msg")[1]:
print(data.split("msg")[1].replace(' "', "").replace('"', ""))
else:
print(dick[data.split("msg")[1]])
elif data.startswith("add"):
formula = data.split(",")[1].replace(" ", "")
formula2 = data.split(",")[2].replace(" ", "")
val = data.split(",")[0].split(" ")[1]
dick[val] = int(dick[formula]) + int(dick[formula2])
elif data.startswith("sub"):
formula = data.split(",")[1].replace(" ", "")
formula2 = data.split(",")[2].replace(" ", "")
val = data.split(",")[0].split(" ")[1]
dick[val] = int(dick[formula]) - int(dick[formula2])
if __name__ == '__main__':
Run().run()
This code is also extremely small if you think of it as a processing system.
In addition to these explanations and main.py / run.py, Github also comes with sample code. Please come to Github by all means. Link is here
This time, I explained the processing system and virtual machine of my own language using only python. My impression is that there is too little you can do. I want to increase more. As a future issue,
--There are few things you can do as mentioned above. --Not a statically typed language (my preference). --Not object-oriented. --You can only add and subtract.
Can be given. In the next article, I would like to explain the program itself while improving this issue. See you in the next article. goodbye!
Recommended Posts