bets 0.0.13 → 0.0.14
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -0
- data/bin/bets +2 -2
- data/install.sh +3 -0
- data/lib/bets/version.rb +1 -1
- data/lib/bets.glade +971 -0
- data/lib/bets.rb +1058 -150
- data/lib/options.dat +0 -0
- data/lib/rules.rb +747 -0
- metadata +6 -2
data/lib/rules.rb
ADDED
@@ -0,0 +1,747 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Rules
|
3
|
+
class Lexical
|
4
|
+
attr_reader :result
|
5
|
+
attr_reader :errors
|
6
|
+
private
|
7
|
+
def initialize
|
8
|
+
# Дерево лексического разбора
|
9
|
+
keywrd_trm = '[\s\;]'
|
10
|
+
digvar_trm = '[\s\)\+\-\*\/\=\>\<\;]'
|
11
|
+
operat_trm = '[\sA-Za-zА-Яа-я0-9\(]'
|
12
|
+
|
13
|
+
@lexems = [
|
14
|
+
[['\.','\s','',:stop],
|
15
|
+
['','\.',keywrd_trm,'',:dup],
|
16
|
+
['','','','','','','','','','']],
|
17
|
+
[[';','\s','',:semicolon],
|
18
|
+
['','','','','','','','']],
|
19
|
+
[['\(','.?\s?','',:l_brace],
|
20
|
+
['','','','','','','','']],
|
21
|
+
[['\)','.?\s?','',:r_brace],
|
22
|
+
['','','','','','','','']],
|
23
|
+
[['\=',operat_trm,'',:equ],
|
24
|
+
['','','','','','','','','','']],
|
25
|
+
[['\+',operat_trm,'',:plus],
|
26
|
+
['','','','','','','','','','']],
|
27
|
+
[['\-',operat_trm,'',:minus],
|
28
|
+
['','','','','','','','','','']],
|
29
|
+
[['\*',operat_trm,'',:mul],
|
30
|
+
['','','','','','','','','','']],
|
31
|
+
[['\/',operat_trm,'',:div],
|
32
|
+
['','','','','','','','','','']],
|
33
|
+
[['\>',operat_trm,'',:great],
|
34
|
+
['' ,'=', operat_trm, '', :ge],
|
35
|
+
['','','','','','','','','','']],
|
36
|
+
[['\<',operat_trm,'',:low],
|
37
|
+
['','\=',operat_trm,'',:le],
|
38
|
+
['','\-',keywrd_trm,'',:ret],
|
39
|
+
['','\>',keywrd_trm,'',:swap],
|
40
|
+
['','','','','','','','','','']],
|
41
|
+
[['\|', keywrd_trm,'',:lim],
|
42
|
+
['','','','','','','','','','']],
|
43
|
+
|
44
|
+
[['\-','\-', '[\r\n]','',:comment],
|
45
|
+
['','', '~', '.', '[\r\n]','',:comment],
|
46
|
+
['','','','','','','','']],
|
47
|
+
|
48
|
+
|
49
|
+
[['\?','д','а',keywrd_trm,'',:if_yes],
|
50
|
+
['','н','е','т',keywrd_trm,'',:if_no],
|
51
|
+
['','|',keywrd_trm,'',:lcp],
|
52
|
+
['','','','','','','','']],
|
53
|
+
|
54
|
+
[['и',keywrd_trm,'',:and],
|
55
|
+
['','л','и',keywrd_trm,'',:or],
|
56
|
+
['','н','а','ч','е',keywrd_trm,'',:else],
|
57
|
+
['','с','т','и','н','а',keywrd_trm,'',:true],
|
58
|
+
['','','','','','','','','','']],
|
59
|
+
|
60
|
+
[['л','о','ж','ь',keywrd_trm,'',:false],
|
61
|
+
['','','','','','','','']],
|
62
|
+
|
63
|
+
[['п','о','д','к','л','ю','ч','и','т','ь',keywrd_trm,'',:include],
|
64
|
+
['','у','с','т','о',keywrd_trm,'',:nil],
|
65
|
+
['','','','','','','','']],
|
66
|
+
|
67
|
+
[['r','u','b','y',keywrd_trm,'',:ruby],
|
68
|
+
['','','','','','','','']],
|
69
|
+
|
70
|
+
[['\d',digvar_trm,'', :number],
|
71
|
+
['' ,'\.','~','\d',digvar_trm,'',:float],
|
72
|
+
['' ,'~','\d',digvar_trm,'',:number],
|
73
|
+
['' , '', '','\.','~','\d',digvar_trm,'',:float],
|
74
|
+
['','','','','','','','','','','','','']],
|
75
|
+
|
76
|
+
[['\"','~','[^"]','\"',keywrd_trm,'',:string],
|
77
|
+
['','','','','','','','','','']],
|
78
|
+
|
79
|
+
[['\'','~','[^\']','\'',keywrd_trm,'',:string],
|
80
|
+
['','','','','','','','','','']],
|
81
|
+
|
82
|
+
[['\:','~','[а-яА-Я\w]',keywrd_trm,'',:word],
|
83
|
+
['','','','','','','','','','']],
|
84
|
+
|
85
|
+
[['[а-яА-Яa-zA-Z]',digvar_trm,'',:var],
|
86
|
+
['','~','[а-яА-Я\w]',digvar_trm,'',:var],
|
87
|
+
['','','','\:','\s','',:label],
|
88
|
+
['','','','','\:','\s','',:proc],
|
89
|
+
['','','','','','','','','','']],
|
90
|
+
|
91
|
+
[['@','~','[а-яА-Я\w]',digvar_trm,'',:addr],
|
92
|
+
['','','','','','','','','','']],
|
93
|
+
|
94
|
+
[['!','~','[а-яА-Я\w]',digvar_trm,'',:wvar],
|
95
|
+
['','','','','','','','','','']],
|
96
|
+
|
97
|
+
[['\x0', '\s', '', :end],
|
98
|
+
['','','','','','','','','','']],
|
99
|
+
|
100
|
+
[['.','\s','',:lexical_error],
|
101
|
+
['', '~', '.','\s', '',:lexical_error],
|
102
|
+
['','','','','','','','','','']]
|
103
|
+
]
|
104
|
+
@error_msg = {
|
105
|
+
incorrect_lexem: "Недопустимая лексема"
|
106
|
+
}
|
107
|
+
@result = []
|
108
|
+
@errors = []
|
109
|
+
|
110
|
+
@step = @step_count = 1
|
111
|
+
end
|
112
|
+
# Проход по подлексемам
|
113
|
+
def get_sublexem(lg, tp)
|
114
|
+
bp = p = tp
|
115
|
+
y = x = 0
|
116
|
+
f = false
|
117
|
+
value = ''
|
118
|
+
loop do
|
119
|
+
while @t[p] =~ Regexp.new(lg[y][x]) do
|
120
|
+
x += 1 unless f
|
121
|
+
value += @t[p]
|
122
|
+
if lg[y][x].empty?
|
123
|
+
result = {
|
124
|
+
line: @l,
|
125
|
+
begin: bp,
|
126
|
+
length: p - bp,
|
127
|
+
lexem: lg[y][x + 1],
|
128
|
+
value: value[0..-2]
|
129
|
+
}
|
130
|
+
return result
|
131
|
+
end
|
132
|
+
p += 1
|
133
|
+
if f == true && not(@t[p] =~ Regexp.new(lg[y][x]))
|
134
|
+
x += 1
|
135
|
+
f = false
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
if lg[y][x] == '~'
|
140
|
+
x += 1
|
141
|
+
f = true
|
142
|
+
next
|
143
|
+
end
|
144
|
+
y += 1
|
145
|
+
|
146
|
+
y += 1 while not lg[y][x-1].empty?
|
147
|
+
return nil if lg[y][x].empty?
|
148
|
+
end
|
149
|
+
end
|
150
|
+
# Получить текущую лексему
|
151
|
+
def get_lexem
|
152
|
+
a = 0
|
153
|
+
loop do
|
154
|
+
return nil if @p >= @t.length
|
155
|
+
lg = @lexems[a]
|
156
|
+
while @t[@p] =~ /\s/ do
|
157
|
+
@l += 1 if @t[@p] =~ /\n/
|
158
|
+
@p += 1
|
159
|
+
return nil if @p >= @t.length
|
160
|
+
end
|
161
|
+
if @t[@p] =~ Regexp.new(lg[0][0])
|
162
|
+
result = get_sublexem(lg, @p)
|
163
|
+
unless result.nil?
|
164
|
+
@p += result[:length]
|
165
|
+
@cls.send(@mth, @p * 20 / @t.length ) unless @cls.nil?
|
166
|
+
return result
|
167
|
+
end
|
168
|
+
end
|
169
|
+
a += 1
|
170
|
+
end
|
171
|
+
end
|
172
|
+
public
|
173
|
+
# Разбор на лексемы
|
174
|
+
def analyze (text, filename)
|
175
|
+
@p = 0
|
176
|
+
@l = 1
|
177
|
+
@t = text + "\n\x0\n"
|
178
|
+
# Удаление блочных комментариев
|
179
|
+
# @t.gsub!(/\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\//, '')
|
180
|
+
# Удаление строчных комментариев
|
181
|
+
# @t.gsub!(/\-\-.*\n/, '')
|
182
|
+
|
183
|
+
@result = []
|
184
|
+
@errors = []
|
185
|
+
loop do
|
186
|
+
lexem = get_lexem
|
187
|
+
break if lexem.nil?
|
188
|
+
break if lexem[:lexem] == :end
|
189
|
+
lexem[:filename] = filename
|
190
|
+
if lexem[:lexem] == :lexical_error
|
191
|
+
@errors << {
|
192
|
+
:message => @error_msg[:incorrect_lexem],
|
193
|
+
:lexem => lexem } if @errors.length < 5
|
194
|
+
else
|
195
|
+
@result << lexem
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
def set_progress_callback(classp, mth)
|
200
|
+
@cls = classp
|
201
|
+
@mth = mth
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|
205
|
+
|
206
|
+
class Syntax
|
207
|
+
attr_reader :errors
|
208
|
+
private
|
209
|
+
def initialize
|
210
|
+
# Дерево синтаксического разбора
|
211
|
+
operators = [:plus,:minus,:div,:mul,:great,:ge,:low,:le,:equ,:or,:and]
|
212
|
+
digits = [:number,:float,:true,:false,:nil]
|
213
|
+
strings = [:string,:word]
|
214
|
+
conditions = [:if_yes,:if_no,:else,:lcp,:semicolon]
|
215
|
+
ids = [:var,:proc,:label,:addr,:wvar]
|
216
|
+
term = ids + conditions + operators + digits + strings + [:stop,:l_brace,:end,:ret,:include,:dup,:swap,:lim,:ruby,:comment,nil]
|
217
|
+
|
218
|
+
@syntax = {
|
219
|
+
:stop => term + [nil],
|
220
|
+
:semicolon => term + [nil],
|
221
|
+
:dup => term + [nil],
|
222
|
+
:swap => term + [nil],
|
223
|
+
:l_brace => [:l_brace] + digits + [:minus,:var,nil],
|
224
|
+
:r_brace => [:r_brace] + operators + ids + term + [:semicolon,nil],
|
225
|
+
:equ => term + [nil],
|
226
|
+
:plus => term + [nil],
|
227
|
+
:minus => term + [nil],
|
228
|
+
:mul => term + [nil],
|
229
|
+
:div => term + [nil],
|
230
|
+
:great => term + [nil],
|
231
|
+
:ge => term + [nil],
|
232
|
+
:low => term + [nil],
|
233
|
+
:le => term + [nil],
|
234
|
+
:and => term + [nil],
|
235
|
+
:or => term + [nil],
|
236
|
+
:ret => term + [nil],
|
237
|
+
:if_yes => term + [nil],
|
238
|
+
:if_no => term + [nil],
|
239
|
+
:lcp => term + [nil],
|
240
|
+
:else => term + [nil],
|
241
|
+
:true => digits + [:var,:wvar] + operators + conditions + [:r_brace,:end,nil],
|
242
|
+
:false => digits + [:var,:wvar] + operators + conditions + [:r_brace,:end,nil],
|
243
|
+
:number => digits + strings + [:var,:wvar] + operators + conditions + [:r_brace,:end,nil],
|
244
|
+
:float => digits + strings + [:var,:wvar] + operators + conditions + [:r_brace,:end,nil],
|
245
|
+
:string => term + [nil],
|
246
|
+
:var => operators + term + [nil],
|
247
|
+
:addr => operators + term + [nil],
|
248
|
+
:wvar => term + [nil],
|
249
|
+
:label => term + [nil],
|
250
|
+
:proc => term + [nil],
|
251
|
+
:include => term + [nil],
|
252
|
+
:ruby => term + [nil],
|
253
|
+
:comment => term + [nil],
|
254
|
+
:nil => term + [nil],
|
255
|
+
:lim => term + [nil],
|
256
|
+
:word => term + [nil],
|
257
|
+
:end => term + [nil]
|
258
|
+
}
|
259
|
+
|
260
|
+
@error_msg = {
|
261
|
+
incorrect_syntax: "Недопустимый синтаксис"
|
262
|
+
}
|
263
|
+
@errors = []
|
264
|
+
end
|
265
|
+
public
|
266
|
+
def analyze(lexem_seq)
|
267
|
+
@errors = []
|
268
|
+
sp = nil
|
269
|
+
lp = 0
|
270
|
+
while lp < lexem_seq.length and !lexem_seq[lp + 1].nil? do
|
271
|
+
sp = @syntax[lexem_seq[lp][:lexem]]
|
272
|
+
sp.each do |s|
|
273
|
+
break if s == lexem_seq[lp + 1][:lexem]
|
274
|
+
if s.nil?
|
275
|
+
@errors << {
|
276
|
+
:message => @error_msg[:incorrect_syntax],
|
277
|
+
:lexem => lexem_seq[lp + 1]} if @errors.length < 5
|
278
|
+
break
|
279
|
+
end
|
280
|
+
end
|
281
|
+
lp += 1
|
282
|
+
@cls.send(@mth, 20 + lp * 20 / lexem_seq.length ) unless @cls.nil?
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def set_progress_callback(classp, mth)
|
287
|
+
@cls = classp
|
288
|
+
@mth = mth
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
class Translator
|
293
|
+
attr_reader :ids
|
294
|
+
attr_reader :debug
|
295
|
+
attr_reader :data_seg
|
296
|
+
attr_reader :code_seg
|
297
|
+
attr_reader :errors
|
298
|
+
attr_reader :includes
|
299
|
+
|
300
|
+
private
|
301
|
+
def initialize
|
302
|
+
@syntax = Syntax.new
|
303
|
+
@lexical = Lexical.new
|
304
|
+
@uid = 0
|
305
|
+
@errors = 0
|
306
|
+
|
307
|
+
@error_msg = {
|
308
|
+
brace: "Кол-во открытых скобок не соответствует кол-ву закрытых",
|
309
|
+
include: "Ошибка открытия файла в инструкции `подключить`"
|
310
|
+
}
|
311
|
+
end
|
312
|
+
def unique_id
|
313
|
+
@uid += 1
|
314
|
+
return "ABC#{@uid}"
|
315
|
+
end
|
316
|
+
|
317
|
+
# Первый проход:
|
318
|
+
def first_pass(lex_seq, libdir)
|
319
|
+
@errors = []
|
320
|
+
@code_seg = []
|
321
|
+
@data_seg = []
|
322
|
+
@ids = {}
|
323
|
+
@debug = []
|
324
|
+
@includes = []
|
325
|
+
|
326
|
+
postfix_stack = []
|
327
|
+
condition_stack = []
|
328
|
+
f_unary = false
|
329
|
+
|
330
|
+
store = nil
|
331
|
+
il = 0
|
332
|
+
while il < lex_seq.length do
|
333
|
+
break if lex_seq[il].nil?
|
334
|
+
case lex_seq[il][:lexem]
|
335
|
+
# Раздел обработки выражений
|
336
|
+
when :l_brace
|
337
|
+
postfix_stack.push lex_seq[il]
|
338
|
+
when :r_brace
|
339
|
+
loop do
|
340
|
+
if postfix_stack.last.nil?
|
341
|
+
@errors << {
|
342
|
+
message: @error_msg[:brace],
|
343
|
+
lexem: lex_seq[il]
|
344
|
+
}
|
345
|
+
return
|
346
|
+
end
|
347
|
+
|
348
|
+
break if postfix_stack.last[:lexem] == :l_brace
|
349
|
+
d = postfix_stack.pop
|
350
|
+
@code_seg << d[:lexem]
|
351
|
+
@debug << d
|
352
|
+
end
|
353
|
+
postfix_stack.pop
|
354
|
+
when :plus,:minus,:div,:mul,:equ,:great,:low,:ge,:le
|
355
|
+
if postfix_stack.length == 0
|
356
|
+
@code_seg << lex_seq[il][:lexem]
|
357
|
+
@debug << lex_seq[il]
|
358
|
+
else
|
359
|
+
if store[:lexem] == :l_brace and lex_seq[il][:lexem] == :minus
|
360
|
+
lex_seq[il][:lexem] = :unary_minus
|
361
|
+
f_unary = true
|
362
|
+
else
|
363
|
+
if ([:plus,:minus,:equ,:great,:low,:ge,:le].include? lex_seq[il][:lexem] and !postfix_stack.last.nil? and [:plus,:minus,:div,:mul].include? postfix_stack.last[:lexem]) or (!postfix_stack.last.nil? and [:div,:mul,:unary_minus].include? postfix_stack.last[:lexem])
|
364
|
+
d = postfix_stack.pop
|
365
|
+
@code_seg << d[:lexem]
|
366
|
+
@debug << d
|
367
|
+
end
|
368
|
+
postfix_stack.push lex_seq[il]
|
369
|
+
end
|
370
|
+
end
|
371
|
+
# Раздел обработки идентификаторов
|
372
|
+
when :var
|
373
|
+
id = lex_seq[il][:value]
|
374
|
+
if @ids[id].nil?
|
375
|
+
@data_seg << nil
|
376
|
+
@ids[id] = {:type => :var, :addr => @data_seg.length - 1, :changes => [@code_seg.length + 1]}
|
377
|
+
else
|
378
|
+
@ids[id][:changes] << @code_seg.length + 1
|
379
|
+
end
|
380
|
+
if @ids[id][:type] == :var
|
381
|
+
@code_seg << :dpush
|
382
|
+
@debug << lex_seq[il]
|
383
|
+
else
|
384
|
+
@code_seg << 0
|
385
|
+
@debug << lex_seq[il]
|
386
|
+
end
|
387
|
+
@code_seg << @ids[id][:addr]
|
388
|
+
@debug << lex_seq[il]
|
389
|
+
when :wvar
|
390
|
+
id = lex_seq[il][:value][1..-1]
|
391
|
+
if @ids[id].nil?
|
392
|
+
@data_seg << nil
|
393
|
+
@ids[id] = {:type => :var, :addr => @data_seg.length - 1, :changes => [@code_seg.length + 1]}
|
394
|
+
else
|
395
|
+
@ids[id][:changes] << @code_seg.length + 1
|
396
|
+
end
|
397
|
+
@code_seg << :dpop
|
398
|
+
@debug << lex_seq[il]
|
399
|
+
@code_seg << @ids[id][:addr]
|
400
|
+
@debug << lex_seq[il]
|
401
|
+
when :proc
|
402
|
+
id = lex_seq[il][:value].gsub(/\:*/, '')
|
403
|
+
if @ids[id].nil?
|
404
|
+
@ids[id] = {:type => :proc, :addr => @code_seg.length, :changes => []}
|
405
|
+
else
|
406
|
+
@data_seg.delete_at @ids[id][:addr]
|
407
|
+
@ids[id][:addr] = @code_seg.length
|
408
|
+
@ids[id][:type] = :proc
|
409
|
+
end
|
410
|
+
when :label
|
411
|
+
id = lex_seq[il][:value].gsub(/\:*/, '')
|
412
|
+
if @ids[id].nil?
|
413
|
+
@ids[id] = {:type => :label, :addr => @code_seg.length, :changes => []}
|
414
|
+
else
|
415
|
+
@data_seg.delete_at @ids[id][:addr]
|
416
|
+
@ids[id][:addr] = @code_seg.length
|
417
|
+
@ids[id][:type] = :label
|
418
|
+
end
|
419
|
+
# Раздел обработки литералов
|
420
|
+
when :addr
|
421
|
+
@code_seg << :push
|
422
|
+
@debug << lex_seq[il]
|
423
|
+
addr = @ids[lex_seq[il][:value][1..-1]][:addr]
|
424
|
+
@code_seg << addr
|
425
|
+
@debug << lex_seq[il]
|
426
|
+
when :number
|
427
|
+
@code_seg << :push
|
428
|
+
@debug << lex_seq[il]
|
429
|
+
@code_seg << lex_seq[il][:value].to_i * (f_unary ? -1 : 1)
|
430
|
+
@debug << lex_seq[il]
|
431
|
+
f_unary = false
|
432
|
+
when :float
|
433
|
+
@code_seg << :push
|
434
|
+
@debug << lex_seq[il]
|
435
|
+
@code_seg << lex_seq[il][:value].to_f * (f_unary ? -1 : 1)
|
436
|
+
@debug << lex_seq[il]
|
437
|
+
f_unary = false
|
438
|
+
when :string
|
439
|
+
@code_seg << :push
|
440
|
+
@debug << lex_seq[il]
|
441
|
+
@code_seg << lex_seq[il][:value][1..-2]
|
442
|
+
@debug << lex_seq[il]
|
443
|
+
when :word
|
444
|
+
@code_seg << :push
|
445
|
+
@debug << lex_seq[il]
|
446
|
+
@code_seg << lex_seq[il][:value][1..-1]
|
447
|
+
@debug << lex_seq[il]
|
448
|
+
when :uminus
|
449
|
+
f_unary = true
|
450
|
+
# Раздел обработки условий
|
451
|
+
when :true
|
452
|
+
@code_seg << :push
|
453
|
+
@debug << lex_seq[il]
|
454
|
+
@code_seg << 1
|
455
|
+
@debug << lex_seq[il]
|
456
|
+
when :false
|
457
|
+
@code_seg << :push
|
458
|
+
@debug << lex_seq[il]
|
459
|
+
@code_seg << 0
|
460
|
+
@debug << lex_seq[il]
|
461
|
+
when :nil
|
462
|
+
@code_seg << :push
|
463
|
+
@debug << lex_seq[il]
|
464
|
+
@code_seg << nil
|
465
|
+
@debug << lex_seq[il]
|
466
|
+
when :if_yes
|
467
|
+
@code_seg << :jne
|
468
|
+
@debug << lex_seq[il]
|
469
|
+
id = unique_id
|
470
|
+
@ids[id] = {:type => :in, :addr => 0, :changes => [@code_seg.length]}
|
471
|
+
@code_seg << 0
|
472
|
+
@debug << lex_seq[il]
|
473
|
+
condition_stack.push id
|
474
|
+
when :if_no
|
475
|
+
@code_seg << :je
|
476
|
+
@debug << lex_seq[il]
|
477
|
+
id = unique_id
|
478
|
+
@ids[id] = {:type => :in, :addr => 0, :changes => [@code_seg.length]}
|
479
|
+
@code_seg << 0
|
480
|
+
@debug << lex_seq[il]
|
481
|
+
condition_stack.push id
|
482
|
+
when :else
|
483
|
+
id_yesno = condition_stack.pop
|
484
|
+
id = unique_id
|
485
|
+
@code_seg << :jmp
|
486
|
+
@debug << lex_seq[il]
|
487
|
+
@ids[id] = {:type => :in, :addr => 0, :changes => [@code_seg.length]}
|
488
|
+
@code_seg << 0
|
489
|
+
@debug << lex_seq[il]
|
490
|
+
condition_stack.push id
|
491
|
+
@ids[id_yesno][:addr] = @code_seg.length
|
492
|
+
when :semicolon
|
493
|
+
id = condition_stack.pop
|
494
|
+
@ids[id][:addr] = @code_seg.length
|
495
|
+
when :include
|
496
|
+
il += 1
|
497
|
+
# Чтение исходного кода
|
498
|
+
filename = lex_seq[il][:value][1..-2]
|
499
|
+
basename = File.basename(filename)
|
500
|
+
unless File.exist?("#{filename}.rules")
|
501
|
+
filename = File.join(libdir, 'ruleslib', "#{basename}.rules")
|
502
|
+
end
|
503
|
+
unless File.exist?(filename)
|
504
|
+
gem_file = Gem::find_files("#{basename}_rules.rb").last
|
505
|
+
if gem_file.nil?
|
506
|
+
@errors << {
|
507
|
+
message: @error_msg[:include],
|
508
|
+
lexem: lex_seq[il]
|
509
|
+
}
|
510
|
+
return
|
511
|
+
end
|
512
|
+
filename = File.join(File.dirname(gem_file), "#{basename}.rules")
|
513
|
+
end
|
514
|
+
text = ''
|
515
|
+
begin
|
516
|
+
filename = File.expand_path(filename)
|
517
|
+
text = File.open(filename, "r:UTF-8").read
|
518
|
+
@includes << basename
|
519
|
+
rescue Exception => e
|
520
|
+
@errors << {
|
521
|
+
message: @error_msg[:include],
|
522
|
+
lexem: lex_seq[il]
|
523
|
+
}
|
524
|
+
return
|
525
|
+
end
|
526
|
+
@lexical.analyze(text, filename)
|
527
|
+
@syntax.analyze(@lexical.result)
|
528
|
+
@errors += @syntax.errors + @lexical.errors
|
529
|
+
@lexical.result.each_index do |i|
|
530
|
+
lex_seq.insert(il+1+i,@lexical.result[i])
|
531
|
+
end
|
532
|
+
when :comment
|
533
|
+
else
|
534
|
+
@code_seg << lex_seq[il][:lexem]
|
535
|
+
@debug << lex_seq[il]
|
536
|
+
end
|
537
|
+
store = lex_seq[il]
|
538
|
+
il += 1
|
539
|
+
@cls.send(@mth, 40 + il * 40 / lex_seq.length ) unless @cls.nil?
|
540
|
+
end
|
541
|
+
while postfix_stack.length > 0 do
|
542
|
+
if postfix_stack.last[:lexem] == :l_brace
|
543
|
+
@errors << {
|
544
|
+
message: @error_msg[:brace],
|
545
|
+
lexem: postfix_stack.last
|
546
|
+
}
|
547
|
+
return
|
548
|
+
end
|
549
|
+
d = postfix_stack.pop
|
550
|
+
@code_seg << d[:lexem]
|
551
|
+
@debug << d
|
552
|
+
end
|
553
|
+
if @errors.length > 0
|
554
|
+
@code_seg = nil
|
555
|
+
@data_seg = nil
|
556
|
+
@debug = nil
|
557
|
+
@ids = nil
|
558
|
+
end
|
559
|
+
end
|
560
|
+
# Второй проход
|
561
|
+
def second_pass
|
562
|
+
i = 0
|
563
|
+
@ids.each do |k,id|
|
564
|
+
id[:changes].each do |c|
|
565
|
+
@code_seg[c] = id[:addr]
|
566
|
+
@code_seg[c - 1] = :call if id[:type] == :proc
|
567
|
+
@code_seg[c - 1] = :jmp if id[:type] == :label
|
568
|
+
end
|
569
|
+
i += 1
|
570
|
+
@cls.send(@mth, 80 + i * 20 / @ids.length ) unless @cls.nil?
|
571
|
+
end
|
572
|
+
end
|
573
|
+
public
|
574
|
+
def translate(lex_seq, libdir)
|
575
|
+
@ids = {}
|
576
|
+
@debug = []
|
577
|
+
@data_seg = []
|
578
|
+
@code_seg = []
|
579
|
+
first_pass(lex_seq, libdir)
|
580
|
+
# @code_seg.each_index {|i| puts "#{i} -- #{@code_seg[i]}"}
|
581
|
+
second_pass unless @errors.length > 0
|
582
|
+
# @code_seg.each_index {|i| puts "#{i} -- #{@code_seg[i]}"}
|
583
|
+
end
|
584
|
+
|
585
|
+
def set_progress_callback(classp, mth)
|
586
|
+
@cls = classp
|
587
|
+
@mth = mth
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
class VM
|
592
|
+
attr_reader :data
|
593
|
+
attr_reader :data_stack
|
594
|
+
attr_reader :limit_stack
|
595
|
+
attr_reader :prog
|
596
|
+
attr_reader :ip
|
597
|
+
|
598
|
+
private
|
599
|
+
def initialize(data_seg, code_seg, debug)
|
600
|
+
@cls = nil
|
601
|
+
@mth = nil
|
602
|
+
# trap("SIGINT") { exit! }
|
603
|
+
# Память данных
|
604
|
+
@data = data_seg
|
605
|
+
# Стек данных
|
606
|
+
@data_stack = []
|
607
|
+
# Стек ограничителей
|
608
|
+
@limit_stack = []
|
609
|
+
# Стек вызовов
|
610
|
+
@call_stack = []
|
611
|
+
# Память программ
|
612
|
+
@prog = code_seg
|
613
|
+
# Указатель текущей инструкции
|
614
|
+
@ip = 0
|
615
|
+
# Отладочная информация
|
616
|
+
@debug = debug
|
617
|
+
|
618
|
+
# Объекты ruby
|
619
|
+
@uid = 0
|
620
|
+
@objects = {}
|
621
|
+
end
|
622
|
+
|
623
|
+
def unique_id
|
624
|
+
@uid += 1
|
625
|
+
return "#vm_#{@uid}"
|
626
|
+
end
|
627
|
+
|
628
|
+
public
|
629
|
+
def halt
|
630
|
+
@thread.terminate unless @thread.nil?
|
631
|
+
end
|
632
|
+
|
633
|
+
def run
|
634
|
+
Thread.abort_on_exception = true
|
635
|
+
@thread = Thread.new do
|
636
|
+
@ip = 0
|
637
|
+
while @ip < @prog.length do
|
638
|
+
@cls.send(@mth, @debug[@ip]) unless @cls.nil?
|
639
|
+
case @prog[@ip]
|
640
|
+
when :push
|
641
|
+
@ip += 1; @data_stack.push @prog[@ip]
|
642
|
+
when :call
|
643
|
+
@call_stack.push @ip + 2
|
644
|
+
@ip = @prog[@ip + 1]
|
645
|
+
next
|
646
|
+
when :ret
|
647
|
+
@ip = @call_stack.pop
|
648
|
+
next
|
649
|
+
when :dup
|
650
|
+
@data_stack.push @data_stack.last
|
651
|
+
when :swap
|
652
|
+
a = @data_stack.pop
|
653
|
+
b = @data_stack.pop
|
654
|
+
@data_stack.push a
|
655
|
+
@data_stack.push b
|
656
|
+
when :plus
|
657
|
+
a = @data_stack.pop
|
658
|
+
b = @data_stack.pop
|
659
|
+
@data_stack.push b + a
|
660
|
+
when :minus
|
661
|
+
a = @data_stack.pop
|
662
|
+
b = @data_stack.pop
|
663
|
+
@data_stack.push b - a
|
664
|
+
when :div
|
665
|
+
a = @data_stack.pop
|
666
|
+
b = @data_stack.pop
|
667
|
+
@data_stack.push b / a
|
668
|
+
when :mul
|
669
|
+
a = @data_stack.pop
|
670
|
+
b = @data_stack.pop
|
671
|
+
@data_stack.push b * a
|
672
|
+
when :great
|
673
|
+
a = @data_stack.pop
|
674
|
+
b = @data_stack.pop
|
675
|
+
@data_stack.push b > a
|
676
|
+
when :low
|
677
|
+
a = @data_stack.pop
|
678
|
+
b = @data_stack.pop
|
679
|
+
@data_stack.push b < a
|
680
|
+
when :ge
|
681
|
+
a = @data_stack.pop
|
682
|
+
b = @data_stack.pop
|
683
|
+
@data_stack.push b >= a
|
684
|
+
when :gl
|
685
|
+
a = @data_stack.pop
|
686
|
+
b = @data_stack.pop
|
687
|
+
@data_stack.push b <= a
|
688
|
+
when :equ
|
689
|
+
a = @data_stack.pop
|
690
|
+
b = @data_stack.pop
|
691
|
+
@data_stack.push b == a
|
692
|
+
when :dpush
|
693
|
+
@ip += 1
|
694
|
+
@data_stack.push @data[@prog[@ip]]
|
695
|
+
when :dpop
|
696
|
+
@ip += 1
|
697
|
+
@data[@prog[@ip]] = @data_stack.pop
|
698
|
+
when :je
|
699
|
+
a = @data_stack.pop
|
700
|
+
a = (a > 0) if a.kind_of? Fixnum or a.kind_of? Float
|
701
|
+
if a
|
702
|
+
@ip = @prog[@ip + 1]
|
703
|
+
else
|
704
|
+
@ip += 2
|
705
|
+
end
|
706
|
+
next
|
707
|
+
when :jne
|
708
|
+
a = @data_stack.pop
|
709
|
+
a = (a > 0) if a.kind_of? Fixnum or a.kind_of? Float
|
710
|
+
unless a
|
711
|
+
@ip = @prog[@ip + 1]
|
712
|
+
else
|
713
|
+
@ip += 2
|
714
|
+
end
|
715
|
+
next
|
716
|
+
when :jmp
|
717
|
+
@ip = @prog[@ip + 1]
|
718
|
+
next
|
719
|
+
when :stop
|
720
|
+
break
|
721
|
+
when :ruby
|
722
|
+
a = @data_stack.pop
|
723
|
+
begin
|
724
|
+
send(a)
|
725
|
+
rescue Exception => e
|
726
|
+
puts e
|
727
|
+
end
|
728
|
+
when :lim
|
729
|
+
@limit_stack.push @data_stack.length
|
730
|
+
when :lcp
|
731
|
+
a = @data_stack.length
|
732
|
+
b = @limit_stack.pop
|
733
|
+
result = a <= b
|
734
|
+
@limit_stack.push b unless result
|
735
|
+
@data_stack.push result
|
736
|
+
end
|
737
|
+
@ip += 1
|
738
|
+
end
|
739
|
+
end
|
740
|
+
end
|
741
|
+
|
742
|
+
def set_debug_callback(classp, mth)
|
743
|
+
@cls = classp
|
744
|
+
@mth = mth
|
745
|
+
end
|
746
|
+
end
|
747
|
+
end
|