rubimc 0.2.1 → 0.2.2
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 +12 -12
- data/bin/rubimc +14 -5
- data/lib/rubimc.rb +74 -23
- data/lib/rubimc/control_structures.rb +11 -4
- data/lib/rubimc/controllers.rb +1 -25
- data/lib/rubimc/init_var.rb +59 -53
- data/lib/rubimc/io_ports.rb +56 -27
- data/lib/rubimc/mcu/avr/attiny13.rb +19 -14
- data/lib/rubimc/mcu/avr/avr_controller.rb +1 -11
- data/lib/rubimc/preprocessor.rb +20 -41
- data/lib/rubimc/printer.rb +90 -32
- data/lib/rubimc/ruby_classes.rb +1 -1
- data/lib/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b52fe6847b85209bb0018b7afd0ebc6fcc92d0cc
|
|
4
|
+
data.tar.gz: 88e2ebaee4e861f2764b21f1458508c63894a443
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3d5e74dc243f0c55e0ea8aa6d876df15336c5027c52df64db64ee03d52a084dc6ea3d46c499b3e6b9a7ffcdf95d9940fd92250d24cca9b93bb9a7cbb600e54e2
|
|
7
|
+
data.tar.gz: 3346556ddb1be68a8da416132fbf137bbacf4db50bb846ac90b77419cec5fd52601db71498fc153628b5b2b2aa0bdb73000897b60ac980068131f994a82ef636
|
data/README.md
CHANGED
|
@@ -38,22 +38,23 @@ To install *avr-gcc* use this [manual] (http://avr-eclipse.sourceforge.net/wiki/
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
### ToDo list (main of them):
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
1. Validate code before preprocessing
|
|
42
|
+
1. Support C-libraries
|
|
43
43
|
1. Code generator:
|
|
44
44
|
+ define user`s variables as local (now it defined in top-level instance)
|
|
45
45
|
+ support all C types of variables (int ,float, unsigned int, u_int8 e.t.)
|
|
46
|
-
+
|
|
46
|
+
+ check match types (in assign and operations) and try to cast
|
|
47
|
+
+ support array, hash, string, range and constants (as full as possible)
|
|
47
48
|
+ support user`s methods and classes
|
|
48
49
|
+ support threads
|
|
49
50
|
2. Write libraries for microcontrollers (AVR, PIC, STM, e.t.)
|
|
50
51
|
3. Fix a lot of possible bugs & features
|
|
51
52
|
|
|
52
|
-
### What is done
|
|
53
|
-
1.
|
|
54
|
-
2. Support
|
|
55
|
-
3. Support conditions
|
|
56
|
-
4.
|
|
53
|
+
### What is done now
|
|
54
|
+
1. Initialize variables (supported types: bool,int,float,double)
|
|
55
|
+
2. Support most of ruby operators: arithmetic, unary, comparison, binary (need to realize logical operators: and/or/not)
|
|
56
|
+
3. Support conditions if/unless (with return values) and it modify version
|
|
57
|
+
4. Suppotr loops while/until and it modify version (except redo/retry instruction)
|
|
57
58
|
5. Realize example library for AVR AtTiny13 MCU with DigitalIO and ADC support
|
|
58
59
|
|
|
59
60
|
### Example for AVR microcontroller:
|
|
@@ -124,7 +125,7 @@ ISR(ADC_vect)
|
|
|
124
125
|
### Some rake helpers
|
|
125
126
|
For create new project RubimC gem support command "generate" (of just "g"). For example:
|
|
126
127
|
```sh
|
|
127
|
-
rubimc generate mcu
|
|
128
|
+
rubimc generate mcu BrainControll type:attiny13 # create template "BrainControll.rb" for AVR microcontroller 'attiny13'
|
|
128
129
|
rubimc g mcu FirstProg # create template "FirstProg.rb" for unknown microcontroller
|
|
129
130
|
rubimc g clearC Example # create template "Example.rb" for generate clear C code
|
|
130
131
|
```
|
|
@@ -135,8 +136,7 @@ There is interesting idea for connect few microconrollers (IC) via some firmware
|
|
|
135
136
|
```ruby
|
|
136
137
|
class BrainController < AVR_atmega16
|
|
137
138
|
def initialize()
|
|
138
|
-
input
|
|
139
|
-
# its a syntax surag of "@button = input name: 'button', port: 'A', pin: 6"
|
|
139
|
+
input :@button, port: :A, pin: 6
|
|
140
140
|
end
|
|
141
141
|
|
|
142
142
|
def main_loop() # infinit loop, it stop only when IC is reset
|
|
@@ -162,7 +162,7 @@ class LeftHandController < AVR_attiny13
|
|
|
162
162
|
end
|
|
163
163
|
|
|
164
164
|
def initialize()
|
|
165
|
-
output
|
|
165
|
+
output :@led, port: :B, pin: 3
|
|
166
166
|
end
|
|
167
167
|
|
|
168
168
|
def main_loop() # infinit loop, it stop only when IC is reset
|
data/bin/rubimc
CHANGED
|
@@ -114,7 +114,7 @@ elsif exec_type == 'compile'
|
|
|
114
114
|
end
|
|
115
115
|
|
|
116
116
|
# === check syntax of user program ===
|
|
117
|
-
print "Check syntax..."
|
|
117
|
+
print " Check syntax..."
|
|
118
118
|
sh "ruby -c '#{input_file}'", verbose: false do |ok, res|
|
|
119
119
|
exit 1 unless ok # check exit status after command runs
|
|
120
120
|
end
|
|
@@ -134,9 +134,10 @@ elsif exec_type == 'compile'
|
|
|
134
134
|
Dir.mkdir("#{release_folder}/") unless Dir.exists?("#{release_folder}/")
|
|
135
135
|
|
|
136
136
|
# === preprocessing user`s program ===
|
|
137
|
-
print "preprocessing file \"#{basename}.rb\"..."
|
|
137
|
+
print " preprocessing file \"#{basename}.rb\"..."
|
|
138
138
|
require 'rubimc/preprocessor'
|
|
139
139
|
PreProcessor.write_in_file(input_file, dirname, basename, "#{outfile}.rb")
|
|
140
|
+
print "done\n"
|
|
140
141
|
|
|
141
142
|
# === check type: gcc/avr-gcc
|
|
142
143
|
require "#{outfile}.rb"
|
|
@@ -150,7 +151,7 @@ elsif exec_type == 'compile'
|
|
|
150
151
|
mcu_type = RubimCode::Printer.mcu_type
|
|
151
152
|
|
|
152
153
|
# === execute preprocessing program, generate C code ===
|
|
153
|
-
puts "generate C code"
|
|
154
|
+
puts " generate C code"
|
|
154
155
|
sh "ruby '#{outfile}.rb' '#{outfile}'.c", verbose: false do |ok, res|
|
|
155
156
|
exit 1 unless ok # check exit status after command runs
|
|
156
157
|
end
|
|
@@ -159,7 +160,7 @@ elsif exec_type == 'compile'
|
|
|
159
160
|
# === compile C code to object-code and link to hex/exe ===
|
|
160
161
|
# ToDo: add DF_CPU (is it need?)
|
|
161
162
|
if code_type == "avr-gcc"
|
|
162
|
-
print "compile and link..."
|
|
163
|
+
print " compile and link..."
|
|
163
164
|
sh "avr-gcc -std=c99 -Os -mmcu=#{mcu_type} -c '#{outfile}.c' -o '#{outfile}.o'", verbose: false do |ok, res|
|
|
164
165
|
exit 1 unless ok # check exit status after command runs
|
|
165
166
|
end
|
|
@@ -170,7 +171,7 @@ elsif exec_type == 'compile'
|
|
|
170
171
|
puts "done"
|
|
171
172
|
|
|
172
173
|
elsif code_type == "gcc"
|
|
173
|
-
print "compile and link..."
|
|
174
|
+
print " compile and link..."
|
|
174
175
|
sh "gcc -std=c99 -o '#{outfile}.out' '#{outfile}.c'", verbose: false do |ok, res|
|
|
175
176
|
exit 1 unless ok # check exit status after command runs
|
|
176
177
|
end
|
|
@@ -183,6 +184,14 @@ elsif exec_type == 'compile'
|
|
|
183
184
|
end
|
|
184
185
|
end
|
|
185
186
|
|
|
187
|
+
# Development mode
|
|
188
|
+
elsif exec_type == "dev_compile"
|
|
189
|
+
require "#{gem_dir}/lib/version.rb"
|
|
190
|
+
puts "development mode"
|
|
191
|
+
sh "gem build rubimc.gemspec"
|
|
192
|
+
sh "gem install rubimc-#{RubimCode::VERSION}.gem"
|
|
193
|
+
sh "rubimc compile #{ARGV[1]}"
|
|
194
|
+
|
|
186
195
|
else
|
|
187
196
|
puts "ERROR: unknown command for rubimc"
|
|
188
197
|
puts "Available commands: compile; generate;"
|
data/lib/rubimc.rb
CHANGED
|
@@ -31,22 +31,41 @@ class RubimCode
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def to_i
|
|
34
|
-
|
|
34
|
+
self.name.to_i
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def to_bool
|
|
38
|
+
return true if self.name == true || self.name =~ (/(true|t|yes|y|1)$/i)
|
|
39
|
+
return false if self.name == false || self.name.blank? || self.name =~ (/(false|f|no|n|0)$/i)
|
|
40
|
+
RubimCode.perror "Can not convert variable #{self} to boolean"
|
|
35
41
|
end
|
|
36
42
|
|
|
37
43
|
def to_rubim
|
|
38
44
|
self
|
|
39
45
|
end
|
|
40
46
|
|
|
41
|
-
def c_assign=(val)
|
|
42
|
-
RubimCode.
|
|
47
|
+
def c_assign=(val)
|
|
48
|
+
RubimCode::Isolator.permit!(self)
|
|
49
|
+
RubimCode::Isolator.permit!(val)
|
|
50
|
+
|
|
51
|
+
RubimCode.perror "Undefined variable or method" if val.nil?
|
|
52
|
+
RubimCode.perror "Wrong match types" unless val.is_a? UserVariable
|
|
53
|
+
|
|
54
|
+
RubimCode.pout "#{self.name} = #{val};"
|
|
43
55
|
end
|
|
44
56
|
|
|
45
|
-
def common_operator(val, operator_sym)
|
|
57
|
+
def common_operator(val, operator_sym, **options)
|
|
46
58
|
if not val.class.respond_to? :to_s
|
|
47
59
|
RubimCode.perror "Conversion of variable #{val} is impossible. Method 'to_s' not found"
|
|
48
60
|
else
|
|
49
|
-
|
|
61
|
+
if options[:unary]
|
|
62
|
+
RubimCode::Isolator.permit!(self)
|
|
63
|
+
UserVariable.new(operator_sym.to_s[0] + self.name, 'expression')
|
|
64
|
+
else
|
|
65
|
+
RubimCode::Isolator.permit!(self)
|
|
66
|
+
RubimCode::Isolator.permit!(val)
|
|
67
|
+
UserVariable.new(self.name + operator_sym.to_s + val.to_s, 'expression')
|
|
68
|
+
end
|
|
50
69
|
end
|
|
51
70
|
end
|
|
52
71
|
|
|
@@ -62,18 +81,18 @@ class RubimCode
|
|
|
62
81
|
# ToDo: (can not override; use preprocessor)
|
|
63
82
|
|
|
64
83
|
# Unary Operators:
|
|
65
|
-
def -@;
|
|
66
|
-
def +@;
|
|
67
|
-
def !@;
|
|
68
|
-
def ~@;
|
|
84
|
+
def -@; common_operator(nil, __method__, unary: true); end
|
|
85
|
+
def +@; common_operator(nil, __method__, unary: true); end
|
|
86
|
+
def !@; common_operator(nil, __method__, unary: true); end
|
|
87
|
+
def ~@; common_operator(nil, __method__, unary: true); end
|
|
69
88
|
|
|
70
89
|
# Comparison Operators:
|
|
71
|
-
def ==(val);
|
|
72
|
-
def !=(val);
|
|
73
|
-
def <(val);
|
|
74
|
-
def >(val);
|
|
75
|
-
def <=(val);
|
|
76
|
-
def >=(val);
|
|
90
|
+
def ==(val); common_operator(val, __method__); end
|
|
91
|
+
def !=(val); common_operator(val, __method__); end
|
|
92
|
+
def <(val); common_operator(val, __method__); end
|
|
93
|
+
def >(val); common_operator(val, __method__); end
|
|
94
|
+
def <=(val); common_operator(val, __method__); end
|
|
95
|
+
def >=(val); common_operator(val, __method__); end
|
|
77
96
|
|
|
78
97
|
# Binary Operators:
|
|
79
98
|
def &(val); common_operator(val, __method__); end
|
|
@@ -88,8 +107,9 @@ class RubimCode
|
|
|
88
107
|
# Ternary Operators: (? :)
|
|
89
108
|
# ToDo...
|
|
90
109
|
|
|
91
|
-
# Ruby Parallel Assignment:
|
|
92
|
-
# a, b, c = 10, 20, 30
|
|
110
|
+
# Ruby Parallel Assignment :
|
|
111
|
+
# a, b, c = 10, 20, 30
|
|
112
|
+
# ToDo: use preprocessor: => [a, b, c].c_assing= 10, 20, 30
|
|
93
113
|
|
|
94
114
|
# ToDo: операторы, которым нет аналогов в Си
|
|
95
115
|
# def <=>(val); ??? end
|
|
@@ -110,7 +130,8 @@ class RubimCode
|
|
|
110
130
|
end
|
|
111
131
|
|
|
112
132
|
# ToDo: add mixins Enumerable and Comparable
|
|
113
|
-
|
|
133
|
+
|
|
134
|
+
end # end UserVariable class
|
|
114
135
|
|
|
115
136
|
# ToDo: в Ruby присваивание значений индексной переменной
|
|
116
137
|
# не должно влиять на выполнение цикла
|
|
@@ -126,7 +147,7 @@ class RubimCode
|
|
|
126
147
|
def to_s
|
|
127
148
|
self.name
|
|
128
149
|
end
|
|
129
|
-
end
|
|
150
|
+
end # end LoopCounter class
|
|
130
151
|
|
|
131
152
|
class UserArray < Array
|
|
132
153
|
attr_accessor :name, :type
|
|
@@ -148,7 +169,7 @@ class RubimCode
|
|
|
148
169
|
RubimCode.level -=1
|
|
149
170
|
RubimCode.pout "}"
|
|
150
171
|
end
|
|
151
|
-
end
|
|
172
|
+
end # end UserArray class
|
|
152
173
|
|
|
153
174
|
# Наследник всех пользовательских классов
|
|
154
175
|
class UserClass < UserVariable
|
|
@@ -194,7 +215,7 @@ class RubimCode
|
|
|
194
215
|
end
|
|
195
216
|
end
|
|
196
217
|
|
|
197
|
-
end
|
|
218
|
+
end # end UserClass class
|
|
198
219
|
|
|
199
220
|
# Список аппаратных прерываний (содержит Си-код в текстовом виде)
|
|
200
221
|
class Interrupts
|
|
@@ -217,7 +238,37 @@ class RubimCode
|
|
|
217
238
|
RubimCode.pout interrupt_code
|
|
218
239
|
end
|
|
219
240
|
end
|
|
220
|
-
end
|
|
241
|
+
end # end Interrupts class
|
|
242
|
+
|
|
243
|
+
class Isolator
|
|
244
|
+
class << self
|
|
245
|
+
attr_accessor :outside_binding
|
|
246
|
+
attr_accessor :local_variables
|
|
247
|
+
attr_accessor :enabled
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def self.permit!(var)
|
|
251
|
+
return unless self.enabled
|
|
252
|
+
return unless self.outside_binding
|
|
253
|
+
return unless var.is_a? UserVariable
|
|
254
|
+
return if var.type.in? ["fixed", "expression", "undefined", nil]
|
|
255
|
+
return if var.type === /^tmp/
|
|
256
|
+
|
|
257
|
+
if !local_variables.include?(var.name) and
|
|
258
|
+
outside_binding.local_variable_defined?(var.name.to_sym)
|
|
259
|
+
RubimCode.perror "Undefined variable '#{var.name}'. To pass params in interruprts use instance variables: '@#{var.name}'"
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def self.run
|
|
264
|
+
self.local_variables = []
|
|
265
|
+
self.enabled = true
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def self.stop
|
|
269
|
+
self.enabled = false
|
|
270
|
+
end
|
|
271
|
+
end # end Isolator class
|
|
221
272
|
|
|
222
273
|
class CC_ARGS # class for arguments when work with clear C-code
|
|
223
274
|
def count
|
|
@@ -227,7 +278,7 @@ class RubimCode
|
|
|
227
278
|
def [](index)
|
|
228
279
|
RubimCode::UserVariable.new("argv[#{index}]", "int")
|
|
229
280
|
end
|
|
230
|
-
end
|
|
281
|
+
end # end CC_ARGS class
|
|
231
282
|
|
|
232
283
|
end
|
|
233
284
|
# === END class RubimCode === #
|
|
@@ -3,6 +3,7 @@ class << self
|
|
|
3
3
|
|
|
4
4
|
@@rubim_defined_values = []
|
|
5
5
|
|
|
6
|
+
# instructions "if" & "unless"
|
|
6
7
|
def rubim_cond(cond, type="if", &block)
|
|
7
8
|
# ToDo: auto-define type of ret_value
|
|
8
9
|
# use:: __rubim__rval__int, __rubim__rval__float, e.t.
|
|
@@ -24,9 +25,10 @@ class << self
|
|
|
24
25
|
pout "__rubim__rval#{@level-1} = #{ret_val};" if ret_val!="__rubim__noreturn"
|
|
25
26
|
pout "}"
|
|
26
27
|
@level -= 1
|
|
27
|
-
return "__rubim__rval#{@level}"
|
|
28
|
+
return RubimCode::UserVariable.new("__rubim__rval#{@level}", 'tmp_int')
|
|
28
29
|
end
|
|
29
30
|
|
|
31
|
+
# instructions "while" & "until"
|
|
30
32
|
def rubim_cycle(type="while", cond="true", &block)
|
|
31
33
|
pout "#{type} (#{cond}) {"
|
|
32
34
|
@level+=1
|
|
@@ -35,24 +37,29 @@ class << self
|
|
|
35
37
|
@level-=1
|
|
36
38
|
end
|
|
37
39
|
|
|
40
|
+
# flat instructions
|
|
38
41
|
def rubim_if(cond, &block); rubim_cond(cond, "if", &block); end
|
|
39
42
|
def rubim_unless(cond, &block); rubim_cond(cond, "unless", &block); end
|
|
40
43
|
def rubim_while(cond, &block); rubim_cycle("while", cond, &block); end
|
|
41
44
|
def rubim_until(cond); rubim_cycle("until", cond, &block); end
|
|
42
45
|
def rubim_loop(&block); rubim_cycle("while", "true", &block); end
|
|
43
46
|
|
|
47
|
+
# modify instructions
|
|
48
|
+
def rubim_ifmod(cond); pout "if (#{cond}) {"; @level+=1; true; end
|
|
49
|
+
def rubim_unlessmod(cond); pout "if (!(#{cond})) {"; @level+=1; true; end
|
|
44
50
|
def rubim_whilemod(cond); pout "} while (#{cond});"; @level-=1; end
|
|
45
51
|
def rubim_untilmod(cond); pout "} until (#{cond});"; @level-=1; end
|
|
46
52
|
|
|
47
|
-
def rubim_ifmod(cond); pout "if (#{cond}) {"; @level+=1; true; end
|
|
48
|
-
def rubim_unlessmod(cond); pout "if (!(#{cond})) {"; @level+=1; true; end
|
|
49
53
|
def rubim_begin(); pout "{"; @level+=1; true; end
|
|
50
54
|
def rubim_end(); pout "}"; @level-=1; "__rubim__noreturn"; end
|
|
51
55
|
def rubim_tmpif(tmp); end
|
|
52
56
|
|
|
53
57
|
def rubim_else(); @level-=1; pout "} else {"; @level+=1; end
|
|
54
58
|
def rubim_elsif(cond); @level-=1; pout "} else if (#{cond}) {"; @level+=1; end
|
|
55
|
-
# ToDo: set return_val, like in rubim_if (need to change preprocessor)
|
|
59
|
+
# ToDo: in 'else' and 'elsif' set return_val, like in rubim_if (need to change preprocessor)
|
|
60
|
+
|
|
61
|
+
def rubim_next; pout "continue;" end
|
|
62
|
+
def rubim_break; pout "break;" end
|
|
56
63
|
|
|
57
64
|
end # class << self
|
|
58
65
|
end # RubimCode class
|
data/lib/rubimc/controllers.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ToDo:
|
|
1
|
+
# ToDo: rename Controllers to MCUs
|
|
2
2
|
class Controllers
|
|
3
3
|
def self.all # list of USER`s microcontrolles
|
|
4
4
|
@@controllers_array
|
|
@@ -13,30 +13,6 @@ class Controllers
|
|
|
13
13
|
false
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def self.print_cc_layout(position)
|
|
17
|
-
if position == :before_main
|
|
18
|
-
RubimCode.pout "/**************************************************************"
|
|
19
|
-
RubimCode.pout " * This code was generated by RubimC micro-framework"
|
|
20
|
-
RubimCode.pout " * RubimC version: #{RubimCode::VERSION}"
|
|
21
|
-
RubimCode.pout " * Author: Evgeny Danilov"
|
|
22
|
-
RubimCode.pout " * File created at #{Time.now}"
|
|
23
|
-
RubimCode.pout " **************************************************************/"
|
|
24
|
-
RubimCode.pout
|
|
25
|
-
RubimCode.pout "#include <stdbool.h>"
|
|
26
|
-
RubimCode.pout "#include <stdio.h>"
|
|
27
|
-
RubimCode.pout
|
|
28
|
-
yield if block_given?
|
|
29
|
-
RubimCode.pout
|
|
30
|
-
RubimCode.pout "int main(int argc, char *argv[]) {"
|
|
31
|
-
RubimCode.level += 1
|
|
32
|
-
else
|
|
33
|
-
RubimCode.pout
|
|
34
|
-
RubimCode.pout "return 1;"
|
|
35
|
-
RubimCode.level -= 1
|
|
36
|
-
RubimCode.pout "}"
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
16
|
def self.find_mcu(name)
|
|
41
17
|
series_array = Controllers.descendants
|
|
42
18
|
real_mcu_array = []
|
data/lib/rubimc/init_var.rb
CHANGED
|
@@ -2,75 +2,80 @@
|
|
|
2
2
|
# Initialize user`s variables #
|
|
3
3
|
#####################################################################
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
str_cc = "int "
|
|
11
|
-
ret_var = []
|
|
5
|
+
# type_cc - тип переменной в С-программе
|
|
6
|
+
# variables - набор инициализируемых переменных
|
|
7
|
+
def RubimCode.init_vars(type_cc, *variables)
|
|
8
|
+
vars_cc = ""
|
|
9
|
+
rubim_vars = []
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
variables.each {|var|
|
|
14
12
|
# ToDo - поиск уже объявленных переменных и выдача предупреждений
|
|
15
13
|
|
|
16
14
|
if var.is_a? Hash # ToDo
|
|
17
|
-
RubimCode.perror "Ошибка. В
|
|
15
|
+
RubimCode.perror "Ошибка. В текущей версии нельзя назначать переменным значения при объявлении"
|
|
18
16
|
# key = var.keys.first
|
|
19
17
|
# instance_variable_set("@#{key.to_s}" , UserVariable.new("#{key.to_s}"))
|
|
20
|
-
#
|
|
21
|
-
else
|
|
22
|
-
if var.to_s[0] == '@'
|
|
23
|
-
# ToDo:
|
|
24
|
-
RubimCode.perror "ToDo:"
|
|
25
|
-
elsif var.to_s[0] == '$'
|
|
26
|
-
# ToDo or delete
|
|
27
|
-
RubimCode.perror "Ошибка. В текущей версии нельзя инициализировать глобальные переменные"
|
|
28
|
-
else
|
|
29
|
-
str_cc += "#{var}, "
|
|
30
|
-
ret_var << RubimCode::UserVariable.new("#{var}", 'int')
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# if self.ancestors.include? RubimCode or self == TestController
|
|
18
|
+
# vars_cc += "#{key.to_s}=#{var[key]}, "
|
|
34
19
|
|
|
35
|
-
|
|
36
|
-
|
|
20
|
+
elsif var.is_a? Symbol
|
|
21
|
+
var_str = var.to_s
|
|
22
|
+
var_name = var_str.gsub(/^[@$]/, "")
|
|
23
|
+
new_var = RubimCode::UserVariable.new("#{var_name}", type_cc)
|
|
24
|
+
rubim_vars << new_var
|
|
37
25
|
|
|
38
|
-
|
|
39
|
-
#
|
|
40
|
-
|
|
41
|
-
#
|
|
42
|
-
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
#
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
# def #{var}=(value)
|
|
53
|
-
# pout \"\#{self.name}.#{var} = \#{value};\"
|
|
54
|
-
# end
|
|
55
|
-
# def #{var}
|
|
56
|
-
# UserVariable.new(\"\#{self.name}.#{var}\", 'int')
|
|
57
|
-
# end
|
|
58
|
-
# ")
|
|
59
|
-
# end
|
|
26
|
+
case var_str[0..1]
|
|
27
|
+
when /$./ # define GLOBAL variable
|
|
28
|
+
RubimCode.perror "Ruby-like global variables are not supported yet. Use 'integer :@#{var_name}'"
|
|
29
|
+
when /@@/ # define CLASS variable
|
|
30
|
+
RubimCode.perror "Ruby-like class variables are not supported yet. Use 'integer :@#{var_name}'"
|
|
31
|
+
when /@./ # define INSTANCE variable (in C it defined as global - outside the 'main' function)
|
|
32
|
+
RubimCode::Printer.instance_vars_cc << new_var
|
|
33
|
+
else # define LOCAL variable (in C it defined as local)
|
|
34
|
+
RubimCode::Isolator.local_variables << var_name if RubimCode::Isolator.enabled
|
|
35
|
+
vars_cc += "#{var_name}, "
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
else
|
|
39
|
+
RubimCode.perror "Unknown type of parameters for helper #{__method__}"
|
|
60
40
|
end
|
|
61
41
|
}
|
|
62
|
-
if
|
|
63
|
-
RubimCode.perror "
|
|
42
|
+
if rubim_vars.empty?
|
|
43
|
+
RubimCode.perror "No variables for initialize"
|
|
44
|
+
end
|
|
45
|
+
unless vars_cc.empty?
|
|
46
|
+
vars_cc.chomp!(", ")
|
|
47
|
+
RubimCode.pout ("#{type_cc} #{vars_cc};")
|
|
64
48
|
end
|
|
65
|
-
RubimCode.pout ("#{str_cc.chomp(', ')};")
|
|
66
49
|
|
|
67
|
-
if
|
|
68
|
-
return
|
|
50
|
+
if rubim_vars.count == 1
|
|
51
|
+
return rubim_vars[0]
|
|
69
52
|
else
|
|
70
|
-
return
|
|
53
|
+
return rubim_vars
|
|
71
54
|
end
|
|
72
55
|
end
|
|
73
56
|
|
|
57
|
+
def boolean(*variables)
|
|
58
|
+
RubimCode.init_vars("bool", *variables)
|
|
59
|
+
end
|
|
60
|
+
alias :bool :boolean
|
|
61
|
+
|
|
62
|
+
def integer(*variables)
|
|
63
|
+
RubimCode.init_vars("int", *variables)
|
|
64
|
+
end
|
|
65
|
+
alias :int :integer
|
|
66
|
+
|
|
67
|
+
def float(*variables)
|
|
68
|
+
RubimCode.init_vars("float", *variables)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def double(*variables)
|
|
72
|
+
RubimCode.init_vars("double", *variables)
|
|
73
|
+
end
|
|
74
|
+
###############################################################################
|
|
75
|
+
# NOTE! When add NEW TYPES, modify preprocessor: method 'add_binding_to_init' #
|
|
76
|
+
###############################################################################
|
|
77
|
+
|
|
78
|
+
|
|
74
79
|
def array_of_integer(var, size: nil)
|
|
75
80
|
array(var, with: {type: :integer, size: size})
|
|
76
81
|
end
|
|
@@ -85,6 +90,7 @@ def array(var, with: {type: 'UserVariable', size: nil})
|
|
|
85
90
|
|
|
86
91
|
user_class = with[:type]
|
|
87
92
|
with[:type] = 'int' if with[:type] == 'integer'
|
|
93
|
+
with[:type] = 'bool' if with[:type] == 'boolean'
|
|
88
94
|
if (with[:type].in? ['bool','int','float','double','string'])
|
|
89
95
|
user_class = "UserVariable"
|
|
90
96
|
end
|
data/lib/rubimc/io_ports.rb
CHANGED
|
@@ -1,23 +1,21 @@
|
|
|
1
|
-
def
|
|
1
|
+
def RubimCode.init_io(mcu_class, rb_type, var, port: nil, pin: nil, type: "normal")
|
|
2
2
|
if port.nil? or pin.nil?
|
|
3
3
|
RubimCode.perror "Необходимо указать порт и пин для выхода #{var}"
|
|
4
|
-
elsif not
|
|
5
|
-
RubimCode.perror "У микроконтроллера #{
|
|
6
|
-
elsif not
|
|
7
|
-
RubimCode.perror "У микроконтроллера #{
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@users__var__#{var} = RubimCode::UserOutput.new(\"#{var}\", port: port, pin: pin, type: type)
|
|
20
|
-
")
|
|
4
|
+
elsif not mcu_class::PORTS.include? port.to_sym
|
|
5
|
+
RubimCode.perror "У микроконтроллера #{mcu_class::MCU_NAME} нет порта #{port}"
|
|
6
|
+
elsif not mcu_class::PORTS[port.to_sym].include? pin.to_i
|
|
7
|
+
RubimCode.perror "У микроконтроллера #{mcu_class::MCU_NAME} нет порта пина #{pin} для порта #{port}"
|
|
8
|
+
elsif not var.is_a? Symbol
|
|
9
|
+
RubimCode.perror "Unknown type of parameters for helper #{__method__}"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
if type == "normal"
|
|
13
|
+
var_name = var.to_s.gsub(/^[@$]/, "")
|
|
14
|
+
if rb_type == 'output'
|
|
15
|
+
return RubimCode::UserOutput.new(var_name, port: port, pin: pin, type: type)
|
|
16
|
+
elsif rb_type == 'input'
|
|
17
|
+
return RubimCode::UserInput.new(var_name, port: port, pin: pin, type: type)
|
|
18
|
+
end
|
|
21
19
|
|
|
22
20
|
elsif type == "tri-state"
|
|
23
21
|
RubimCode.perror "В данный момент тип выхода 'z-state' не реализован"
|
|
@@ -27,8 +25,12 @@ def output (var, port: nil, pin: nil, type: "normal")
|
|
|
27
25
|
end
|
|
28
26
|
end
|
|
29
27
|
|
|
30
|
-
|
|
28
|
+
def output(var, port: nil, pin: nil)
|
|
29
|
+
RubimCode.init_io(self.class, 'output', var, port: port, pin: pin)
|
|
30
|
+
end
|
|
31
|
+
|
|
31
32
|
def input (var, port: nil, pin: nil)
|
|
33
|
+
RubimCode.init_io(self.class, 'input', var, port: port, pin: pin)
|
|
32
34
|
end
|
|
33
35
|
|
|
34
36
|
|
|
@@ -39,28 +41,55 @@ class RubimCode
|
|
|
39
41
|
def rubim_tbit(var, bit); "#{var} ^= 1<<#{bit};"; end
|
|
40
42
|
end # class << self
|
|
41
43
|
|
|
42
|
-
class
|
|
44
|
+
class UserIO
|
|
43
45
|
attr_accessor :name, :port, :pin, :type
|
|
44
46
|
|
|
45
47
|
def initialize(name, port: nil, pin: nil, type: "normal")
|
|
48
|
+
# ToDo: check type of params:
|
|
49
|
+
# name, port - only symbol
|
|
50
|
+
# pin - only UserVariable with type 'fixed' (feature: pin can receive also instance vars: @pin_num)
|
|
51
|
+
# type - only 'normal' (feature: realize 'tri-state' type)
|
|
46
52
|
@name = name.to_s
|
|
47
53
|
@port = port.to_s
|
|
48
|
-
@pin = pin.to_s
|
|
54
|
+
@pin = pin.name.to_s
|
|
49
55
|
@type = type.to_s
|
|
50
|
-
RubimCode.pout (RubimCode.rubim_sbit("DDR#{port}", "#{pin}"))
|
|
51
56
|
end
|
|
57
|
+
end # end UserIO class
|
|
58
|
+
|
|
59
|
+
class UserOutput < UserIO
|
|
60
|
+
def initialize(name, port: nil, pin: nil, type: "normal")
|
|
61
|
+
super
|
|
62
|
+
RubimCode.pout(RubimCode.rubim_sbit("DDR#{port}", "#{pin}") + " /* #{self.name} configure as output */ ")
|
|
63
|
+
end
|
|
64
|
+
|
|
52
65
|
|
|
53
66
|
def on
|
|
54
|
-
RubimCode.pout
|
|
67
|
+
RubimCode.pout(RubimCode.rubim_sbit("PORT#{port}", "#{pin}") + " /*#{self.name}.#{__method__}*/")
|
|
55
68
|
end
|
|
56
69
|
|
|
57
70
|
def off
|
|
58
|
-
RubimCode.pout
|
|
71
|
+
RubimCode.pout(RubimCode.rubim_cbit("PORT#{port}", "#{pin}") + " /*#{self.name}.#{__method__}*/")
|
|
59
72
|
end
|
|
60
73
|
|
|
61
74
|
def toggle
|
|
62
|
-
RubimCode.pout
|
|
75
|
+
RubimCode.pout(RubimCode.rubim_tbit("PORT#{port}", "#{pin}") + " /*#{self.name}.#{__method__}*/")
|
|
63
76
|
end
|
|
64
|
-
end
|
|
77
|
+
end # end UserInput class
|
|
78
|
+
|
|
79
|
+
class UserInput < UserIO
|
|
80
|
+
def initialize(name, port: nil, pin: nil, type: "normal")
|
|
81
|
+
super
|
|
82
|
+
RubimCode.pout(RubimCode.rubim_cbit("DDR#{port}", "#{pin}") + " /* #{self.name} configure as output */ ")
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def hi?
|
|
87
|
+
"bit_is_set(PORT#{port}, #{pin})" + " /*#{self.name}.#{__method__}*/"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def low?
|
|
91
|
+
"bit_is_clear(PORT#{port}, #{pin})" + " /*#{self.name}.#{__method__}*/"
|
|
92
|
+
end
|
|
93
|
+
end # end UserOutput class
|
|
65
94
|
|
|
66
|
-
end # RubimCode class
|
|
95
|
+
end # end RubimCode class
|
|
@@ -8,7 +8,7 @@ class AVR_attiny13 < AVRController
|
|
|
8
8
|
true
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
def
|
|
11
|
+
def mcu_layout
|
|
12
12
|
# ToDo: set F_CPU from user programm
|
|
13
13
|
RubimCode.pout "#define __AVR_ATtiny13__ 1"
|
|
14
14
|
RubimCode.pout "#define F_CPU 1000000UL" # Microcontroller frequency (Hz)
|
|
@@ -56,19 +56,19 @@ class AVR_attiny13 < AVRController
|
|
|
56
56
|
refs0 = case options[:ref] # источник опорного напряжения
|
|
57
57
|
when "vcc" then 0
|
|
58
58
|
when "internal" then 1
|
|
59
|
-
else perror "Undefined value for option :ref in method '#{__method__}'"
|
|
59
|
+
else RubimCode.perror "Undefined value for option :ref in method '#{__method__}'"
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
adlar = case "right" # options[:result_adjust] # выравнивание результата вычислений всегда по правому краю
|
|
63
63
|
when "left" then 1
|
|
64
64
|
when "right" then 0
|
|
65
|
-
else perror "Undefined value for option :result_adjust in method '#{__method__}'"
|
|
65
|
+
else RubimCode.perror "Undefined value for option :result_adjust in method '#{__method__}'"
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
channel = options[:channel]
|
|
69
69
|
unless channel.in? [ADC0, ADC1, ADC2, ADC3]
|
|
70
70
|
RubimCode.pout channel
|
|
71
|
-
perror "Undefined value for option :channel in method '#{__method__}'"
|
|
71
|
+
RubimCode.perror "Undefined value for option :channel in method '#{__method__}'"
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
RubimCode.pout("ADMUX = (#{refs0}<<REFS0) | (#{adlar}<<ADLAR) | #{channel};")
|
|
@@ -77,7 +77,7 @@ class AVR_attiny13 < AVRController
|
|
|
77
77
|
adate = case options[:auto_triggering] # одиночное преобразование или множественное
|
|
78
78
|
when "enable" then 1
|
|
79
79
|
when "disable" then 0
|
|
80
|
-
else perror "Undefined value for option :auto_triggering in method '#{__method__}'"
|
|
80
|
+
else RubimCode.perror "Undefined value for option :auto_triggering in method '#{__method__}'"
|
|
81
81
|
end
|
|
82
82
|
|
|
83
83
|
# adif = ? # ToDo: ADC Interrupt Flag
|
|
@@ -92,7 +92,7 @@ class AVR_attiny13 < AVRController
|
|
|
92
92
|
when 32 then 5
|
|
93
93
|
when 64 then 6
|
|
94
94
|
when 128 then 7
|
|
95
|
-
else perror "Undefined value for option :prescale in method '#{__method__}'"
|
|
95
|
+
else RubimCode.perror "Undefined value for option :prescale in method '#{__method__}'"
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
RubimCode.pout ("ADCSRA = (1<<ADEN) | (#{adate}<<ADATE) | (#{adps}<<ADPS0) | (#{adie}<<ADIE);")
|
|
@@ -106,7 +106,7 @@ class AVR_attiny13 < AVRController
|
|
|
106
106
|
# ToDo: должен возвращать значение, реализовать как С-функцию
|
|
107
107
|
# ToDo: можно использовать ленивую загрузку Ruby - autoload
|
|
108
108
|
unless channel.in? [ADC0, ADC1, ADC2, ADC3, nil]
|
|
109
|
-
perror "Undefined value for option :channel in method '#{__method__}'"
|
|
109
|
+
RubimCode.perror "Undefined value for option :channel in method '#{__method__}'"
|
|
110
110
|
end
|
|
111
111
|
|
|
112
112
|
unless channel.nil?
|
|
@@ -127,15 +127,16 @@ class AVR_attiny13 < AVRController
|
|
|
127
127
|
end
|
|
128
128
|
|
|
129
129
|
def self.interrupt(**options, &block)
|
|
130
|
+
|
|
130
131
|
options.permit_and_default!(enabled: false)
|
|
131
132
|
# if is_enabled && block.nil? # ToDo: проверить на наличие блока если прерывание активно
|
|
132
133
|
# perror "method #{__method__} mast have a block"
|
|
133
134
|
# end
|
|
134
135
|
|
|
135
|
-
adie = case options[:enabled] # ADC Interrupt Enable
|
|
136
|
+
adie = case options[:enabled].to_bool # ADC Interrupt Enable
|
|
136
137
|
when true then 1
|
|
137
138
|
when false then 0
|
|
138
|
-
else perror "Undefined value for option :
|
|
139
|
+
else RubimCode.perror "Undefined value for option :enabled in method '#{__method__}'"
|
|
139
140
|
end
|
|
140
141
|
if adie == 0 # if interrupt disabled
|
|
141
142
|
RubimCode.pout "Start continuously ADC convert"
|
|
@@ -146,10 +147,10 @@ class AVR_attiny13 < AVRController
|
|
|
146
147
|
# RubimCode.pout ("sei();") # automatically set (is it?)
|
|
147
148
|
end
|
|
148
149
|
|
|
149
|
-
#
|
|
150
|
+
# Generate Interrupt code
|
|
150
151
|
if block_given?
|
|
151
152
|
interrupt_code = "" # Write code in variable "interrupt_code"
|
|
152
|
-
RubimCode.pout_destination = interrupt_code
|
|
153
|
+
RubimCode::Printer.pout_destination = interrupt_code
|
|
153
154
|
old_level = RubimCode.level
|
|
154
155
|
RubimCode.level = 0
|
|
155
156
|
|
|
@@ -160,12 +161,15 @@ class AVR_attiny13 < AVRController
|
|
|
160
161
|
# ToDo - надо точно разобраться с выравниванием
|
|
161
162
|
# (see above in convert method)
|
|
162
163
|
RubimCode.pout "int __rubim__volt = ADCL + ((ADCH&0b11) << 8);"
|
|
163
|
-
|
|
164
|
+
RubimCode::Isolator.outside_binding = block.binding
|
|
165
|
+
RubimCode::Isolator.run
|
|
166
|
+
yield(RubimCode::UserVariable.new("__rubim__volt", "tmp_int"))
|
|
167
|
+
RubimCode::Isolator.stop
|
|
164
168
|
RubimCode.level -= 1
|
|
165
169
|
RubimCode.pout ("}")
|
|
166
170
|
|
|
167
171
|
RubimCode.level = old_level
|
|
168
|
-
RubimCode.pout_destination = :default
|
|
172
|
+
RubimCode::Printer.pout_destination = :default
|
|
169
173
|
RubimCode::Interrupts.add(interrupt_code)
|
|
170
174
|
end
|
|
171
175
|
end # interrupt method
|
|
@@ -173,4 +177,5 @@ class AVR_attiny13 < AVRController
|
|
|
173
177
|
end # ANALOG_TO_DIGITAL Class
|
|
174
178
|
|
|
175
179
|
|
|
176
|
-
end # RubimCode class
|
|
180
|
+
end # RubimCode class
|
|
181
|
+
|
|
@@ -1,16 +1,6 @@
|
|
|
1
1
|
class AVRController < Controllers
|
|
2
2
|
MCU_SERIES = "AVR"
|
|
3
|
-
|
|
4
|
-
def self.print_layout(position)
|
|
5
|
-
if position == :before_main
|
|
6
|
-
print_cc_layout(:before_main) do
|
|
7
|
-
micro_layout # prints includes for current microcontroller
|
|
8
|
-
end
|
|
9
|
-
elsif position == :after_main
|
|
10
|
-
print_cc_layout(:after_main)
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
3
|
end
|
|
14
4
|
|
|
15
|
-
#
|
|
5
|
+
# ToDo: add all folder 'avr'
|
|
16
6
|
require 'rubimc/mcu/avr/attiny13'
|
data/lib/rubimc/preprocessor.rb
CHANGED
|
@@ -51,7 +51,7 @@ class RubimRipper
|
|
|
51
51
|
if (ident.in? [:on_int, :on_float])
|
|
52
52
|
bug_plus = (symb[0]=="+" ? "+" : "")
|
|
53
53
|
# Note: space before "UserVariable" is neсessary
|
|
54
|
-
source = replace_words(source, symb, "#{bug_plus} RubimCode::UserVariable.new(#{symb})", pos)
|
|
54
|
+
source = replace_words(source, symb, "#{bug_plus} RubimCode::UserVariable.new(#{symb}, 'fixed')", pos)
|
|
55
55
|
end
|
|
56
56
|
end
|
|
57
57
|
return source
|
|
@@ -127,18 +127,22 @@ class RubimRipper
|
|
|
127
127
|
end
|
|
128
128
|
|
|
129
129
|
def self.replace_boolean_kw(source)
|
|
130
|
-
source = replace_keywords(source, "true", "UserVariable.new(true)")
|
|
131
|
-
source = replace_keywords(source, "false", "UserVariable.new(false)")
|
|
130
|
+
source = replace_keywords(source, "true", "RubimCode::UserVariable.new(true, 'fixed')")
|
|
131
|
+
source = replace_keywords(source, "false", "RubimCode::UserVariable.new(false, 'fixed')")
|
|
132
132
|
return source
|
|
133
133
|
end
|
|
134
134
|
|
|
135
135
|
def self.add_binding_to_init(source) # for initialize variables with methods 'integer', 'float', e.t.
|
|
136
|
+
helpers_array = ["boolean", "bool", "integer", "int", "float", "double"]
|
|
137
|
+
helpers_array += ["string"]
|
|
138
|
+
helpers_array += ["output", "input"]
|
|
139
|
+
|
|
136
140
|
sexp = Ripper.sexp(source)
|
|
137
141
|
command_array = find_rec(sexp, :command)
|
|
138
142
|
command_array.reverse_each do |elem|
|
|
139
143
|
varies_name = []
|
|
140
144
|
symb, helper_name, helper_pos = elem[1]
|
|
141
|
-
if helper_name.in?
|
|
145
|
+
if helper_name.in? helpers_array # if one of helper methods
|
|
142
146
|
args_add_block = find_rec(elem, :args_add_block)[0][1]
|
|
143
147
|
args_add_block.each do |arg|
|
|
144
148
|
if arg[0] == :symbol_literal
|
|
@@ -157,6 +161,7 @@ class RubimRipper
|
|
|
157
161
|
raise ArgumentError.new("Wrong arguments for helper '#{helper_name}'")
|
|
158
162
|
end
|
|
159
163
|
end
|
|
164
|
+
varies_name = [varies_name[0]] if helper_name.in? ['output', 'input']
|
|
160
165
|
var_str = varies_name.join(', ') # list of vars, defined in helper method
|
|
161
166
|
source = paste_before_pos(source, "#{var_str} = ", helper_pos) # paste vars before helper method
|
|
162
167
|
end
|
|
@@ -164,6 +169,12 @@ class RubimRipper
|
|
|
164
169
|
return source
|
|
165
170
|
end
|
|
166
171
|
|
|
172
|
+
def self.replace_instructions(source)
|
|
173
|
+
source = replace_keywords(source, "next", "RubimCode.rubim_next")
|
|
174
|
+
source = replace_keywords(source, "break", "RubimCode.rubim_break")
|
|
175
|
+
return source
|
|
176
|
+
end
|
|
177
|
+
|
|
167
178
|
#########################
|
|
168
179
|
# === PRIVATE SECTION ===
|
|
169
180
|
#########################
|
|
@@ -232,7 +243,7 @@ class RubimRipper
|
|
|
232
243
|
raise "can not find near position in array #{array}"
|
|
233
244
|
end
|
|
234
245
|
|
|
235
|
-
# Поиск позиции наиболее дальнего идентификатора справа
|
|
246
|
+
# Поиск позиции наиболее дальнего идентификатора справа (рекурсивно)
|
|
236
247
|
def self.find_far_pos(array)
|
|
237
248
|
array.reverse_each do |el|
|
|
238
249
|
if el.is_a? Array # если найден идентификатор, указывающий на позицию
|
|
@@ -288,10 +299,10 @@ class PreProcessor
|
|
|
288
299
|
|
|
289
300
|
def self.execute(str)
|
|
290
301
|
@@program = str
|
|
302
|
+
|
|
303
|
+
# Последовательность очень важна - не нарушать!
|
|
291
304
|
@@program = RubimRipper.replace_assing_operators(@@program)
|
|
292
305
|
@@program = RubimRipper.replace_all_numeric(@@program)
|
|
293
|
-
|
|
294
|
-
# Последовательность очень важна - не нарушать!
|
|
295
306
|
@@program = RubimRipper.replace_then_else_elsif_kw(@@program)
|
|
296
307
|
|
|
297
308
|
@@program = RubimRipper.replace_modify_express(@@program, "if")
|
|
@@ -308,47 +319,15 @@ class PreProcessor
|
|
|
308
319
|
@@program = RubimRipper.replace_rubim_tmpif(@@program)
|
|
309
320
|
|
|
310
321
|
@@program = RubimRipper.add_binding_to_init(@@program)
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
# See
|
|
316
|
-
# p defined?(x = 1) # => "assignment"
|
|
317
|
-
# p defined?(x[5] = 1) # => "method"
|
|
318
|
-
# p defined?(x[5] += 1) # => "method"
|
|
319
|
-
|
|
320
|
-
# --- OLD VERSION, BASED ON REGEXP ---
|
|
321
|
-
# убрать пробелы между всеми односимвольными операторами (кроме оператора ":")
|
|
322
|
-
# operators = "\\+\\-\\*\\/\\^\\!\\=\\~\\?\\:\\%\\|\\&"
|
|
323
|
-
# @@program.gsub!(/\ *?([#{operators}&&[^\:]])\ ?/, '\1')
|
|
324
|
-
|
|
325
|
-
# замена оператора "=" на ".c_assign=" (только перед переменными)
|
|
326
|
-
# ch = "a-zA-Z"
|
|
327
|
-
# @@program.gsub!(/(^|[^#{ch}\.])([#{ch}\d]+)=([^\=\~])/, '\1\2.c_assign=\3')
|
|
328
|
-
|
|
329
|
-
# замена всех цифр(Fixnum), после которых идут операторы, на UserVariable.new()
|
|
330
|
-
# @@program.gsub!(/(^|[^\w])([-+]?\d*\.?\d+)([#{operators}&&[^\=]])/, '\1UserVariable.new(\2)\3')
|
|
331
|
-
# замена всех цифр(Fixnum), после которых идет указание метода, на UserVariable.new()
|
|
332
|
-
# @@program.gsub!(/(^|[^\w])(\d+)(\.[\w&&[^\d]])/, '\1UserVariable.new(\2)\3')
|
|
322
|
+
@@program = RubimRipper.replace_instructions(@@program) # next/break
|
|
323
|
+
@@program = RubimRipper.replace_boolean_kw(@@program) # true/false
|
|
333
324
|
end
|
|
334
325
|
|
|
335
326
|
|
|
336
327
|
# write preprocessing program in file
|
|
337
328
|
def self.write_in_file(input_file, dirname, basename, outfile)
|
|
338
|
-
# basename = File.basename(input_file)
|
|
339
|
-
# dirname = File.dirname(input_file)
|
|
340
|
-
# outfile = "#{dirname}/release"
|
|
341
|
-
|
|
342
|
-
# # clear directory "release"
|
|
343
|
-
# Dir.mkdir(outfile) unless Dir.exists?(outfile)
|
|
344
|
-
# Dir.foreach(outfile) do |file|
|
|
345
|
-
# File.delete("#{outfile}/#{file}") if (file!='.' && file!='..')
|
|
346
|
-
# end
|
|
347
|
-
|
|
348
329
|
PreProcessor.execute( File.read(input_file) )
|
|
349
330
|
File.write("#{outfile}", PreProcessor.program)
|
|
350
|
-
|
|
351
|
-
print "done\n"
|
|
352
331
|
end
|
|
353
332
|
|
|
354
333
|
end
|
data/lib/rubimc/printer.rb
CHANGED
|
@@ -16,13 +16,11 @@ end
|
|
|
16
16
|
|
|
17
17
|
class RubimCode
|
|
18
18
|
class << self
|
|
19
|
-
|
|
20
19
|
attr_accessor :level
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@level
|
|
24
|
-
end
|
|
20
|
+
end
|
|
21
|
+
@level = 0
|
|
25
22
|
|
|
23
|
+
class << self
|
|
26
24
|
def perror(error_message)
|
|
27
25
|
if error_message.nil? or error_message.to_s.nil?
|
|
28
26
|
raise ArgumentError, "error message is not string"
|
|
@@ -32,7 +30,7 @@ class << self
|
|
|
32
30
|
code_ptr = caller_locations(2)
|
|
33
31
|
code_ptr.each do |place|
|
|
34
32
|
place = place.to_s
|
|
35
|
-
place.gsub!(
|
|
33
|
+
place.gsub!(/\/release\//, '/')
|
|
36
34
|
error_message += "\tfrom #{place}\n"
|
|
37
35
|
end
|
|
38
36
|
puts "#ERROR: #{error_message}"
|
|
@@ -47,31 +45,22 @@ class << self
|
|
|
47
45
|
else
|
|
48
46
|
@level = 0 if @level.nil?
|
|
49
47
|
res_str = " "*4*@level + str.to_s
|
|
50
|
-
if
|
|
48
|
+
if RubimCode::Printer.pout_destination.in? [:default, nil]
|
|
51
49
|
puts res_str
|
|
52
50
|
unless defined? TEST_MODE
|
|
53
51
|
File.open("#{ARGV[0]}", 'a+') {|file| file.puts(res_str) }
|
|
54
52
|
end
|
|
53
|
+
elsif RubimCode::Printer.pout_destination == :h_file
|
|
54
|
+
unless defined? TEST_MODE
|
|
55
|
+
h_name = ARGV[0].gsub(/\.c$/, '') + ".h"
|
|
56
|
+
File.open("#{h_name}", 'a+') {|file| file.puts(res_str) }
|
|
57
|
+
end
|
|
55
58
|
else
|
|
56
|
-
|
|
59
|
+
RubimCode::Printer.pout_destination.concat(res_str).concat("\n")
|
|
57
60
|
end
|
|
58
61
|
end
|
|
59
62
|
end
|
|
60
63
|
|
|
61
|
-
# ToDo: remove to RubimCode::Printer
|
|
62
|
-
$pout_destination = :default
|
|
63
|
-
def pout_destination=(dest)
|
|
64
|
-
if dest.nil?
|
|
65
|
-
perror "Wrong parameter for method #{__method__}. Set destination string"
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
if dest.class.name == "String" or dest == :default # dest.is_a? not work...WTF
|
|
69
|
-
$pout_destination = dest
|
|
70
|
-
else
|
|
71
|
-
perror "Wrong parameter for method #{__method__}. Only string variable or ':default' value is permit as a parameters"
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
64
|
def clear_c(str)
|
|
76
65
|
pout "// generate with clear_c function"
|
|
77
66
|
pout str
|
|
@@ -87,6 +76,27 @@ class RubimCode::Printer
|
|
|
87
76
|
attr_accessor :sandbox
|
|
88
77
|
end
|
|
89
78
|
|
|
79
|
+
@@instance_vars_cc = []
|
|
80
|
+
def self.instance_vars_cc
|
|
81
|
+
@@instance_vars_cc
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
@@pout_destination = :default
|
|
85
|
+
def self.pout_destination
|
|
86
|
+
@@pout_destination
|
|
87
|
+
end
|
|
88
|
+
def self.pout_destination=(dest)
|
|
89
|
+
if dest.nil?
|
|
90
|
+
perror "Wrong parameter for method #{__method__}. Set destination string"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
if dest.class.name == "String" or dest.in? [:default, :h_file] # dest.is_a?(String) not work...WTF
|
|
94
|
+
@@pout_destination = dest
|
|
95
|
+
else
|
|
96
|
+
perror "Wrong parameter for method #{__method__}. Only string variable or ':default' value is permit as a parameters"
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
90
100
|
def self.code_type
|
|
91
101
|
if not Controllers.all.empty?
|
|
92
102
|
"avr-gcc"
|
|
@@ -101,6 +111,41 @@ class RubimCode::Printer
|
|
|
101
111
|
code_type == "avr-gcc" ? Controllers.all.first::MCU_NAME : "undefined"
|
|
102
112
|
end
|
|
103
113
|
|
|
114
|
+
def self.print_layout(position, &mcu_layout)
|
|
115
|
+
return if RubimCode::Printer.sandbox == true # don`t print output in sandbox
|
|
116
|
+
h_name = File.basename(ARGV[0], '.c') + '.h'
|
|
117
|
+
if position == :before_main
|
|
118
|
+
RubimCode::Printer.pout_destination = :h_file
|
|
119
|
+
RubimCode.pout "/**************************************************************"
|
|
120
|
+
RubimCode.pout " * This code was generated by RubimC micro-framework"
|
|
121
|
+
RubimCode.pout " * Include file for \"#{ARGV[0]}\""
|
|
122
|
+
RubimCode.pout " **************************************************************/"
|
|
123
|
+
|
|
124
|
+
RubimCode::Printer.pout_destination = :default
|
|
125
|
+
RubimCode.pout "/**************************************************************"
|
|
126
|
+
RubimCode.pout " * This code was generated by RubimC micro-framework"
|
|
127
|
+
RubimCode.pout " * RubimC version: #{RubimCode::VERSION}"
|
|
128
|
+
RubimCode.pout " * RubimC author: Evgeny Danilov"
|
|
129
|
+
RubimCode.pout " * File created at #{Time.now}"
|
|
130
|
+
RubimCode.pout " **************************************************************/"
|
|
131
|
+
RubimCode.pout
|
|
132
|
+
RubimCode.pout "#include <stdbool.h>"
|
|
133
|
+
RubimCode.pout "#include <stdio.h>"
|
|
134
|
+
RubimCode.pout
|
|
135
|
+
yield if block_given? # print includes for current MCU (see mcu libraries)
|
|
136
|
+
RubimCode.pout
|
|
137
|
+
RubimCode.pout "#include \"#{h_name}\""
|
|
138
|
+
RubimCode.pout
|
|
139
|
+
RubimCode.pout "int main(int argc, char *argv[]) {"
|
|
140
|
+
RubimCode.level += 1
|
|
141
|
+
else
|
|
142
|
+
RubimCode.pout
|
|
143
|
+
RubimCode.pout "return 1;"
|
|
144
|
+
RubimCode.level -= 1
|
|
145
|
+
RubimCode.pout "}"
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
104
149
|
def self.print_main_loop
|
|
105
150
|
RubimCode.pout
|
|
106
151
|
RubimCode.pout "// === Main Infinite Loop === //"
|
|
@@ -111,25 +156,38 @@ class RubimCode::Printer
|
|
|
111
156
|
RubimCode.pout"} // end main loop"
|
|
112
157
|
end
|
|
113
158
|
|
|
159
|
+
def self.print_instance_vars
|
|
160
|
+
RubimCode::Printer.pout_destination = :h_file
|
|
161
|
+
@@instance_vars_cc.each do |var|
|
|
162
|
+
if var.is_a? RubimCode::UserVariable
|
|
163
|
+
RubimCode.pout "#{var.type} #{var.name};"
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
RubimCode::Printer.pout_destination = :default
|
|
167
|
+
end
|
|
168
|
+
|
|
114
169
|
def self.generate_cc
|
|
115
170
|
if Controllers.all.count > 1
|
|
116
171
|
RubimCode.perror "In current version in one file you can define only one Controller Class"
|
|
117
172
|
end
|
|
118
173
|
|
|
119
174
|
if self.code_type == "avr-gcc" # if compile program for MCU
|
|
120
|
-
Controllers.all.each do |
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
175
|
+
Controllers.all.each do |mcu_class|
|
|
176
|
+
print_layout(:before_main) do
|
|
177
|
+
mcu_class.mcu_layout if mcu_class.respond_to? :mcu_layout
|
|
178
|
+
end
|
|
179
|
+
mcu = mcu_class.new # print initialize section
|
|
180
|
+
print_main_loop {mcu.main_loop} # print body of main loop
|
|
181
|
+
print_layout(:after_main)
|
|
182
|
+
RubimCode::Interrupts.print()
|
|
183
|
+
RubimCode::Printer.print_instance_vars()
|
|
126
184
|
end # each Controllers.all
|
|
127
185
|
|
|
128
|
-
elsif self.code_type == "gcc" # if compile clear-C program
|
|
186
|
+
elsif self.code_type == "gcc" # if compile clear-C program
|
|
129
187
|
if Controllers.all.empty? and eval("self.private_methods.include? :main")
|
|
130
|
-
|
|
131
|
-
eval("main(RubimCode::CC_ARGS.new)") # execute method :main (CC_ARGS - helper for C agruments argc/argv)
|
|
132
|
-
|
|
188
|
+
print_layout(:before_main)
|
|
189
|
+
eval("main(RubimCode::CC_ARGS.new)") # execute user`s method :main (CC_ARGS - helper for C agruments argc/argv)
|
|
190
|
+
print_layout(:after_main)
|
|
133
191
|
end
|
|
134
192
|
end
|
|
135
193
|
end
|
data/lib/rubimc/ruby_classes.rb
CHANGED
data/lib/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubimc
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Evgeny Danilov
|
|
@@ -53,8 +53,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
53
53
|
version: '0'
|
|
54
54
|
requirements: []
|
|
55
55
|
rubyforge_project:
|
|
56
|
-
rubygems_version: 2.4.
|
|
56
|
+
rubygems_version: 2.4.8
|
|
57
57
|
signing_key:
|
|
58
58
|
specification_version: 4
|
|
59
|
-
summary: 'RubimC: Framework for MCU - 0.2.
|
|
59
|
+
summary: 'RubimC: Framework for MCU - 0.2.2'
|
|
60
60
|
test_files: []
|