-
Notifications
You must be signed in to change notification settings - Fork 0
/
Interpreter2.rb
251 lines (232 loc) · 7.89 KB
/
Interpreter2.rb
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
require 'Parser2'
# TODO: use Symbol/SymTable (generate it statically)
# TODO: make exceptions instead of throwing strings
$values = Hash::new
$arrays = Hash::new
$procs = Hash::new
module Yisiel
class ReturnException < RuntimeError; end
class ASTProg
def run
@definiciones.each do |definicion|
definicion.run
end
$globalvalues = $values
$globalarrays = $arrays
@procedimientos.each do |procedimiento|
procedimiento.run
end
@instrucciones.each do |instruccion|
instruccion.run
end
end
end
class ASTDefValue
def run
if $values.has_key? @ident or $arrays.has_key? @ident
raise "La variable #{@ident} ya está definida :-("
end
$values[@ident] = false
return
end
end
class ASTDefArray
def run
if $values.has_key? @ident or $arrays.has_key? @ident
raise "La variable #{@ident} ya está definida :-("
end
$arrays[@ident] = [false]*@size
return
end
end
class ASTStmtSet
def run
valores = @expresiones.map { |e| e.run }
@lvalues.each_with_index do |lvalue, i|
if lvalue.kind_of? ASTLValueValue
if not $values.has_key? lvalue.ident
raise "La variable #{lvalue.ident}, usada en la línea #{lvalue.line}, columna #{lvalue.col}, no está definida :-("
end
$values[lvalue.ident] = valores[i]
return
elsif lvalue.kind_of? ASTLValueArray
if not $arrays.has_key? lvalue.ident
raise "El arreglo #{lvalue.ident} no está definido :-("
end
j = lvalue.expresion.run
if 0 <= j && j < $arrays[lvalue.ident].size
$arrays[lvalue.ident][j] = valores[i]
return
end
raise "El índice #{i} no le sirve al arreglo #{lvalue.ident} :-("
end
end
end
end
class ASTStmtIf
def run
@casos.each do |caso|
if caso.predicado.run
caso.instruccion.run
return
end
end
# raise "Ningún caso sirvió :-("
end
end
class ASTStmtDo
def run
@casos.each do |caso|
if caso.predicado.run
caso.instruccion.run
redo
end
end
return
end
end
class ASTStmtBlock
def run
@instrucciones.each do |instruccion|
instruccion.run
end
return
end
end
class ASTProc
def run
if $procs.has_key? @ident
raise "El procedimiento #{@ident} ya está definido :-("
end
$procs[ident] = [@parametros, @definiciones, @instruccion]
return
end
end
class ASTStmtCall
def run
if not $procs.has_key? @ident
raise "El procedimiento #{@ident} no está definido :-("
end
tupla = $procs[@ident]
parametros = tupla[0]
definiciones = tupla[1]
instruccion = tupla[2]
if parametros.size != expresiones.size
raise "Se llamó al procedimiento #{@ident} con #{@expresiones.size} parámetros, debiendo ser #{parametros.size} :-("
end
i = 0
evaluadas = [false]*(parametros.size)
[parametros, @expresiones].transpose.each do |parametro, expresion|
if parametro.is_a? ASTParamIn
evaluadas[i] = expresion.run
end
i = i + 1
end
savedvalues = $values.clone
savedarrays = $arrays.clone
$values = $globalvalues.clone
$arrays = $globalarrays.clone
parametros.each do |parametro|
$values.delete(parametro.ident)
end
definiciones.each do |definicion|
if definicion.is_a? ASTDefValue
$values.delete(definicion.ident)
elsif definicion.is_a? ASTDefArray
$arrays.delete(definicion.ident)
end
end
i = 0
[parametros, @expresiones].transpose.each do |parametro, expresion|
if parametro.is_a? ASTParamOut
if not expresion.is_a? ASTMathDefValue
raise "El parámetro #{parametro.ident} del procedimiento #{@ident} es un parámetro de salida y debe pasársele un identificador de una variable de tipo value, pero se le pasó otra cosa al ser llamado en la línea #{@line}, columna #{col} :-("
end
ASTDefValue::new(parametro.ident, parametro.line, parametro.col).run
elsif parametro.is_a? ASTParamIn
ASTDefValue::new(parametro.ident, parametro.line, parametro.col).run
ASTStmtSet::new(
[ASTLValueValue::new(parametro.ident, parametro.line, parametro.col)],
[ASTMathNum::new(evaluadas[i])]
).run
end
i = i + 1
end
definiciones.each { |definicion| definicion.run }
begin
instruccion.run
rescue ReturnException => e
end
results = []
[parametros, @expresiones].transpose.each do |parametro, expresion|
if parametro.is_a? ASTParamOut
raise "No se asignó ningún valor al parámetro de salida #{parametro.ident} del procedimiento #{@ident} luego de ser llamado en la línea #{@line}, columna #{@col} :-(" unless $values[parametro.ident]
results << ASTStmtSet::new(
[ASTLValueValue::new(expresion.ident, expresion.line, expresion.col)],
[ASTMathNum::new($values[parametro.ident])]
)
end
end
$values = savedvalues
$arrays = savedarrays
results.each { |i| i.run }
end
end
class ASTMathSize
def run
if $arrays.has_key? @ident
return $arrays[@ident].size
end
raise "El arreglo #{@ident} no está definido :-("
end
end
class ASTMathDefValue
def run
if not $values.has_key? @ident
raise "El valor #{@ident} no está definido en la línea #{@line}, columna #{@col} :-("
end
if $values[@ident] == false
raise "El valor #{@ident} no ha sido inicializado :-("
end
return $values[@ident]
end
end
class ASTMathDefArray
def run
if not $arrays.has_key? @ident
raise "El arreglo #{@ident} no existe :-("
end
i = @expresion.run
if i < 0 && $array[@ident].size <= i
raise "El índice #{i} no le sirve al arreglo #{@ident} :-("
end
if $arrays[@ident][i] == false
raise "El valor #{@ident}[#{i}] no ha sido inicializado :-("
end
return $arrays[@ident][i]
end
end
class ASTStmtRet ; def run; raise ReturnException::new ; end; end
class ASTStmtSkip ; def run; return; end; end
class ASTStmtShowMath; def run; print @expresion.run;return; end; end
class ASTStmtShowStr ; def run; print @string ;return; end; end
class ASTMathAdd ; def run; return @lhs.run + @rhs.run; end; end
class ASTMathSub ; def run; return @lhs.run - @rhs.run; end; end
class ASTMathMod ; def run; return @lhs.run % @rhs.run; end; end
class ASTMathProd ; def run; return @lhs.run * @rhs.run; end; end
# TODO: check div by 0
class ASTMathDiv ; def run; return @lhs.run / @rhs.run; end; end
class ASTMathNum ; def run; return @numero ; end; end
class ASTMathNeg ; def run; return -@expresion.run ; end; end
class ASTBoolL ; def run; return @lhs.run < @rhs.run; end; end
class ASTBoolLE ; def run; return @lhs.run <= @rhs.run; end; end
class ASTBoolG ; def run; return @lhs.run > @rhs.run; end; end
class ASTBoolGE ; def run; return @lhs.run >= @rhs.run; end; end
class ASTBoolE ; def run; return @lhs.run == @rhs.run; end; end
class ASTBoolNE ; def run; return @lhs.run != @rhs.run; end; end
class ASTBoolAnd ; def run; return @lhs.run && @rhs.run; end; end
class ASTBoolOr ; def run; return @lhs.run || @rhs.run; end; end
class ASTBoolNot ; def run; return !@predicado.run ; end; end
class ASTBoolTrue ; def run; return true ; end; end
class ASTBoolFalse ; def run; return false ; end; end
end