source: azure_iot_hub/trunk/asp3_dcre/tecsgen/tecslib/core/tecsgen.rb@ 389

Last change on this file since 389 was 389, checked in by coas-nagasima, 5 years ago

ビルドが通るよう更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-ruby;charset=UTF-8
File size: 19.0 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# TECS Generator
4# Generator for TOPPERS Embedded Component System
5#
6# Copyright (C) 2008-2017 by TOPPERS Project
7#--
8# 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
9# ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
10# 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
11# (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
12# 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
13# スコード中に含まれていること.
14# (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
15# 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
16# 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
17# の無保証規定を掲載すること.
18# (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
19# 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
20# と.
21# (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
22# 作権表示,この利用条件および下記の無保証規定を掲載すること.
23# (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
24# 報告すること.
25# (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
26# 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
27# また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
28# 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
29# 免責すること.
30#
31# 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
32# よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
33# に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
34# アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
35# の責任を負わない.
36#
37# $Id$
38#++
39
40
41class TECSGEN
42
43 @@b_post_coded = false # ポストコード生成開始後 true
44
45 #=== import パス (-I) を末尾に追加
46 # 既に登録済みであれば、追加しない
47 def self.add_import_path path
48 if $import_path.index( path ) == nil then
49 dbgPrint "add_import_path: '#{path}'\n"
50 $import_path << path
51 end
52 end
53
54 #=== EXEB 版のパスの調整
55 # 環境変数 TECSPATH が cygwin スタイルだと、exerb 版では扱えない
56 # $import_path と $TECSPATH を調整する
57 def self.adjust_exerb_path
58 if $IN_EXERB then
59 new_tecspath = cygpath( $tecspath, $tecspath )
60 pattern = /\A#{$tecspath}/
61 paths = []
62 $import_path.each{ |path|
63 # cygpath は '..' を簡約してしまうので、new_tecspath で置換する
64 # paths << cygpath( path, path )
65 paths << path.sub( pattern, new_tecspath )
66 }
67 $import_path = paths
68 $tecspath = new_tecspath
69 else
70 return
71 end
72 end
73
74 #=== $(TECSPATH) への置換
75 #path::String : ENV[ 'TECSPATH' ] に一致する部分があれば、 "$(TECSPATH)" に置換
76 #b_global::Bool : true なら gsub で置換。false なら sub で置換
77 def self.subst_tecspath( path, b_global = false )
78 tp = $tecspath.dup
79 tp.gsub!( /\\/, "\\\\\\\\" )
80 pattern = /#{tp}/
81 substr = "$(TECSPATH)"
82 if b_global then
83 str = path.gsub( pattern, substr )
84 else
85 str = path.sub( pattern, substr )
86 end
87 dbgPrint "subst_tecspath #{path}, #{str}\n"
88 return str
89 end
90
91 #=== path は絶対パスか?
92 #path:: String :
93 # '/' または '$' で始まる場合、絶対パスと判定する
94 def self.is_absolute_path?( path )
95 pa = path[0..0]; pa2 = path[0..1]
96 if pa == '/' || pa == '$' || pa2 =~ /[A-Za-z]:/ then
97 res = true
98 else
99 res = false
100 end
101 dbgPrint "is_absolute( #{path} ) = #{res} #{path[0]}\n"
102 return res
103 end
104
105 #=== tecsgen のデフォルトを設定
106 def self.set_default_config
107 Makefile::set_default_config
108 end
109
110 ###
111 #== Makefile.templ の出力内容を追加、変更するための操作
112 module Makefile
113 # 固定されている変数(add_var で変更できない)
114 @@fixed_vars = { :INCLUDES => nil, :DEFINES => nil, :TARGET_BASE => nil, :BASE_DIR => nil }
115 @@config_mode = false
116
117 @@vars = { }
118 @@vars_default = { }
119 @@var_comments = { }
120
121 @@objs = []
122 @@ldflags = ""
123 @@search_path = []
124 @@pre_tecsgen_target = []
125 @@post_tecsgen_target = []
126 @@lines = []
127
128 #=== OTHER_OBJS に追加する
129 def self.add_obj obj
130 @@objs << obj
131 end
132 #=== 追加する変数
133 # プラグインからは、デフォルト値を変更できる
134 # config により
135 def self.add_var( var, val, comment = nil )
136 if @@fixed_vars[ var ]
137 raise "fixed var '#{var}' cannot be changed"
138 end
139 if @@config_mode then
140 @@vars_default[ var.to_sym ] = val
141 @@var_comments_default[ var.to_sym ] = comment
142 else
143 @@vars[ var.to_sym ] = val
144 @@var_comments[ var.to_sym ] = comment
145 end
146 end
147 #=== LDFLAGS に追加する
148 def self.add_ldflag ldflag
149 @@ldflags += " " + ldflag
150 end
151 #=== サーチパスを追加する
152 # CFLAGS, vpath に追加する
153 def self.add_search_path path
154 @@search_path << path
155 end
156 #=== PRE_TECSGEN_TARGET に追加する
157 # PRE_TECSGEN_TARGET に target を追加する
158 def self.add_pre_tecsgen_target target
159 @@pre_tecsgen_target << pre_tecsgen_target
160 end
161 #=== POST_TECSGEN_TARGET に追加する
162 # POST_TECSGEN_TARGET に target を追加する
163 def self.add_post_tecsgen_target target
164 @@post_tecsgen_target << pre_tecsgen_target
165 end
166 #=== 追加する変数
167 def self.add_line( line )
168 @@lines << line.to_s + "\n"
169 end
170
171 def self.get_objs # Array を返す
172 return @@objs.uniq
173 end
174 def self.get_vars # Array を返す
175 if RUBY_VERSION >= '1.9' then
176 return (@@vars.keys + @@vars_default.keys).sort.uniq
177 else
178 # V1.8 では、Symbol の sort ができないので、一旦 String に置換する
179 return (@@vars.keys + @@vars_default.keys).map{|s| s.to_s }.sort.uniq.map!{|s| s.to_sym }
180 end
181 end
182 def self.get_var_val( var )
183 return @@vars[ var ] ? @@vars[ var ] : @@vars_default[ var ]
184 end
185 def self.get_var_comment( var )
186 return @@var_comments[ var ]
187 end
188 def self.get_ldflags # String を返す
189 return @@ldflags
190 end
191 def self.get_search_path # Array を返す
192 return @@search_path.uniq
193 end
194 def self.get_pre_tecsgen_target # Array を返す
195 return @@pre_tecsgen_target.uniq
196 end
197 def self.get_post_tecsgen_target # Array を返す
198 return @@post_tecsgen_target.uniq
199 end
200 def self.get_lines # 付加する行を得る
201 return @@lines.uniq
202 end
203
204 #=== TECSGEN のデフォルト設定を行う
205 # Makefile
206 # @@fixed_vars で定義されている変数は、変更できず、定数定義されている
207 def self.set_default_config
208 add_var( "TARGET", "$(TARGET_BASE).exe", "default target name" )
209 add_var( "TECSGEN", "tecsgen", "default TECS generator" )
210 add_var( "TIMESTAMP", "$(GEN_DIR)/tecsgen.timestamp", "Time Stamp" )
211 add_var( "CC", "gcc", "default C Compiler" )
212 add_var( "CFLAGS", '$(INCLUDES) $(DEFINES) -D "Inline=static inline"', "default C Compiler options" )
213 add_var( "LD", "gcc", "default Liknker" )
214 add_var( "LDFLAGS", @@ldflags, "default Liknker Options" )
215 add_var( "SRC_DIR", "$(BASE_DIR)/src", "default source directory" )
216 add_var( "_TECS_OBJ_DIR", "$(GEN_DIR)/", "default relocatable object (.o) directory" )
217 end
218 end
219
220 def self.get_argv
221 ARGV
222 end
223
224 #------ TECSGEN CDL analyze and generate ------#
225
226 def syntax_analisys argv
227 # ルート namespace (region) を生成
228 @root_namespace = Region.new("::")
229
230 #### 構文解析 (post コードを除く) ####
231 # すべての cdl を import する
232 argv.each{ |f|
233 dbgPrint( "## Import: #{f}\n")
234 Import.new( f, false, false )
235 }
236
237 # すべての構文解釈が完了したことの報告
238 # 実際には、後からプラグインの生成する CDL のパースが行われる
239 # エラー行数の決定方法の変更のために行う
240 Generator.end_all_parse
241 dbgPrint( "## End all parse (except Post Code)\n")
242 end # syntax_analisys
243
244 #=== TECSGEN#semantics_analisys_1
245 # semantics check. only cells here
246 # other objects (signature, celltype, typedef, etc ) are checked while syntax analisys
247 def semantics_analisys_1
248 #### 意味解析1 (post コードを除く) ####
249 dbgPrint( "## Creating reverse join \n")
250 Cell.create_reverse_join
251
252 DescriptorType.check_signature
253 Signature.set_descriptor_list
254 Celltype.check_dynamic_join
255
256 #0 set_definition_join は2回呼び出される(1回目)
257 dbgPrint( "## Checking all join\n")
258 @root_namespace.set_definition_join
259 # @root_namespace.set_require_join ### いったん見合わせ。重複エラーを見逃す
260 # through プラグインで生成されたセルにも require も生成できる (set_definition_join の後ろで実施)
261
262 #### post コードの生成と構文解析 ####
263 @@b_post_coded = true # ポストコード生成開始後 true
264 # 引数がなければ、プラグインのポストコードを出力しない
265 if ARGV.length > 0 then
266 dbgPrint( "## Generating Post Code\n")
267 # プラグインのポストコードの出力と import
268 tmp_file_name = "#{$gen}/tmp_plugin_post_code.cdl"
269 file = nil
270 begin
271 file = CFile.open( tmp_file_name, "w" )
272 rescue
273 Generator.error( "G9999 fail to create #{tmp_file_name}" )
274 end
275
276 if file then
277 # through プラグインのポストコード生成
278 PluginModule.gen_plugin_post_code file
279
280 begin
281 file.close
282 rescue
283 Generator.error( "G9999 fail to close #{tmp_file_name}" )
284 end
285 dbgPrint( "## Import Post Code\n")
286 Import.new( "#{tmp_file_name}" )
287 end
288 end
289
290 #### 意味解析1 (post コード) ####
291 dbgPrint( "## Creating reverse join (for post code) \n")
292 Cell.create_reverse_join
293
294 # Join の定義の設定とチェック
295 #0 # 前方参照対応
296 #0 set_definition_join は2回呼び出される(2回目) post_code で生成された
297 dbgPrint( "## Checking all join (for cells generated by Post Code\n")
298 @root_namespace.set_definition_join
299 @root_namespace.set_max_entry_port_inner_cell
300
301 dbgPrint( "## Set require join\n")
302 @root_namespace.set_require_join # mikan post の前にも
303 # ポストコードで生成されたセルの require のjoin を生成
304 # mikan require で through が適用されて、ポストコードが必要となっても出力されない
305 end # semantics_analisys_1
306
307 def semantics_analisys_2
308 #### 意味解析2 ####
309 Cell.make_cell_list2
310 dbgPrint( "## Set fixed join\n")
311 Cell.create_reverse_require_join
312 # create_reverse_require_join は set_detinition_join に埋め込むことができない
313 # namespace に依存しない出現順で行う
314 # mikan through プラグインが適用されポストコードに影響を与える場合が考慮できていない
315 # mikan post code に影響のあるものであれば、早くに reverse_require_join の結合が必要
316 dbgPrint( "## Setting port reference count\n")
317 @root_namespace.set_port_reference_count
318
319 dbgPrint( "## Checking all join\n")
320 @root_namespace.check_join
321
322 # mikan プラグインで生成されたコンポーネントの set_def_and_check_join
323
324 dbgPrint( "## Checking referenced but undefined cell\n")
325 @root_namespace.check_ref_but_undef
326 end # semantics_analisys_2
327
328 def optimize_and_generate
329 #### Region link root ごとにオプティマイズおよび生成 ####
330 Region.get_link_roots.each { |region|
331
332 n_cells = region.get_n_cells
333
334 dbgPrint "#{region.get_name} has #{n_cells} cells\n"
335 if $verbose
336 print "=====================================\n"
337 print "=== Region.path_str: #{region.get_namespace_path.get_path_str}\n"
338 print "=====================================\n"
339 else
340 dbgPrint "Region.path_str: #{region.get_namespace_path.get_path_str}\n"
341 end
342
343 if $region_list.length > 0 then
344 if $region_list[ region.get_namespace_path.get_path_str ] then
345 $region_list[ region.get_namespace_path.get_path_str ] = false
346 else
347 next
348 end
349 end
350
351 # セルが一つもなければ生成しない
352 # セルの生成がない場合
353 if region.get_n_cells == 0 then
354 if $region_list.length > 0 then
355 Generator.warning( "W9999 $1: specified to generate but has no cell", region.get_name )
356 end
357 if region != @root_namespace then
358 next
359 end
360 end
361
362 $generating_region = region
363 if Region.get_link_roots.length > 1 then
364 if region.get_name == "::" then
365 $gen = $gen_base
366 else
367 $gen = $gen_base + "/" + region.get_global_name.to_s
368 begin
369 if ! File.directory?( $gen ) then
370 Dir.mkdir( $gen )
371 end
372 rescue
373 print( "Cannot mkdir #{$gen}\n" )
374 exit 1
375 end
376 end
377 else
378 $gen = $gen_base
379 end
380
381 dbgPrint( "## Unset optimize variables\n")
382 @root_namespace.reset_optimize # 最適化をリセットする
383
384 if Generator.get_n_error == 0 then
385 # エラーが発生していたら、設定しない
386 dbgPrint( "## Set cell id\n")
387 @root_namespace.set_cell_id_and_domain # セルの ID とドメイン情報を設定(linkunit 毎に0からつける)
388
389 # エラーが発生していたら、最適化は実施しない
390 if ! $unopt then
391 dbgPrint( "## Optimizing: Link Region=#{@root_namespace.get_name}\n")
392 @root_namespace.optimize
393 end
394 end
395
396 if $show_tree then
397 # エラーが発生していても表示(エラー発生時は最適化されていないので注意)
398 print "##### show_tree LinkRegion=#{region.get_name} #####\n"
399 @root_namespace.show_tree(0)
400 print "##### END LinkRegion=#{region.get_name} #####\n\n"
401 end
402
403 # 構文解釈、意味解析でエラー発生していたら、コード生成をしない
404 if Generator.get_n_error != 0 then
405 print_report
406 exit 1
407 end
408
409 #### コード生成 ####
410 begin
411 dbgPrint( "## Generating: Link Region=#{@root_namespace.get_name}\n")
412 @root_namespace.generate
413 dbgPrint( "## Generating Post: Link Region=#{@root_namespace.get_name}\n")
414 @root_namespace.generate_post
415 rescue
416 # 通常ここへは来ない (generate, generate_post で処置される)
417 Generator.error( "G9999 fail to generate" )
418 end
419 }
420 end # optimize_and_generate
421
422 def finalize
423 dbgPrint( "## Generating XML\n")
424 # Region.gen_xml @root_namespace
425 ##
426 # Namespace.gen_XML @root_namespace
427
428 $region_list.each{ |region_path_str, val|
429 if val == true then
430 Generator.warning( "W9999 $1: not link root, -G ignored", region_path_str )
431 end
432 }
433
434 # update する
435 # APPFile で生成されたファイルは、もし変化があれば、ここで更新する
436 # コード生成段階でエラーが発生すれば、更新しない
437 # CFile で生成されたものは、更新されている
438 if Generator.get_n_error == 0 then
439 begin
440 AppFile.update
441 rescue => evar
442 Generator.error( "G9999 Fail to update. (error occurred while renaming generated files)" )
443 print_exception( evar )
444 end
445 end
446
447 print_report
448 if Generator.get_n_error != 0 then
449 STDERR.print "error occurred while generating. some file can be corrupt in #{$gen_base}\n"
450 exit 1
451 end
452
453 open( "#{$gen_base}/tecsgen.timestamp", "w" ){|io|}
454 end # finalize
455
456 def dump_tecsgen_rbdmp
457 dbgPrint "dump_tecsgen_rbdmp 0:\n"
458 #### unjoin_plugin 後に行う必要があるため、コード生成後にダンプを行う
459 #### Region link root ごとにオプティマイズしてダンプ ####
460 Namespace.get_root.unjoin_plugin
461 Namespace.get_root.find_plugin 0, []
462
463 Region.get_link_roots.each { |region|
464 dbgPrint "dump_tecsgen_rbdmp 1: Region.path_str: #{region.get_namespace_path.get_path_str}\n"
465
466 n_cells = region.get_n_cells
467
468 if $region_list.length > 0 then
469 if $region_list[ region.get_namespace_path.get_path_str ] == false then
470 $region_list[ region.get_namespace_path.get_path_str ] = true
471 else
472 next
473 end
474 end
475
476 dbgPrint "dump_tecsgen_rbdmp 2: Region.path_str: #{region.get_namespace_path.get_path_str}\n"
477 # セルが一つもなければ生成しない
478 # セルの生成がない場合
479 if region.get_n_cells == 0 then
480 # if $region_list.length > 0 then
481 # Generator.warning( "W9999 $1: specified to generate but has no cell", region.get_name )
482 # end
483 if region != @root_namespace then
484 next
485 end
486 end
487
488 dbgPrint "dump_tecsgen_rbdmp 3: Region.path_str: #{region.get_namespace_path.get_path_str}\n"
489 $generating_region = region
490 if Region.get_link_roots.length > 1 then
491 if region.get_name == "::" then
492 $gen = $gen_base
493 else
494 $gen = $gen_base + "/" + region.get_global_name.to_s
495 end
496 else
497 $gen = $gen_base
498 end
499
500 dbgPrint "dump_tecsgen_rbdmp 4: Region.path_str: #{region.get_namespace_path.get_path_str}\n"
501 dbgPrint( "## Unset optimize variables\n")
502 @root_namespace.reset_optimize # 最適化をリセットする
503
504 # if Generator.get_n_error == 0 then
505 # # エラーが発生していたら、ここへは来ない
506 dbgPrint( "## Set cell id\n")
507 @root_namespace.set_cell_id_and_domain # セルの ID とドメイン情報を設定(linkunit 毎に0からつける)
508
509 # エラーが発生していたら、最適化は実施しない
510 if ! $unopt then
511 dbgPrint( "## Optimizing: Link Region=#{@root_namespace.get_name}\n")
512 @root_namespace.optimize
513 end
514 # end
515 dbgPrint "dump_tecsgen_rbdmp final: Region.path_str: #{region.get_namespace_path.get_path_str}\n"
516 File.write( "#{$gen}/tecsgen.rbdmp", Marshal.dump(Namespace.get_root) )
517 }
518 end
519
520 def self.post_coded?
521 @@b_post_coded
522 end
523end # class TECSGEN
Note: See TracBrowser for help on using the repository browser.