source: EcnlProtoTool/trunk/asp3_dcre/tecsgen/tecslib/core/tecsgen.rb@ 321

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

文字コードを設定

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-ruby;charset=UTF-8
File size: 16.0 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# TECS Generator
4# Generator for TOPPERS Embedded Component System
5#
6# Copyright (C) 2008-2014 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 #=== import パス (-I) を末尾に追加
44 # 既に登録済みであれば、追加しない
45 def self.add_import_path path
46 if $import_path.index( path ) == nil then
47 dbgPrint "add_import_path: '#{path}'\n"
48 $import_path << path
49 end
50 end
51
52 #=== EXEB 版のパスの調整
53 # 環境変数 TECSPATH が cygwin スタイルだと、exerb 版では扱えない
54 # $import_path と $TECSPATH を調整する
55 def self.adjust_exerb_path
56 if $IN_EXERB then
57 new_tecspath = cygpath( $tecspath, $tecspath )
58 pattern = /\A#{$tecspath}/
59 paths = []
60 $import_path.each{ |path|
61 # cygpath は '..' を簡約してしまうので、new_tecspath で置換する
62 # paths << cygpath( path, path )
63 paths << path.sub( pattern, new_tecspath )
64 }
65 $import_path = paths
66 $tecspath = new_tecspath
67 else
68 return
69 end
70 end
71
72 #=== $(TECSPATH) への置換
73 #path::String : ENV[ 'TECSPATH' ] に一致する部分があれば、 "$(TECSPATH)" に置換
74 #b_global::Bool : true なら gsub で置換。false なら sub で置換
75 def self.subst_tecspath( path, b_global = false )
76 tp = $tecspath.dup
77 tp.gsub!( /\\/, "\\\\\\\\" )
78 pattern = /#{tp}/
79 substr = "$(TECSPATH)"
80 if b_global then
81 str = path.gsub( pattern, substr )
82 else
83 str = path.sub( pattern, substr )
84 end
85 dbgPrint "subst_tecspath #{path}, #{str}\n"
86 return str
87 end
88
89 #=== path は絶対パスか?
90 #path:: String :
91 # '/' または '$' で始まる場合、絶対パスと判定する
92 def self.is_absolute_path?( path )
93 pa = path[0..0]; pa2 = path[0..1]
94 if pa == '/' || pa == '$' || pa2 =~ /[A-Za-z]:/ then
95 res = true
96 else
97 res = false
98 end
99 dbgPrint "is_absolute( #{path} ) = #{res} #{path[0]}\n"
100 return res
101 end
102
103 #=== tecsgen のデフォルトを設定
104 def self.set_default_config
105 Makefile::set_default_config
106 end
107
108 ###
109 #== Makefile.templ の出力内容を追加、変更するための操作
110 module Makefile
111 # 固定されている変数(add_var で変更できない)
112 @@fixed_vars = { :INCLUDES => nil, :DEFINES => nil, :TARGET_BASE => nil, :BASE_DIR => nil }
113 @@config_mode = false
114
115 @@vars = { }
116 @@vars_default = { }
117 @@var_comments = { }
118
119 @@objs = []
120 @@ldflags = ""
121 @@search_path = []
122 @@pre_tecsgen_target = []
123 @@post_tecsgen_target = []
124 @@lines = []
125
126 #=== OTHER_OBJS に追加する
127 def self.add_obj obj
128 @@objs << obj
129 end
130 #=== 追加する変数
131 # プラグインからは、デフォルト値を変更できる
132 # config により
133 def self.add_var( var, val, comment = nil )
134 if @@fixed_vars[ var ]
135 raise "fixed var '#{var}' cannot be changed"
136 end
137 if @@config_mode then
138 @@vars_default[ var.to_sym ] = val
139 @@var_comments_default[ var.to_sym ] = comment
140 else
141 @@vars[ var.to_sym ] = val
142 @@var_comments[ var.to_sym ] = comment
143 end
144 end
145 #=== LDFLAGS に追加する
146 def self.add_ldflag ldflag
147 @@ldflags += " " + ldflag
148 end
149 #=== サーチパスを追加する
150 # CFLAGS, vpath に追加する
151 def self.add_search_path path
152 @@search_path << path
153 end
154 #=== PRE_TECSGEN_TARGET に追加する
155 # PRE_TECSGEN_TARGET に target を追加する
156 def self.add_pre_tecsgen_target target
157 @@pre_tecsgen_target << pre_tecsgen_target
158 end
159 #=== POST_TECSGEN_TARGET に追加する
160 # POST_TECSGEN_TARGET に target を追加する
161 def self.add_post_tecsgen_target target
162 @@post_tecsgen_target << pre_tecsgen_target
163 end
164 #=== 追加する変数
165 def self.add_line( line )
166 @@lines << line.to_s + "\n"
167 end
168
169 def self.get_objs # Array を返す
170 return @@objs.uniq
171 end
172 def self.get_vars # Array を返す
173 if RUBY_VERSION >= '1.9' then
174 return (@@vars.keys + @@vars_default.keys).sort.uniq
175 else
176 # V1.8 では、Symbol の sort ができないので、一旦 String に置換する
177 return (@@vars.keys + @@vars_default.keys).map{|s| s.to_s }.sort.uniq.map!{|s| s.to_sym }
178 end
179 end
180 def self.get_var_val( var )
181 return @@vars[ var ] ? @@vars[ var ] : @@vars_default[ var ]
182 end
183 def self.get_var_comment( var )
184 return @@var_comments[ var ]
185 end
186 def self.get_ldflags # String を返す
187 return @@ldflags
188 end
189 def self.get_search_path # Array を返す
190 return @@search_path.uniq
191 end
192 def self.get_pre_tecsgen_target # Array を返す
193 return @@pre_tecsgen_target.uniq
194 end
195 def self.get_post_tecsgen_target # Array を返す
196 return @@post_tecsgen_target.uniq
197 end
198 def self.get_lines # 付加する行を得る
199 return @@lines.uniq
200 end
201
202 #=== TECSGEN のデフォルト設定を行う
203 # Makefile
204 # @@fixed_vars で定義されている変数は、変更できず、定数定義されている
205 def self.set_default_config
206 add_var( "TARGET", "$(TARGET_BASE).exe", "default target name" )
207 add_var( "TECSGEN", "tecsgen", "default TECS generator" )
208 add_var( "TIMESTAMP", "$(GEN_DIR)/tecsgen.timestamp", "Time Stamp" )
209 add_var( "CC", "gcc", "default C Compiler" )
210 add_var( "CFLAGS", '$(INCLUDES) $(DEFINES) -D "Inline=static inline"', "default C Compiler options" )
211 add_var( "LD", "gcc", "default Liknker" )
212 add_var( "LDFLAGS", @@ldflags, "default Liknker Options" )
213 add_var( "SRC_DIR", "$(BASE_DIR)/src", "default source directory" )
214 add_var( "_TECS_OBJ_DIR", "$(GEN_DIR)/", "default relocatable object (.o) directory" )
215 end
216 end
217
218 #------ TECSGEN CDL analyze and generate ------#
219
220 def syntax_analisys argv
221 # ルート namespace (region) を生成
222 @root_namespace = Region.new("::")
223
224 #### 構文解析 (post コードを除く) ####
225 # すべての cdl を import する
226 argv.each{ |f|
227 dbgPrint( "## Import: #{f}\n")
228 Import.new( f, false, false )
229 }
230
231 # すべての構文解釈が完了したことの報告
232 # 実際には、後からプラグインの生成する CDL のパースが行われる
233 # エラー行数の決定方法の変更のために行う
234 Generator.end_all_parse
235 dbgPrint( "## End all parse (except Post Code)\n")
236 end # syntax_analisys
237
238 def semantics_analisys_1
239 #### 意味解析1 (post コードを除く) ####
240 dbgPrint( "## Creating reverse join \n")
241 Cell.create_reverse_join
242
243 #0 set_definition_join は2回呼び出される(1回目)
244 dbgPrint( "## Checking all join\n")
245 @root_namespace.set_definition_join
246 # @root_namespace.set_require_join ### いったん見合わせ。重複エラーを見逃す
247 # through プラグインで生成されたセルにも require も生成できる (set_definition_join の後ろで実施)
248
249 #### post コードの生成と構文解析 ####
250 # 引数がなければ、プラグインのポストコードを出力しない
251 if ARGV.length > 0 then
252 dbgPrint( "## Generating Post Code\n")
253 # プラグインのポストコードの出力と import
254 tmp_file_name = "#{$gen}/tmp_plugin_post_code.cdl"
255 file = nil
256 begin
257 file = CFile.open( tmp_file_name, "w" )
258 rescue
259 Generator.error( "G9999 fail to create #{tmp_file_name}" )
260 end
261
262 if file then
263 # through プラグインのポストコード生成
264 PluginModule.gen_plugin_post_code file
265
266 begin
267 file.close
268 rescue
269 Generator.error( "G9999 fail to close #{tmp_file_name}" )
270 end
271 dbgPrint( "## Import Post Code\n")
272 Import.new( "#{tmp_file_name}" )
273 end
274 end
275
276 #### 意味解析1 (post コード) ####
277 dbgPrint( "## Creating reverse join (for post code) \n")
278 Cell.create_reverse_join
279
280 # Join の定義の設定とチェック
281 #0 # 前方参照対応
282 #0 set_definition_join は2回呼び出される(2回目) post_code で生成された
283 dbgPrint( "## Checking all join (for cells generated by Post Code\n")
284 @root_namespace.set_definition_join
285
286 dbgPrint( "## Set require join\n")
287 @root_namespace.set_require_join # mikan post の前にも
288 # ポストコードで生成されたセルの require のjoin を生成
289 # mikan require で through が適用されて、ポストコードが必要となっても出力されない
290 end # semantics_analisys_1
291
292 def semantics_analisys_2
293 #### 意味解析2 ####
294 Cell.make_cell_list2
295 dbgPrint( "## Set fixed join\n")
296 Cell.create_reverse_require_join
297 # create_reverse_require_join は set_detinition_join に埋め込むことができない
298 # namespace に依存しない出現順で行う
299 # mikan through プラグインが適用されポストコードに影響を与える場合が考慮できていない
300 # mikan post code に影響のあるものであれば、早くに reverse_require_join の結合が必要
301 dbgPrint( "## Setting port reference count\n")
302 @root_namespace.set_port_reference_count
303
304 dbgPrint( "## Checking all join\n")
305 @root_namespace.check_join
306
307 # mikan プラグインで生成されたコンポーネントの set_def_and_check_join
308
309 dbgPrint( "## Checking referenced but undefined cell\n")
310 @root_namespace.check_ref_but_undef
311 end # semantics_analisys_2
312
313 def optimize_and_generate
314 #### Region link root ごとにオプティマイズおよび生成 ####
315 Region.get_link_roots.each { |region|
316
317 n_cells = region.get_n_cells
318
319 dbgPrint "#{region.get_name} has #{n_cells} cells\n"
320 if $verbose
321 print "=====================================\n"
322 print "=== Region.path_str: #{region.get_namespace_path.get_path_str}\n"
323 print "=====================================\n"
324 else
325 dbgPrint "Region.path_str: #{region.get_namespace_path.get_path_str}\n"
326 end
327
328 if $region_list.length > 0 then
329 if $region_list[ region.get_namespace_path.get_path_str ] then
330 $region_list[ region.get_namespace_path.get_path_str ] = false
331 else
332 next
333 end
334 end
335
336 # セルが一つもなければ生成しない
337 # セルの生成がない場合
338 if region.get_n_cells == 0 then
339 if $region_list.length > 0 then
340 Generator.warning( "W9999 $1: specified to generate but has no cell", region.get_name )
341 end
342 if region != @root_namespace then
343 next
344 end
345 end
346
347 $generating_region = region
348 if Region.get_link_roots.length > 1 then
349 if region.get_name == "::" then
350 $gen = $gen_base
351 else
352 $gen = $gen_base + "/" + region.get_global_name.to_s
353 begin
354 if ! File.directory?( $gen ) then
355 Dir.mkdir( $gen )
356 end
357 rescue
358 print( "Cannot mkdir #{$gen}\n" )
359 exit 1
360 end
361 end
362 else
363 $gen = $gen_base
364 end
365
366 dbgPrint( "## Unset optimize variables\n")
367 @root_namespace.reset_optimize # 最適化をリセットする
368
369 if Generator.get_n_error == 0 then
370 # エラーが発生していたら、設定しない
371 dbgPrint( "## Set cell id\n")
372 @root_namespace.set_cell_id_and_domain # セルの ID とドメイン情報を設定(linkunit 毎に0からつける)
373
374 # エラーが発生していたら、最適化は実施しない
375 if ! $unopt then
376 dbgPrint( "## Optimizing: Link Region=#{@root_namespace.get_name}\n")
377 @root_namespace.optimize
378 end
379 end
380
381 if $show_tree then
382 # エラーが発生していても表示(エラー発生時は最適化されていないので注意)
383 print "##### show_tree LinkRegion=#{region.get_name} #####\n"
384 @root_namespace.show_tree(0)
385 print "##### END LinkRegion=#{region.get_name} #####\n\n"
386 end
387
388 # 構文解釈、意味解析でエラー発生していたら、コード生成をしない
389 if Generator.get_n_error != 0 then
390 print_report
391 exit 1
392 end
393
394 #### コード生成 ####
395 begin
396 dbgPrint( "## Generating: Link Region=#{@root_namespace.get_name}\n")
397 @root_namespace.generate
398 dbgPrint( "## Generating Post: Link Region=#{@root_namespace.get_name}\n")
399 @root_namespace.generate_post
400 rescue
401 # 通常ここへは来ない (generate, generate_post で処置される)
402 Generator.error( "G9999 fail to generate" )
403 end
404 }
405 end # optimize_and_generate
406
407 def finalize
408 dbgPrint( "## Generating XML\n")
409 # Region.gen_xml @root_namespace
410 ##
411 # Namespace.gen_XML @root_namespace
412
413 $region_list.each{ |region_path_str, val|
414 if val == true then
415 Generator.warning( "W9999 $1: not link root, -G ignored", region_path_str )
416 end
417 }
418
419 # update する
420 # APPFile で生成されたファイルは、もし変化があれば、ここで更新する
421 # コード生成段階でエラーが発生すれば、更新しない
422 # CFile で生成されたものは、更新されている
423 if Generator.get_n_error == 0 then
424 begin
425 AppFile.update
426 rescue => evar
427 Generator.error( "G9999 Fail to update. (error occurred while renaming generated files)" )
428 print_exception( evar )
429 end
430 end
431
432 print_report
433 if Generator.get_n_error != 0 then
434 STDERR.print "error occurred while generating. some file can be corrupt in #{$gen_base}\n"
435 exit 1
436 end
437
438 open( "#{$gen_base}/tecsgen.timestamp", "w" ){|io|}
439 end # finalize
440end # class TECSGEN
Note: See TracBrowser for help on using the repository browser.