emfrp 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +45 -12
- data/bin/emfrp +4 -1
- data/examples/LCDClock/LCDClock.mfrp +93 -93
- data/examples/LCDClock/LCDClock_LPC1768.bin +0 -0
- data/examples/LCDClock/README.md +24 -24
- data/examples/LCDPositioner/LCDPositioner.mfrp +30 -30
- data/examples/LCDPositioner/LCDPositionerMain.c +15 -15
- data/examples/MostDistantPoint/MostDistantPoint.mfrp +25 -25
- data/examples/MostDistantPoint/MostDistantPointMain.c +14 -14
- data/lib/emfrp/compile/c/alloc.rb +200 -200
- data/lib/emfrp/compile/c/codegen.rb +18 -18
- data/lib/emfrp/compile/c/codegen_context.rb +218 -218
- data/lib/emfrp/compile/c/monofy.rb +185 -185
- data/lib/emfrp/compile/c/syntax_codegen.rb +364 -364
- data/lib/emfrp/compile/c/syntax_exp_codegen.rb +119 -119
- data/lib/emfrp/compile/graphviz/graphviz.rb +53 -53
- data/lib/emfrp/compile_error.rb +95 -95
- data/lib/emfrp/interpreter/command_manager.rb +367 -367
- data/lib/emfrp/interpreter/evaluater.rb +146 -146
- data/lib/emfrp/interpreter/file_loader.rb +52 -52
- data/lib/emfrp/interpreter/interpreter.rb +200 -195
- data/lib/emfrp/parser/expression.rb +386 -386
- data/lib/emfrp/parser/misc.rb +184 -184
- data/lib/emfrp/parser/newnode_convert.rb +72 -72
- data/lib/emfrp/parser/operator.rb +25 -25
- data/lib/emfrp/parser/parser.rb +150 -150
- data/lib/emfrp/parser/parsing_error.rb +49 -49
- data/lib/emfrp/parser/toplevel.rb +555 -555
- data/lib/emfrp/pre_convert/pre_convert.rb +32 -32
- data/lib/emfrp/syntax.rb +171 -171
- data/lib/emfrp/typing/typing_error.rb +47 -47
- data/lib/emfrp/typing/union_type.rb +197 -197
- data/lib/emfrp/version.rb +1 -1
- data/mfrp_include/Std.mfrp +122 -122
- data/tests/Rakefile +8 -8
- data/tests/Rakefile.common +27 -27
- data/tests/command/Rakefile +2 -2
- data/tests/command/ReplaceNode.mfrp +39 -39
- data/tests/compiler/ComplexDataType/ComplexDataType.mfrp +14 -14
- data/tests/compiler/ComplexDataType/ComplexDataTypeMain.c +15 -15
- data/tests/compiler/ComplexDataType/Rakefile +2 -2
- data/tests/compiler/ComplexDataType/expected_out.txt +0 -0
- data/tests/compiler/ComplexDataType/in.txt +5 -5
- data/tests/compiler/LCDClock/LCDClock.mfrp +90 -90
- data/tests/compiler/LCDClock/LCDClockMain.c +0 -0
- data/tests/compiler/LCDClock/Rakefile +2 -2
- data/tests/compiler/LCDClock/expected_out.txt +0 -0
- data/tests/compiler/LCDClock/in.txt +0 -0
- data/tests/compiler/LCDPositioner/LCDPositioner.mfrp +30 -30
- data/tests/compiler/LCDPositioner/LCDPositionerMain.c +15 -15
- data/tests/compiler/LCDPositioner/Rakefile +2 -2
- data/tests/compiler/LCDPositioner/graph.dot +0 -0
- data/tests/compiler/LCDPositioner/graph.png +0 -0
- data/tests/compiler/Rakefile +8 -8
- data/tests/compiler/Rakefile.common +23 -23
- data/tests/compiler/UseData/Rakefile +2 -2
- data/tests/compiler/UseData/UseData.mfrp +8 -8
- data/tests/compiler/UseSubModule/Rakefile +2 -2
- data/tests/compiler/UseSubModule/SubModule.mfrp +8 -8
- data/tests/compiler/UseSubModule/SubModule2.mfrp +5 -5
- data/tests/compiler/UseSubModule/UseSubModule.mfrp +11 -11
- data/tests/core/FromAnnotation.mfrp +18 -18
- data/tests/core/Last.mfrp +10 -10
- data/tests/core/Rakefile +2 -2
- data/tests/core/TypingTest.mfrp +11 -11
- data/tests/core/WithoutInputs.mfrp +19 -19
- data/tests/load_time_error/Rakefile +32 -32
- data/tests/load_time_error/TypeMismatch.mfrp +4 -4
- metadata +3 -3
@@ -1,218 +1,218 @@
|
|
1
|
-
module Emfrp
|
2
|
-
class CodegenContext
|
3
|
-
SymbolToStr = {
|
4
|
-
"!" => "_exclamation_",
|
5
|
-
"#" => "_hash_",
|
6
|
-
"$" => "_dollar_",
|
7
|
-
"%" => "_parcent_",
|
8
|
-
"&" => "_anpersand",
|
9
|
-
"*" => "_asterisk_",
|
10
|
-
"+" => "_plus_",
|
11
|
-
"." => "_dot_",
|
12
|
-
"/" => "_slash_",
|
13
|
-
"<" => "_lt_",
|
14
|
-
"=" => "_eq_",
|
15
|
-
">" => "_gt_",
|
16
|
-
"?" => "_question_",
|
17
|
-
"@" => "_at_",
|
18
|
-
"\\" => "_backslash_",
|
19
|
-
"^" => "_caret_",
|
20
|
-
"|" => "_vertial_",
|
21
|
-
"-" => "_minus_",
|
22
|
-
"~" => "_tilde_",
|
23
|
-
"(" => "_cpbegin_",
|
24
|
-
")" => "_cpend_",
|
25
|
-
"," => "_comma_"
|
26
|
-
}
|
27
|
-
|
28
|
-
def initialize(top)
|
29
|
-
@top = top
|
30
|
-
@global_vars = []
|
31
|
-
@funcs = []
|
32
|
-
@structs = []
|
33
|
-
@protos = []
|
34
|
-
@static_protos = []
|
35
|
-
@macros = []
|
36
|
-
@init_stmts = []
|
37
|
-
@templates = []
|
38
|
-
end
|
39
|
-
|
40
|
-
def code_generate(c_output, h_output, main_output, name)
|
41
|
-
# generate header-file
|
42
|
-
h_output << "#ifndef #{name.upcase}_H\n"
|
43
|
-
h_output << "#define #{name.upcase}_H\n\n"
|
44
|
-
@protos.each do |x|
|
45
|
-
h_output.puts x.to_s
|
46
|
-
end
|
47
|
-
h_output << "\n#endif /* end of include guard */\n"
|
48
|
-
# generate library-file
|
49
|
-
c_output.puts "#include \"#{name}.h\""
|
50
|
-
c_output.puts "/* Primitive functions (Macros) */"
|
51
|
-
@macros.each do |x|
|
52
|
-
c_output.puts x.to_s
|
53
|
-
end
|
54
|
-
c_output.puts "/* Data types */"
|
55
|
-
@structs.each do |x|
|
56
|
-
c_output.puts x.to_s
|
57
|
-
end
|
58
|
-
c_output.puts "/* Global variables */"
|
59
|
-
@global_vars.each do |x|
|
60
|
-
c_output.puts x.to_s
|
61
|
-
end
|
62
|
-
c_output.puts "/* Static prototypes */"
|
63
|
-
@static_protos.each do |x|
|
64
|
-
c_output.puts x.to_s
|
65
|
-
end
|
66
|
-
c_output.puts "/* Functions, Constructors, GCMarkers, etc... */"
|
67
|
-
@funcs.each do |x|
|
68
|
-
c_output.puts x.to_s
|
69
|
-
end
|
70
|
-
# generate main-file
|
71
|
-
main_output << "#include \"#{name}.h\"\n\n"
|
72
|
-
main_output << "void Input(#{@top[:inputs].map{|x| "#{tref(x)}* #{x[:name][:desc]}"}.join(", ")}) {\n /* Your code goes here... */\n}\n"
|
73
|
-
main_output << "void Output(#{@top[:outputs].map{|x| "#{tref(x)}* #{x[:name][:desc]}"}.join(", ")}) {\n /* Your code goes here... */\n}\n"
|
74
|
-
main_output << "int main() {\n Activate#{@top[:module_name][:desc]}();\n}\n"
|
75
|
-
end
|
76
|
-
|
77
|
-
def init_stmts
|
78
|
-
@init_stmts
|
79
|
-
end
|
80
|
-
|
81
|
-
def func_name(name, ret_utype, arg_utypes)
|
82
|
-
case f = @top[:dict][:func_space][name].get
|
83
|
-
when PrimFuncDef
|
84
|
-
f.func_name(self)
|
85
|
-
when FuncDef
|
86
|
-
key = [ret_utype, *arg_utypes].map(&:to_uniq_str) + [name]
|
87
|
-
@top[:dict][:ifunc_space][key].get.func_name(self)
|
88
|
-
else
|
89
|
-
raise "Assertion error: unexpected func type #{f.class}"
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def constructor_name(name, utype)
|
94
|
-
@top[:dict][:itype_space][utype.to_uniq_str].get[:tvalues].each do |tval|
|
95
|
-
if tval[:name][:desc] == name
|
96
|
-
return tval.constructor_name(self)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
raise "Assertion error: #{name} is not found"
|
100
|
-
end
|
101
|
-
|
102
|
-
def escape_name(name)
|
103
|
-
rexp = Regexp.new("[" + Regexp.escape(SymbolToStr.keys.join) + "]")
|
104
|
-
name.gsub(rexp, SymbolToStr)
|
105
|
-
end
|
106
|
-
|
107
|
-
def tdef(x)
|
108
|
-
case x
|
109
|
-
when Typing::UnionType
|
110
|
-
key = x.to_uniq_str
|
111
|
-
if @top[:dict][:type_space][key] && @top[:dict][:type_space][key].get.is_a?(PrimTypeDef)
|
112
|
-
@top[:dict][:type_space][key].get
|
113
|
-
elsif @top[:dict][:itype_space][key]
|
114
|
-
@top[:dict][:itype_space][key].get
|
115
|
-
else
|
116
|
-
raise "Assertion error: itype #{x.to_uniq_str} is undefined"
|
117
|
-
end
|
118
|
-
when Syntax
|
119
|
-
tdef(x[:typing])
|
120
|
-
else
|
121
|
-
raise "Assertion error"
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def tref(x)
|
126
|
-
tdef(x).ref_name(self)
|
127
|
-
end
|
128
|
-
|
129
|
-
def serial(key, id)
|
130
|
-
@serials ||= Hash.new{|h, k| h[k] = []}
|
131
|
-
@serials[key] << id unless @serials[key].find{|x| x == id}
|
132
|
-
return @serials[key].index{|x| x == id}
|
133
|
-
end
|
134
|
-
|
135
|
-
def uniq_id_gen
|
136
|
-
@uniq_ids ||= (0..1000).to_a
|
137
|
-
@uniq_ids.shift
|
138
|
-
end
|
139
|
-
|
140
|
-
def define_global_var(type_str, name_str, initial_value_str=nil)
|
141
|
-
@global_vars << "#{type_str} #{name_str}" + (initial_value_str ? " = #{initial_value_str}" : "") + ";"
|
142
|
-
end
|
143
|
-
|
144
|
-
def define_macro(name_str, params, body_str)
|
145
|
-
@macros << "#define #{name_str}(#{params.join(", ")}) (#{body_str})"
|
146
|
-
end
|
147
|
-
|
148
|
-
def define_func(type_str, name_str, params, accessor=:static, with_proto=true, &block)
|
149
|
-
elements = []
|
150
|
-
proc.call(elements)
|
151
|
-
case accessor
|
152
|
-
when :none then deco = ""
|
153
|
-
when :static then deco = "static "
|
154
|
-
end
|
155
|
-
define_proto(type_str, name_str, params.map(&:first), accessor) if with_proto
|
156
|
-
@funcs << Block.new("#{deco}#{type_str} #{name_str}(#{params.map{|a, b| "#{a} #{b}"}.join(", ")}) {", elements, "}")
|
157
|
-
return nil
|
158
|
-
end
|
159
|
-
|
160
|
-
def define_proto(type_str, name_str, param_types, accessor=:static)
|
161
|
-
case accessor
|
162
|
-
when :none then deco = ""
|
163
|
-
when :static then deco = "static "
|
164
|
-
when :extern then deco = "extern "
|
165
|
-
end
|
166
|
-
proto = "#{deco}#{type_str} #{name_str}(#{param_types.join(", ")});"
|
167
|
-
if accessor == :static || accessor == :extern
|
168
|
-
@static_protos << proto
|
169
|
-
else
|
170
|
-
@protos << proto
|
171
|
-
end
|
172
|
-
return nil
|
173
|
-
end
|
174
|
-
|
175
|
-
def define_init_stmt(stmt)
|
176
|
-
@init_stmts << stmt
|
177
|
-
end
|
178
|
-
|
179
|
-
def define_struct(kind_str, name_str, var_name_str)
|
180
|
-
elements = []
|
181
|
-
proc.call(elements)
|
182
|
-
x = Block.new("#{kind_str} #{name_str}{", elements, "}#{var_name_str};")
|
183
|
-
if name_str
|
184
|
-
@structs << x
|
185
|
-
return nil
|
186
|
-
else
|
187
|
-
return x
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
def make_block(head_str, elements, foot_str)
|
192
|
-
Block.new(head_str, elements, foot_str)
|
193
|
-
end
|
194
|
-
|
195
|
-
class Block
|
196
|
-
T = (0..20).map{|i| " " * i}
|
197
|
-
def initialize(head_str, elements, foot_str)
|
198
|
-
@head_str = head_str
|
199
|
-
@elements = elements
|
200
|
-
@foot_str = foot_str
|
201
|
-
end
|
202
|
-
|
203
|
-
def to_s(t=0)
|
204
|
-
res = ""
|
205
|
-
res << T[t] + @head_str + "\n"
|
206
|
-
@elements.each do |e|
|
207
|
-
case e
|
208
|
-
when Block
|
209
|
-
res << e.to_s(t+1) + "\n"
|
210
|
-
when String
|
211
|
-
res << T[t+1] + e + "\n"
|
212
|
-
end
|
213
|
-
end
|
214
|
-
res << T[t] + @foot_str
|
215
|
-
end
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|
1
|
+
module Emfrp
|
2
|
+
class CodegenContext
|
3
|
+
SymbolToStr = {
|
4
|
+
"!" => "_exclamation_",
|
5
|
+
"#" => "_hash_",
|
6
|
+
"$" => "_dollar_",
|
7
|
+
"%" => "_parcent_",
|
8
|
+
"&" => "_anpersand",
|
9
|
+
"*" => "_asterisk_",
|
10
|
+
"+" => "_plus_",
|
11
|
+
"." => "_dot_",
|
12
|
+
"/" => "_slash_",
|
13
|
+
"<" => "_lt_",
|
14
|
+
"=" => "_eq_",
|
15
|
+
">" => "_gt_",
|
16
|
+
"?" => "_question_",
|
17
|
+
"@" => "_at_",
|
18
|
+
"\\" => "_backslash_",
|
19
|
+
"^" => "_caret_",
|
20
|
+
"|" => "_vertial_",
|
21
|
+
"-" => "_minus_",
|
22
|
+
"~" => "_tilde_",
|
23
|
+
"(" => "_cpbegin_",
|
24
|
+
")" => "_cpend_",
|
25
|
+
"," => "_comma_"
|
26
|
+
}
|
27
|
+
|
28
|
+
def initialize(top)
|
29
|
+
@top = top
|
30
|
+
@global_vars = []
|
31
|
+
@funcs = []
|
32
|
+
@structs = []
|
33
|
+
@protos = []
|
34
|
+
@static_protos = []
|
35
|
+
@macros = []
|
36
|
+
@init_stmts = []
|
37
|
+
@templates = []
|
38
|
+
end
|
39
|
+
|
40
|
+
def code_generate(c_output, h_output, main_output, name)
|
41
|
+
# generate header-file
|
42
|
+
h_output << "#ifndef #{name.upcase}_H\n"
|
43
|
+
h_output << "#define #{name.upcase}_H\n\n"
|
44
|
+
@protos.each do |x|
|
45
|
+
h_output.puts x.to_s
|
46
|
+
end
|
47
|
+
h_output << "\n#endif /* end of include guard */\n"
|
48
|
+
# generate library-file
|
49
|
+
c_output.puts "#include \"#{name}.h\""
|
50
|
+
c_output.puts "/* Primitive functions (Macros) */"
|
51
|
+
@macros.each do |x|
|
52
|
+
c_output.puts x.to_s
|
53
|
+
end
|
54
|
+
c_output.puts "/* Data types */"
|
55
|
+
@structs.each do |x|
|
56
|
+
c_output.puts x.to_s
|
57
|
+
end
|
58
|
+
c_output.puts "/* Global variables */"
|
59
|
+
@global_vars.each do |x|
|
60
|
+
c_output.puts x.to_s
|
61
|
+
end
|
62
|
+
c_output.puts "/* Static prototypes */"
|
63
|
+
@static_protos.each do |x|
|
64
|
+
c_output.puts x.to_s
|
65
|
+
end
|
66
|
+
c_output.puts "/* Functions, Constructors, GCMarkers, etc... */"
|
67
|
+
@funcs.each do |x|
|
68
|
+
c_output.puts x.to_s
|
69
|
+
end
|
70
|
+
# generate main-file
|
71
|
+
main_output << "#include \"#{name}.h\"\n\n"
|
72
|
+
main_output << "void Input(#{@top[:inputs].map{|x| "#{tref(x)}* #{x[:name][:desc]}"}.join(", ")}) {\n /* Your code goes here... */\n}\n"
|
73
|
+
main_output << "void Output(#{@top[:outputs].map{|x| "#{tref(x)}* #{x[:name][:desc]}"}.join(", ")}) {\n /* Your code goes here... */\n}\n"
|
74
|
+
main_output << "int main() {\n Activate#{@top[:module_name][:desc]}();\n}\n"
|
75
|
+
end
|
76
|
+
|
77
|
+
def init_stmts
|
78
|
+
@init_stmts
|
79
|
+
end
|
80
|
+
|
81
|
+
def func_name(name, ret_utype, arg_utypes)
|
82
|
+
case f = @top[:dict][:func_space][name].get
|
83
|
+
when PrimFuncDef
|
84
|
+
f.func_name(self)
|
85
|
+
when FuncDef
|
86
|
+
key = [ret_utype, *arg_utypes].map(&:to_uniq_str) + [name]
|
87
|
+
@top[:dict][:ifunc_space][key].get.func_name(self)
|
88
|
+
else
|
89
|
+
raise "Assertion error: unexpected func type #{f.class}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def constructor_name(name, utype)
|
94
|
+
@top[:dict][:itype_space][utype.to_uniq_str].get[:tvalues].each do |tval|
|
95
|
+
if tval[:name][:desc] == name
|
96
|
+
return tval.constructor_name(self)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
raise "Assertion error: #{name} is not found"
|
100
|
+
end
|
101
|
+
|
102
|
+
def escape_name(name)
|
103
|
+
rexp = Regexp.new("[" + Regexp.escape(SymbolToStr.keys.join) + "]")
|
104
|
+
name.gsub(rexp, SymbolToStr)
|
105
|
+
end
|
106
|
+
|
107
|
+
def tdef(x)
|
108
|
+
case x
|
109
|
+
when Typing::UnionType
|
110
|
+
key = x.to_uniq_str
|
111
|
+
if @top[:dict][:type_space][key] && @top[:dict][:type_space][key].get.is_a?(PrimTypeDef)
|
112
|
+
@top[:dict][:type_space][key].get
|
113
|
+
elsif @top[:dict][:itype_space][key]
|
114
|
+
@top[:dict][:itype_space][key].get
|
115
|
+
else
|
116
|
+
raise "Assertion error: itype #{x.to_uniq_str} is undefined"
|
117
|
+
end
|
118
|
+
when Syntax
|
119
|
+
tdef(x[:typing])
|
120
|
+
else
|
121
|
+
raise "Assertion error"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def tref(x)
|
126
|
+
tdef(x).ref_name(self)
|
127
|
+
end
|
128
|
+
|
129
|
+
def serial(key, id)
|
130
|
+
@serials ||= Hash.new{|h, k| h[k] = []}
|
131
|
+
@serials[key] << id unless @serials[key].find{|x| x == id}
|
132
|
+
return @serials[key].index{|x| x == id}
|
133
|
+
end
|
134
|
+
|
135
|
+
def uniq_id_gen
|
136
|
+
@uniq_ids ||= (0..1000).to_a
|
137
|
+
@uniq_ids.shift
|
138
|
+
end
|
139
|
+
|
140
|
+
def define_global_var(type_str, name_str, initial_value_str=nil)
|
141
|
+
@global_vars << "#{type_str} #{name_str}" + (initial_value_str ? " = #{initial_value_str}" : "") + ";"
|
142
|
+
end
|
143
|
+
|
144
|
+
def define_macro(name_str, params, body_str)
|
145
|
+
@macros << "#define #{name_str}(#{params.join(", ")}) (#{body_str})"
|
146
|
+
end
|
147
|
+
|
148
|
+
def define_func(type_str, name_str, params, accessor=:static, with_proto=true, &block)
|
149
|
+
elements = []
|
150
|
+
proc.call(elements)
|
151
|
+
case accessor
|
152
|
+
when :none then deco = ""
|
153
|
+
when :static then deco = "static "
|
154
|
+
end
|
155
|
+
define_proto(type_str, name_str, params.map(&:first), accessor) if with_proto
|
156
|
+
@funcs << Block.new("#{deco}#{type_str} #{name_str}(#{params.map{|a, b| "#{a} #{b}"}.join(", ")}) {", elements, "}")
|
157
|
+
return nil
|
158
|
+
end
|
159
|
+
|
160
|
+
def define_proto(type_str, name_str, param_types, accessor=:static)
|
161
|
+
case accessor
|
162
|
+
when :none then deco = ""
|
163
|
+
when :static then deco = "static "
|
164
|
+
when :extern then deco = "extern "
|
165
|
+
end
|
166
|
+
proto = "#{deco}#{type_str} #{name_str}(#{param_types.join(", ")});"
|
167
|
+
if accessor == :static || accessor == :extern
|
168
|
+
@static_protos << proto
|
169
|
+
else
|
170
|
+
@protos << proto
|
171
|
+
end
|
172
|
+
return nil
|
173
|
+
end
|
174
|
+
|
175
|
+
def define_init_stmt(stmt)
|
176
|
+
@init_stmts << stmt
|
177
|
+
end
|
178
|
+
|
179
|
+
def define_struct(kind_str, name_str, var_name_str)
|
180
|
+
elements = []
|
181
|
+
proc.call(elements)
|
182
|
+
x = Block.new("#{kind_str} #{name_str}{", elements, "}#{var_name_str};")
|
183
|
+
if name_str
|
184
|
+
@structs << x
|
185
|
+
return nil
|
186
|
+
else
|
187
|
+
return x
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def make_block(head_str, elements, foot_str)
|
192
|
+
Block.new(head_str, elements, foot_str)
|
193
|
+
end
|
194
|
+
|
195
|
+
class Block
|
196
|
+
T = (0..20).map{|i| " " * i}
|
197
|
+
def initialize(head_str, elements, foot_str)
|
198
|
+
@head_str = head_str
|
199
|
+
@elements = elements
|
200
|
+
@foot_str = foot_str
|
201
|
+
end
|
202
|
+
|
203
|
+
def to_s(t=0)
|
204
|
+
res = ""
|
205
|
+
res << T[t] + @head_str + "\n"
|
206
|
+
@elements.each do |e|
|
207
|
+
case e
|
208
|
+
when Block
|
209
|
+
res << e.to_s(t+1) + "\n"
|
210
|
+
when String
|
211
|
+
res << T[t+1] + e + "\n"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
res << T[t] + @foot_str
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|