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

Разбор (parsing) при помощи виртуальной машины(байт-интерпретатора)

Запись от Konst2016 размещена 16.04.2019 в 23:59

Привет!Хочу показать Python код, где показано как можно разобрать выражение типа <int> + <int> + ... +<int> и вычислить значение пользуясь байт-интерпритатором, такая техника называеися PGE-parsing grammar engine.Она используятся для разбора разных грамматик в более больших библиотеках pge:
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
# регулярные выражения
import re
# tag opcode
# байт-код как числа
(OP_CHAR,# 0
OP_MATCH_INT,# 1
SUM,# 2
MATCH_FAIL,# 3
MATCH_ERROR,# 4
BRT,# 5
STOP# 6
)=range(7)
 
class Vm:
 # байт-код
 code=[]
 # указатель (индекс) байт-кода
 ip=0
 # динамичный стек
 steck=[]
 
 # операнды арифметической операции
 a,b=0,0
 
 ps_l=[] # parsing string as list
 # указатель на элемент разбираемойё строки (как списка)
 char_ptr=0
 # флаг - кончилась ли разбираемая строка
 flag_str_not_ends=True
 # @param _code байт-код описывающий правило 
 # @param _ps_l разбираемая строка как список
 def __init__(self,_code,_ps_l):
 
   self.code=_code
   self.ps_l=_ps_l
 # цикл исполнителя
 def vm_match(self):
 
  opcode=self.code[self.ip] # первый опкод
  # элемент в списке разбираемой строки 
  cur_c=self.ps_l[self.char_ptr]
  while (opcode!=STOP):
 
    # указываем следующий байт-код или его операнд
    self.ip+=1
    
    # это числа
    if(opcode==OP_MATCH_INT):
      
      if re.match("[0-9]+",cur_c):
 
        self.steck.append(int(cur_c))
        # переходим на следующий символ
        self.char_ptr+=1
      else:
        
         return MATCH_FAIL
    # это '+'
    elif(opcode==OP_CHAR):
       
       # аргумент опкода
       arg=self.code[self.ip]
       # элемент в списке разбираемой строки 
       if arg!=cur_c:
 
          print("symbol %s does not match rule\n"%self.ps_l[self.char_ptr])
          return MATCH_FAIL
       # переходим на следующий символ
       self.char_ptr+=1 
       # указываем следующий опкод
       self.ip+=1
    # нетерминал - 'свертка'  
    elif(opcode==SUM):
 
      b=self.steck.pop()
      a=self.steck.pop()
      self.steck.append(a+b)
   
    # условный переход
    elif (opcode==BRT):
      # разбираемая строка не кончилась 
      if self.flag_str_not_ends:
 
        arg=self.code[self.ip]
        # переходим на адрес исходя из аргумента байт-кода
        self.ip=arg
      # разбираемая строка кончилась, не делаем прыжок,а
      # просто идем к следующим опкодам(к STOP)
      self.ip+=1  
    
    # узнаем кончилались ли разбираемая строка (как список)
    if self.char_ptr!=len(self.ps_l): # не кончилась
 
       cur_c=self.ps_l[self.char_ptr]
    else: # кончилась
 
       self.flag_str_not_ends=False
    
    # определяем конкретный опкод исходя из индекса(ip)
    opcode=self.code[self.ip]
 
  print("top of steck:%d\n"%self.steck.pop())
# тесты
def test():
 by_co_pge=[OP_MATCH_INT,OP_CHAR,'+',OP_MATCH_INT,SUM,BRT,0,STOP] 
   
 vm_o=Vm( by_co_pge,' 2 + 3 '.split() )
 vm_o.vm_match()
 
 vm_o=Vm( by_co_pge, ' 1 + 2 + 7 '.split() )
 vm_o.vm_match()
 
 vm_o=Vm( by_co_pge,' 0 + 6 + 8 + 3 '.split() )
 vm_o.vm_match()
 
if __name__=='__main__':
  test()
Bash
1
2
3
4
5
6
7
d:\Python_projects\pgeSimpTest>python pgeVm.py
 
top of steck:5
 
top of steck:10
 
top of steck:17
Размещено в Без категории
Просмотров 288 Комментарии 0
Всего комментариев 0
Комментарии
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.