Форум программистов, компьютерный форум, киберфорум
Наши страницы
Konst2016
Войти
Регистрация
Восстановить пароль
Оценить эту запись

Основы виртуальной машины и шитого кода

Запись от Konst2016 размещена 11.07.2018 в 18:20

Привет!Меня зовут Мухамеджанов Константин(вот она слава cyberforum-а )).Вот хочу показать код виртуальной машины(Vm) на python.Я смотрел его по ютуб,
представлял его на java,разработчик antlr-профэссор Terence Parr.Потом я собираюсь привести
'шитый код' который должна выполнять Vm засчет того что здесь работает так называемый адресный
интерпритатор-он формирует байт код файл.Насчет Vm -команды ICONST q,ложит на верхушку стека значение(value),GSTORE ind-'консервирует'
за счет транспортировки значения с верхушки стека в 'глобальную карту' по индексу ind.GLOAD ind-
загружает с 'глобальной' карты с индекса ind на верхушку стека значения переменной.IADD сначала получает значение с
верхушки стека,потом что ниже верхушки стека,складывает и ложит на верхушку стека.DUMP-отпечатывает стек.HALT-выход из Vm.В коде есть инструкции для
вызова функций(CALL),для if-else(BRF <адрес-метка>),while(BRF <адрес-метка>,BR <адрес-метка>-безусловный переход),но
их использование я пока не рассматриваю.
Код Vm
Для функций:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#Context.py
class Context:
    invokingContext=None
    metadata=None
    returnip=0
    locals_=[]
    
    def __init__(self,invokingContext,
        returnip,metadata):
        self.invokingContext=invokingContext
        self.returnip=returnip
        self.metadata=metadata
        self.locals_=[0]*(self.metadata.nargs+self.metadata.nlocals)
        
    def __str__(self):
       return 'self.invokingContext:%s, \
       self.returnip:%s, self.metadata:%s, \
       self.locals_:%s,'%(\
       str(self.invokingContext),
       str(self.returnip),
       str(self.metadata),
       str(self.locals_))
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#FuncMetaData.py
class FuncMetaData:
    name=''
    nargs=0
    nlocals=0
    address=0 #адресс байткода
    
    def __init__(self,name,nargs,nlocals,address):
        self.name=name
        self.nargs=nargs
        self.nlocals=nlocals
        self.address=address
        
    def __str__(self):
        return 'self.name:%s, \
 self.nargs:%s, self.nlocals:%s,\
 self.address:%s'%(str(self.name),
 str(self.nargs), 
 str(self.nlocals),
 str(self.address))
Python
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
#main.py
#-*-coding: utf-8 -*-
#import pdb
#pdb.set_trace()
#import logging as lg
#lg.basicConfig(level=lg.DEBUG,format='%(asctime)s%(levelname)s:%(message)s',filename='vm.log')
from Context import Context
from FuncMetaData import FuncMetaData
IADD=1
ISUB=2
IMUL=3
IDIV=4
LES=5
IEQ=6
BR=7
BRT=8
BRF=9
ICONST=10
LOAD=11
GLOAD=12
STORE=13
GSTORE=14
PRINT=15
POP=16
HALT=17
DUMP=18
DUMP_SP=19
PRINTST=20
DUMP_IP=21
CALL=22
RET=23
INC=24
DEC=25
MOD=26
ABI=27
NEQ=28
LEQ=29
EQU=30
GEQ=31
 
TRUE=1
FALSE=0
 
opcodes=(None,'IADD','ISUB','IMUL','IDIV','LES','IEQ','BR','BRT','BRF',
'ICONST','LOAD','GLOAD','STORE','GSTORE','PRINT','POP','HALT','DUMP',
'DUMP_SP','PRINTST','DUMP_IP','CALL','RET','INC','DEC','MOD','ABI','NEQ',
'LEQ','EQU','GEQ')
class Vm:
 code=[]#сам байт код,как бы слова,но просто числа(байт-обычно до 256 инструкций)
 steck=[]#стек-стек данных-стек операций
 ip=0#указатель инструкций
 sp=-1#указатель стека
 fp=0
 trace=False
 globals_=[]
 metadata=None
 ctx=None
 
 def __init__(self,code,nglobals,metadata,trace=False):
   self.code=code
   self.globals_=[0]*nglobals
   self.steck=[0]*100
   self.metadata=metadata
   self.trace=trace
 def exec_(self,startip):
   self.ip=startip
   if self.metadata!=None: 
#уподобляем определению main()
     self.ctx=Context(None,0,self.metadata[0])
   self.cpu() 
#Отображает выборка-декодирование выполнение петлю
 def cpu(self):
   opcode=-1
#sp+=1 steck[sp]=val
#Выделяем некоторое место на стеке,а затем записываем туда значение.
#Аналог push()
#---
#C++:steck[sp++](постинкремент)
#---
#val=steck[sp]=val sp-=1->val=TOP() sp-=1
#копируем верхушку стека в val и передвигаем указатель на 1
#к меньшему адресу,чтобы TOP() могли ползоваться 
#другие команды.
#Аналог pop()
#---
#C++:steck[--sp](преинкремент)
#---
   while (self.ip<len(self.code) and opcode!=HALT):
     opcode=self.code[self.ip] #fetch 
#некоторая трассировка-вывод только опкодов, без 
#аргументов
     if self.trace:
       print('%d:%s\n'%(self.ip,opcodes[opcode])) 
     if (opcode==ICONST):#switch
      self.ip+=1#exec
      self.sp+=1
      self.steck[self.sp]=self.code[self.ip] 
     elif (opcode==PRINT):
       v=self.steck[self.sp]
       self.sp-=1  
       print(v)
     elif opcode==GSTORE:#сохраняем значение с 
#верхушки стека,в глобальную память по индексу(адресу) взятого 
#как параметр инструкции
       v=self.steck[self.sp]
       #print('v',v)
       self.sp-=1
       self.ip+=1
       addr=self.code[self.ip]
       self.globals_[addr]=v 
#загружаем на верхушку стека значение из глобальной памяти
#взятого по индексу(адресу) как параметр инструкции      
     elif opcode==GLOAD:
      self.ip+=1
      addr=self.code[self.ip]
      v=self.globals_[addr]
      self.sp+=1
      self.steck[self.sp]=v 
     #выход из функции cpu() 
     elif opcode==HALT:
        return
     elif opcode==DUMP:
        print('steck:',self.steck)  
     elif opcode==DUMP_SP:
      print('steck sp:',self.sp)     
     elif opcode==BR:
        self.ip+=1
        self.ip=self.code[self.ip]
        continue
     elif opcode==BRT:
       self.ip+=1
       addr=self.code[self.ip]
       if self.steck[self.sp]==TRUE:
          self.ip=addr
          self.sp-=1 
          continue  
     elif opcode==BRF:
        self.ip+=1
        addr=self.code[self.ip]
        if self.steck[self.sp]==FALSE:
          self.ip=addr
          self.sp-=1 
          continue
     elif opcode==IADD:
       b=self.steck[self.sp]
       self.sp-=1
       a=self.steck[self.sp]
       self.sp-=1
       self.sp+=1
       self.steck[self.sp]=a+b
     elif opcode==ISUB:
       b=self.steck[self.sp]
       self.sp-=1
       a=self.steck[self.sp]
       self.sp-=1
       self.sp+=1
       self.steck[self.sp]=a-b 
     elif opcode==IMUL:
       b=self.steck[self.sp]
       self.sp-=1
       a=self.steck[self.sp]
       self.sp-=1
       self.sp+=1
       self.steck[self.sp]=a*b 
     elif opcode==IDIV:
       b=self.steck[self.sp]
       self.sp-=1
       a=self.steck[self.sp]
       self.sp-=1
       self.sp+=1
       self.steck[self.sp]=a/b  
     elif opcode==LES:
        b=self.steck[self.sp]
        self.sp-=1
        a=self.steck[self.sp]
        self.sp-=1
        if a<b:
          self.sp+=1 
          self.steck[self.sp]=TRUE#True 
        else:
          self.sp+=1
          self.steck[self.sp]=FALSE#False 
     elif opcode==PRINTST:   
        self.ip+=1
        v=self.code[self.ip]
        print(v)
     elif opcode==DUMP_IP:   
        print('ip:',self.ip)
     elif opcode==POP:
      self.sp-=1
#Загружает на верхушку стека,значение из 'локальной' карты,
#взятое по индексу-аргументу LOAD
     elif opcode==LOAD:
        self.ip+=1
        regnum=self.code[self.ip]
        self.sp+=1
        self.steck[self.sp]=self.ctx.locals_[regnum]
#'консервируем' в 'локальную' карту верхушку
#стека на индекс(адрес) как аргумент STORE        
     elif opcode==STORE:
        self.ip+=1
        regnum=self.code[self.ip]
        self.ctx.locals_[regnum]=self.steck[self.sp]
        self.sp-=1 
     elif opcode==CALL:
#ожидается все аргументы на стеке
        self.ip+=1
#индекс целевой функции
        findex=self.code[self.ip]
#сколько аргументов она положила на стек
        nargs=self.metadata[findex].nargs
#ip+1 как аргумент-это returnip,адрес возврата для данной функции,
#используется в RET
        self.ctx=Context(self.ctx,self.ip+1,self.metadata[findex])
#первый аргумент
        firstarg=self.sp-nargs+1
#копируем аргументы со стека
#в новый контекст
        for i in range(0,nargs):
           self.ctx.locals_[i]=self.steck[firstarg+i]
        self.sp-=nargs
        self.ip=self.metadata[findex].address
        continue
     elif opcode==RET:
        self.ip=self.ctx.returnip
        self.ctx=self.ctx.invokingContext
        continue
     elif opcode==INC:
       v=self.steck[self.sp]
       v+=1
       self.steck[self.sp]=v
     elif opcode==DEC: 
      v=self.steck[self.sp]
      v-=1
      self.steck[self.sp]=v
     elif opcode==MOD:
      b=self.steck[self.sp]
      self.sp-=1
      a=self.steck[self.sp]
      self.sp-=1
      self.sp+=1
      self.steck[self.sp]=a%b 
     elif opcode==ABI:
      v=self.steck[self.sp]
      self.steck[self.sp]=abs(v)
     elif opcode==NEQ:#a != b ?
      b=self.steck[self.sp]
      self.sp-=1
      a=self.steck[self.sp]
      self.sp-=1
      if a!=b:
       self.sp+=1 
       self.steck[self.sp]=TRUE#True 
      else:
       self.sp+=1
       self.steck[self.sp]=FALSE#False   
     elif opcode==LEQ:#a <= b ?
      b=self.steck[self.sp]
      self.sp-=1
      a=self.steck[self.sp]
      self.sp-=1
      if a<=b:
       self.sp+=1 
       self.steck[self.sp]=TRUE#True 
      else:
       self.sp+=1
       self.steck[self.sp]=FALSE#False    
     elif opcode==EQU:#a == b ?
      b=self.steck[self.sp]
      self.sp-=1
      a=self.steck[self.sp]
      self.sp-=1
      if a==b:
       self.sp+=1 
       self.steck[self.sp]=TRUE#True 
      else:
       self.sp+=1
       self.steck[self.sp]=FALSE#False  
     elif opcode==GEQ:#a == b ?
      b=self.steck[self.sp]
      self.sp-=1
      a=self.steck[self.sp]
      self.sp-=1
      if a>=b:
       self.sp+=1 
       self.steck[self.sp]=TRUE#True 
      else:
       self.sp+=1
       self.steck[self.sp]=FALSE#False         
     else:
       raise Exception("invalid opcode:",opcode," at ip=",(self.ip-1))
      
     self.ip+=1
 
if __name__=='__main__':
 code=[ICONST,99,
       ICONST,1,
       IADD,
       DUMP,
       PRINT,
       ] 
 #2 параметр -4 глобалных переменных,метадата для функций-Нет,'укороченная'(без параметров) 
 #трассировка есть
 vm_obj=Vm(code,4,None,trace=True)
 #начнем исполнять с (0)й инструкции
 vm_obj.exec_(0)
Адресный интерпритатор
Python
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
#intepret.py
f=open('byte_code.txt','w')
def push(iconst):
    co='ICONST '+str(iconst)+'\n'
    f.write(co)
    
def set(id,const):
    ind=ord(id)-97
    co='ICONST '+str(const)+'\n'+\
    'GSTORE '+str(ind)+'\n'
    f.write(co) 
 
def get(id):
  ind=ord(id)-97  
  co='GLOAD '+str(ind)+'\n'  
  f.write(co)   
def stp():
    f.write('HALT')
    f.close()
    
def iadd(a,b):
    if isinstance(a,int):
     push(a)
    if isinstance(b,int): 
     push(b)
    if isinstance(a,str): 
      get(a) 
    if isinstance(b,str): 
      get(b)  
    co='IADD \n'
    f.write(co)
    
#---
# main
#---
set('a',34)
set('b',44)
iadd('a','b')
 
iadd(56,44)
 
iadd(45,'b')
stp()
#<--
#ICONST 34
#GSTORE 0
#ICONST 44
#GSTORE 1
#GLOAD 0
#GLOAD 1
#IADD
#ICONST 56
#ICONST 44
#IADD
#ICONST 45
#GLOAD 1
#IADD
#HALT
Размещено в Без категории
Просмотров 176 Комментарии 0
Всего комментариев 0
Комментарии
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru