source: asp3_wo_tecs/trunk/cfg/pass1.rb@ 304

Last change on this file since 304 was 304, checked in by ertl-honda, 7 years ago

コンフィギュレータをruby版に変更

File size: 19.4 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# TOPPERS Configurator by Ruby
4#
5# Copyright (C) 2015 by FUJI SOFT INCORPORATED, JAPAN
6# Copyright (C) 2015,2016 by Embedded and Real-Time Systems Laboratory
7# Graduate School of Information Science, Nagoya Univ., JAPAN
8#
9# 上記著作権者
10は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
11# ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
12# 変・再é…
13å¸ƒï¼ˆä»¥ä¸‹ï¼Œåˆ©ç”¨ã¨å‘¼ã¶ï¼‰ã™ã‚‹ã“とを無償で許諾する.
14# (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
15# 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
16# スコード中に含まれていること.
17# (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
18# 用できる形で再é…
19å¸ƒã™ã‚‹å ´åˆã«ã¯ï¼Œå†é…
20å¸ƒã«ä¼´ã†ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆï¼ˆåˆ©ç”¨
21# 者
22マニュアルなど)に,上記の著作権表示,この利用条件および下記
23# の無保証規定を掲載すること.
24# (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
25# 用できない形で再é…
26å¸ƒã™ã‚‹å ´åˆã«ã¯ï¼Œæ¬¡ã®ã„ずれかの条件を満たすこ
27# と.
28# (a) 再é…
29å¸ƒã«ä¼´ã†ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆï¼ˆåˆ©ç”¨è€…
30マニュアルなど)に,上記の著
31# 作権表示,この利用条件および下記の無保証規定を掲載すること.
32# (b) 再é…
33å¸ƒã®å½¢æ…
34‹ã‚’,別に定める方法によって,TOPPERSプロジェクトに
35# 報告すること.
36# (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
37# 害からも,上記著作権者
38およびTOPPERSプロジェクトをå…
39è²¬ã™ã‚‹ã“と.
40# また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
41# 由に基づく請求からも,上記著作権者
42およびTOPPERSプロジェクトを
43# å…
44è²¬ã™ã‚‹ã“と.
45#
46# 本ソフトウェアは,無保証で提供されているものである.上記著作権者
47お
48# よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
49# に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
50# アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
51# の責任を負わない.
52#
53# $Id: pass1.rb 32 2016-01-31 14:45:59Z ertl-hiro $
54#
55
56#
57# パス1の処理
58#
59
60#
61# 値取得シンボルテーブルへの固定登録
62#
63$symbolValueTable = {
64 "CHAR_BIT" => { :EXPR => "CHAR_BIT" },
65 "SCHAR_MAX" => { :EXPR => "SCHAR_MAX", :SIGNED => true },
66 "SCHAR_MIN" => { :EXPR => "SCHAR_MIN", :SIGNED => true },
67 "UCHAR_MAX" => { :EXPR => "UCHAR_MAX" },
68 "CHAR_MAX" => { :EXPR => "CHAR_MAX", :SIGNED => true },
69 "CHAR_MIN" => { :EXPR => "CHAR_MIN", :SIGNED => true },
70 "SHRT_MAX" => { :EXPR => "SHRT_MAX", :SIGNED => true },
71 "SHRT_MIN" => { :EXPR => "SHRT_MIN", :SIGNED => true },
72 "USHRT_MAX" => { :EXPR => "USHRT_MAX" },
73 "INT_MAX" => { :EXPR => "INT_MAX", :SIGNED => true },
74 "INT_MIN" => { :EXPR => "INT_MIN", :SIGNED => true },
75 "UINT_MAX" => { :EXPR => "UINT_MAX" },
76 "LONG_MAX" => { :EXPR => "LONG_MAX", :SIGNED => true },
77 "LONG_MIN" => { :EXPR => "LONG_MIN", :SIGNED => true },
78 "ULONG_MAX" => { :EXPR => "ULONG_MAX" }
79}
80
81#
82# 静的APIテーブルへの固定登録
83#
84$apiDefinition = { "INCLUDE" =>
85 { :PARAM => [ { :NAME => :file, :STRING => true }]}}
86
87#
88# 静的APIテーブルの読み込み
89#
90def ReadApiTableFile
91 $apiTableFileNames.each do |apiTableFileName|
92 if !File.exist?(apiTableFileName)
93 error_exit("`#{apiTableFileName}' not found")
94 next
95 end
96
97 apiFile = File.open(apiTableFileName)
98 apiFile.each do |line|
99 next if /^#/ =~ line # コメントをスキップ
100
101 fields = line.split(/\s+/)
102 staticApi = fields.shift
103 apiDef = { :API => staticApi }
104 apiParams = []
105 fields.each do |param|
106 case param
107 when /^(\W*)(\w+)(\W*)$/
108 prefix = $1
109 name = $2
110 postfix = $3
111 apiParam = { :NAME => name }
112
113 case prefix
114 when "#" # オブジェクト識別名(定義)
115 apiParam[:ID_DEF] = true
116 when "%" # オブジェクト識別名(参ç…
117§ï¼‰
118 apiParam[:ID_REF] = true
119 when "." # 符号無し整数定数式パラメータ
120 apiParam[:UNSIGNED] = true
121 when "+" # 符号付き整数定数式パラメータ
122 apiParam[:SIGNED] = true
123 when "&" # 一般整数定数式パラメータ
124 # do nothing
125 when "$" # 文字列定数式パラメータ
126 apiParam[:STRING] = true
127 else
128 error_exit("`#{param}' is invalid")
129 end
130
131 case postfix
132 when "*" # キーを決めるパラメータ
133 apiDef[:KEYPAR] = name
134 when "?" # オプションパラメータ
135 apiParam[:OPTIONAL] = true
136 when "\.\.\." # リストパラメータ
137 apiParam[:LIST] = true
138 end
139
140 when /^([{}])$/ # {と}
141 apiParam = { :BRACE => $1 }
142
143 else
144 error_exit("`#{param}' is invalid")
145 end
146 apiParams.push(apiParam)
147 end
148 apiDef[:PARAM] = apiParams
149 $apiDefinition[staticApi] = apiDef
150 end
151 apiFile.close
152 end
153end
154
155#
156# 値取得シンボルテーブルの読み込み
157#
158def ReadSymvalTable
159 $symvalTableFileNames.each do |symvalTableFileName|
160 if !File.exist?(symvalTableFileName)
161 error_exit("`#{symvalTableFileName}' not found")
162 next
163 end
164
165 symvalCsv = CSV.open(symvalTableFileName)
166 symvalCsv.each do |record|
167 # 変数名
168 if record[0].nil?
169 error_exit("invalid variable name in `#{fileName}'")
170 end
171
172 symbol = {}
173 variable = record[0]
174
175 # 式
176 if record[1].nil? || record[1] == ""
177 symbol[:EXPR] = variable
178 else
179 symbol[:EXPR] = record[1]
180 end
181
182 # 符号フラグ
183 if !(record[2].nil? || record[2] == "" || /^[uU]/ =~ record[2])
184 symbol[:SIGNED] = true
185 end
186
187 # コンパイル条件
188 symbol[:CONDITION] = record[3]
189
190 # コンパイル条件が満たされない時のデフォルト値
191 symbol[:DEFAULT] = record[4]
192
193 $symbolValueTable[variable] = symbol
194 end
195 symvalCsv.close
196 end
197end
198
199#
200# システムコンフィギュレーションファイルからの読み込みクラス
201#
202class ConfigFile
203 def initialize(fileName)
204 @cfgFileName = fileName
205 begin
206 @cfgFile = File.open(@cfgFileName)
207 rescue Errno::ENOENT, Errno::EACCES => ex
208 abort(ex.message)
209 end
210 @lineNo = 0
211 @withinComment = false
212 end
213
214 def close
215 @cfgFile.close
216 end
217
218 def getNextLine(withinApi)
219 line = @cfgFile.gets
220 return nil if line.nil?
221 @lineNo += 1
222
223 line.chomp!
224 if @withinComment
225 case line
226 when /\*\// # C言語スタイルのコメント終了
227 line.sub!(/^.*?\*\//, "") # 最初の*/にマッチさせる */
228 @withinComment = false
229 else
230 line = ""
231 end
232 end
233 if !@withinComment
234 line.gsub!(/\/\*.*?\*\//, "") # C言語スタイルのコメントの除去
235 # 最初の*/にマッチさせる */
236 case line
237 when /^\s*#/ # プリプロセッサディレクティブ
238 if withinApi
239 parse_error(self, \
240 "preprocessor directive must not be within static API")
241 line = ""
242 end
243 when /\/\*/ # C言語スタイルのコメント開始
244 line.sub!(/\/\*.*$/, "")
245 @withinComment = true
246 when /\/\// # C++言語スタイルのコメント
247 line.sub!(/\/\/.*$/, "")
248 end
249 end
250 return(line)
251 end
252
253 def getFileName
254 return(@cfgFileName)
255 end
256
257 def getLineNo
258 return(@lineNo)
259 end
260end
261
262#
263# システムコンフィギュレーションファイルのパーサークラス
264#
265class CfgParser
266 @@lastApiIndex = 0
267
268 def initialize
269 @line = ""
270 @skipComma = false # 次が,であれば読み飛ばす
271 end
272
273 #
274 # 文字列末まで読む
275 #
276 def parseString(cfgFile)
277 string = ""
278 begin
279 case @line
280 when /^([^"]*\\\\)(.*)$/ # \\まで読む
281 string += $1
282 @line = $2
283 when /^([^"]*\\\")(.*)$/ # \"まで読む
284 string += $1
285 @line = $2
286 when /^([^"]*\")(.*)$/ # "まで読む
287 string += $1
288 @line = $2
289 return(string)
290 else # 行末まで読む
291 string += @line + "\n"
292 @line = cfgFile.getNextLine(true)
293 end
294 end while (@line)
295 error_exit("unterminated string meets end-of-file")
296 return(string)
297 end
298
299 #
300 # 文字末まで読む
301 #
302 def parseChar(cfgFile)
303 string = ""
304 begin
305 case @line
306 when /^([^']*\\\\)(.*)$/ # \\まで読む
307 string += $1
308 @line = $2
309 when /^([^']*\\\')(.*)$/ # \'まで読む
310 string += $1
311 @line = $2
312 when /^([^']*\')(.*)$/ # 'まで読む
313 string += $1
314 @line = $2
315 return(string)
316 else # 行末まで読む
317 string += @line + "\n"
318 @line = cfgFile.getNextLine(true)
319 end
320 end while (@line)
321 error_exit("unterminated string meets end-of-file")
322 return(string)
323 end
324
325 #
326 # パラメータを1つ読む
327 #
328 # @lineのå…
329ˆé ­ã‹ã‚‰ãƒ‘ラメータを1つ読んで,それを文字列で返す.読んだパ
330 # ラメータは,@lineからは削除する.パラメータの途中で行末に達した時は,
331 # cfgFileから次の行を取り出す.ファイル末に達した時は,nilを返す.
332 #
333 def parseParam(cfgFile)
334 param = "" # 読んだ文字列
335 parenLevel = 0 # 括弧のネストレベル
336
337 skipComma = @skipComma
338 @skipComma = false
339
340 @line.lstrip! # å…
341ˆé ­ã®ç©ºç™½ã‚’削除
342 while @line == "" # 空行を読み飛ばす
343 @line = cfgFile.getNextLine(true)
344 return nil if @line.nil? # ファイル末であればリターン
345 @line.lstrip! # å…
346ˆé ­ã®ç©ºç™½ã‚’削除
347 end
348
349 begin
350 if parenLevel == 0
351 case @line
352 when /^(\s*,)(.*)$/ # ,
353 @line = $2
354 if param == "" && skipComma
355 skipComma = false
356 return(parseParam(cfgFile)) # 再帰呼び出し
357 else
358 return(param)
359 end
360 when /^(\s*{)(.*)$/ # {
361 if param != ""
362 return(param)
363 else
364 @line = $2
365 return("{")
366 end
367 when /^(\s*\()(.*)$/ # (
368 param += $1
369 @line = $2
370 parenLevel += 1
371 when /^(\s*([)}]))(.*)$/ # }か)
372 if param != ""
373 return(param)
374 else
375 @line = $3
376 @skipComma = true if $2 == "}"
377 return($2)
378 end
379 when /^(\s*\")(.*)$/ # "
380 @line = $2
381 param += $1 + parseString(cfgFile)
382 when /^(\s*\')(.*)$/ # '
383 @line = $2
384 param += $1 + parseChar(cfgFile)
385 when /^(\s*[^,{}()"'\s]+)(.*)$/ # その他の文字列
386 param += $1
387 @line = $2
388 else # 行末
389 param += "\n"
390 @line = cfgFile.getNextLine(true)
391 end
392 else
393 # 括弧内
394の処理
395 case @line
396 when /^(\s*\()(.*)$/ # "("
397 param += $1
398 @line = $2
399 parenLevel += 1
400 when /^(\s*\))(.*)$/ # ")"
401 param += $1
402 @line = $2
403 parenLevel -= 1
404 when /^(\s*\")(.*)$/ # "
405 @line = $2
406 param += $1 + parseString(cfgFile)
407 when /^(\s*\')(.*)$/ # '
408 @line = $2
409 param += $1 + parseChar(cfgFile)
410 when /^(\s*[^()"'\s]+)(.*)$/ # その他の文字列
411 param += $1
412 @line = $2
413 else # 行末
414 param += "\n"
415 @line = cfgFile.getNextLine(true)
416 end
417 end
418 end while (@line)
419 return(param)
420 end
421
422 def parseApi(cfgFile)
423 # 静的APIの読み込み
424 staticApi = {}
425 if (/^([A-Z_]+)\s*\((.*)$/ =~ @line)
426 apiName = $1
427 @line = $2
428
429 if $apiDefinition.has_key?(apiName)
430 staticApi[:API] = apiName
431 staticApi[:_FILE_] = cfgFile.getFileName
432 staticApi[:_LINE_] = cfgFile.getLineNo
433 apiDef = $apiDefinition[apiName]
434 param = parseParam(cfgFile)
435
436 apiDef[:PARAM].each do |apiParam|
437 if param.nil? # ファイル末であればリターン
438 error_exit("unexpexced end-of-file")
439 return(staticApi)
440 end
441 if apiParam.has_key?(:BRACE)
442 if param != apiParam[:BRACE]
443 parse_error(cfgFile, "'#{apiParam[:BRACE]}' expected")
444 end
445 param = parseParam(cfgFile)
446 elsif apiParam.has_key?(:LIST)
447 staticApi[apiParam[:NAME]] = []
448 while /^([{})])$/ !~ param
449 if apiParam.has_key?(:STRING)
450 staticApi[apiParam[:NAME]].push(param.unquote)
451 else
452 staticApi[apiParam[:NAME]].push(param)
453 end
454 param = parseParam(cfgFile)
455 end
456 elsif /^([{}])$/ =~ param
457 if !apiParam.has_key?(:OPTIONAL)
458 parse_error(cfgFile, "#{$1} unexpected")
459 end
460 else
461 if apiParam.has_key?(:STRING)
462 staticApi[apiParam[:NAME]] = param.unquote
463 else
464 staticApi[apiParam[:NAME]] = param
465 end
466 param = parseParam(cfgFile)
467 end
468 end
469 if param != ")"
470 parse_error(cfgFile, "')' expected")
471 end
472 else
473 parse_error(cfgFile, "unknown static API: #{apiName}")
474 end
475 else
476 parse_error(cfgFile, "syntax error: #{@line}")
477 end
478 @line = ""
479 return(staticApi)
480 end
481
482 def parseFile(cfgFileName)
483 cfgFiles = [ ConfigFile.new(cfgFileName) ]
484 @line = ""
485 begin
486 cfgFile = cfgFiles.last
487 while @line == "" # 空行を読み飛ばす
488 @line = cfgFile.getNextLine(false)
489 @line.sub!(/^[\s;]*/, "") unless @line.nil? # å…
490ˆé ­ã®ç©ºç™½ã¨";"を削除
491 end
492
493 if @line.nil?
494 # ファイル末の処理
495 cfgFiles.pop.close
496 if cfgFiles.empty?
497 break # パース処理終了
498 else
499 @line = ""
500 next # å…
501ƒã®ãƒ•ã‚¡ã‚¤ãƒ«ã«æˆ»ã£ã¦ç¶šã‘ã‚‹
502 end
503 end
504
505 if /^#/ =~ @line
506 # プリプロセッサディレクティブを読む
507 case @line
508 when /^#include\b(.*)$/
509 $includeFiles.push($1.strip)
510 when /^#(ifdef|ifndef|if|endif|else|elif)\b/
511 directive = {:DIRECTIVE => @line.strip}
512 $cfgFileInfo.push(directive)
513 else
514 parse_error(cfgFile, "unknown preprocessor directive: #{@line}")
515 end
516 @line = ""
517 else
518 # 静的APIを1つ読む
519 staticApi = parseApi(cfgFile)
520 if staticApi.empty?
521 # 文法エラー
522 elsif (staticApi[:API] == "INCLUDE")
523 # INCLUDEの処理
524 includeFilePath = SearchFilePath(staticApi[:file])
525 if includeFilePath.nil?
526 parse_error(cfgFile, "`#{staticApi["file"]}' not found")
527 else
528 $dependencyFiles.push(includeFilePath)
529 cfgFiles.push(ConfigFile.new(includeFilePath))
530 end
531 else
532 # 静的APIの処理
533 staticApi[:INDEX] = (@@lastApiIndex += 1)
534 $cfgFileInfo.push(staticApi)
535 end
536 end
537 end while true
538 end
539end
540
541#
542# cfg1_out.cの生成
543#
544def GenerateCfg1OutC
545 cfg1Out = GenFile.new(CFG1_OUT_C)
546
547 cfg1Out.append(<<EOS)
548/* #{CFG1_OUT_C} */
549#define TOPPERS_CFG1_OUT
550#include "kernel/kernel_int.h"
551EOS
552
553 # インクルードヘッダファイル
554 $includeFiles.each do |file|
555 cfg1Out.add("#include #{file}")
556 end
557
558 cfg1Out.append(<<EOS)
559
560#ifdef INT64_MAX
561 typedef int64_t signed_t;
562 typedef uint64_t unsigned_t;
563#else
564 typedef int32_t signed_t;
565 typedef uint32_t unsigned_t;
566#endif
567
568#include "target_cfg1_out.h"
569#include <limits.h>
570
571const uint32_t #{CFG1_MAGIC_NUM} = 0x12345678;
572const uint32_t #{CFG1_SIZEOF_SIGNED} = sizeof(signed_t);
573
574EOS
575
576 # 値取得シンボルの処理
577 $symbolValueTable.each do |symbolName, symbolData|
578 type = symbolData.has_key?(:SIGNED) ? "signed_t" : "unsigned_t"
579 if !symbolData[:CONDITION].nil?
580 cfg1Out.add("#if #{symbolData[:CONDITION]}")
581 end
582 cfg1Out.add("const #{type} #{CFG1_PREFIX}#{symbolName} = " \
583 "(#{type})(#{symbolData[:EXPR]});")
584 if !symbolData[:DEFAULT].nil?
585 cfg1Out.add("#else")
586 cfg1Out.add("const #{type} #{CFG1_PREFIX}#{symbolName} = " \
587 "(#{type})(#{symbolData[:DEFAULT]});")
588 end
589 if !symbolData[:CONDITION].nil?
590 cfg1Out.add("#endif")
591 end
592 end
593
594 # 静的API/プリプロセッサディレクティブの処理
595 $cfgFileInfo.each do |cfgInfo|
596 if cfgInfo.has_key?(:DIRECTIVE)
597 cfg1Out.add2(cfgInfo[:DIRECTIVE])
598 else
599 apiDef = $apiDefinition[cfgInfo[:API]]
600 apiIndex = cfgInfo[:INDEX]
601 cfg1Out.add("#line #{cfgInfo[:_LINE_]} \"#{cfgInfo[:_FILE_]}\"")
602 cfg1Out.add("const unsigned_t #{CFG1_PREFIX}static_api_" \
603 "#{apiIndex} = #{apiIndex};")
604 apiDef[:PARAM].each do |apiParam|
605 if apiParam.has_key?(:ID_DEF)
606 cfg1Out.add("#define #{cfgInfo[apiParam[:NAME]]}\t(<>)")
607 elsif (apiParam.has_key?(:SIGNED) || apiParam.has_key?(:UNSIGNED)) \
608 && !cfgInfo[apiParam[:NAME]].nil?
609 type = apiParam.has_key?(:SIGNED) ? "signed_t" : "unsigned_t"
610 cfg1Out.add("#line #{cfgInfo[:_LINE_]} \"#{cfgInfo[:_FILE_]}\"")
611 cfg1Out.add("const #{type} #{CFG1_PREFIX}valueof_" \
612 "#{apiParam[:NAME]}_#{apiIndex} = " \
613 "(#{type})(#{cfgInfo[apiParam[:NAME]]});")
614 end
615 end
616 cfg1Out.add
617 end
618 end
619end
620
621#
622# パス1の処理
623#
624def Pass1
625 #
626 # タイムスタンプファイルの指定
627 #
628 $timeStampFileName = CFG1_OUT_TIMESTAMP
629
630 #
631 # 静的APIテーブルの読み込み
632 #
633 ReadApiTableFile()
634
635 #
636 # 値取得シンボルテーブルの読み込み
637 #
638 ReadSymvalTable()
639
640 #
641 # システムコンフィギュレーションファイルの読み込み
642 #
643 $cfgFileInfo = []
644 $dependencyFiles = $configFileNames.dup
645 $includeFiles = []
646 $configFileNames.each do |configFileName|
647 CfgParser.new.parseFile(configFileName)
648 end
649 abort if $errorFlag # エラー発生時はabortする
650
651 #
652 # cfg1_out.cの生成
653 #
654 GenerateCfg1OutC()
655
656 #
657 # 依存関係の出力
658 #
659 if !$dependencyFileName.nil?
660 if $dependencyFileName == ""
661 depFile = STDOUT
662 else
663 begin
664 depFile = File.open($dependencyFileName, "w")
665 rescue Errno::ENOENT, Errno::EACCES => ex
666 abort(ex.message)
667 end
668 end
669
670 depFile.print("#{CFG1_OUT_C} #{CFG1_OUT_DB}:")
671 $dependencyFiles.each do |fileName|
672 depFile.print(" #{fileName}")
673 end
674 depFile.puts("")
675
676 if $dependencyFileName != ""
677 depFile.close
678 end
679 end
680
681 #
682 # パス2に引き渡す情
683報をファイルに生成
684 #
685 if $omitOutputDb.nil?
686 db = PStore.new(CFG1_OUT_DB)
687 db.transaction do
688 db[:apiDefinition] = $apiDefinition
689 db[:symbolValueTable] = $symbolValueTable
690 db[:cfgFileInfo] = $cfgFileInfo
691 db[:includeFiles] = $includeFiles
692 end
693 end
694end
Note: See TracBrowser for help on using the repository browser.