source: EcnlProtoTool/trunk/asp3_dcre/cfg/pass1.rb

Last change on this file was 439, checked in by coas-nagasima, 4 years ago

mrubyを2.1.1に更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-ruby;charset=UTF-8
File size: 29.1 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-2018 by Embedded and Real-Time Systems Laboratory
7# Graduate School of Information Science, Nagoya Univ., JAPAN
8#
9# 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
10# ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
11# 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
12# (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
13# 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
14# スコード中に含まれていること.
15# (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
16# 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
17# 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
18# の無保証規定を掲載すること.
19# (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
20# 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
21# と.
22# (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
23# 作権表示,この利用条件および下記の無保証規定を掲載すること.
24# (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
25# 報告すること.
26# (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
27# 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
28# また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
29# 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
30# 免責すること.
31#
32# 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
33# よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
34# に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
35# アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
36# の責任を負わない.
37#
38# $Id$
39#
40
41#
42# パス1の処理
43#
44
45#
46# 値取得シンボルテーブルへの固定登録
47#
48$symbolValueTable = {
49 "CHAR_BIT" => { EXPR: "CHAR_BIT" },
50 "SCHAR_MAX" => { EXPR: "SCHAR_MAX", SIGNED: true },
51 "SCHAR_MIN" => { EXPR: "SCHAR_MIN", SIGNED: true },
52 "UCHAR_MAX" => { EXPR: "UCHAR_MAX" },
53 "CHAR_MAX" => { EXPR: "CHAR_MAX", SIGNED: true },
54 "CHAR_MIN" => { EXPR: "CHAR_MIN", SIGNED: true },
55 "SHRT_MAX" => { EXPR: "SHRT_MAX", SIGNED: true },
56 "SHRT_MIN" => { EXPR: "SHRT_MIN", SIGNED: true },
57 "USHRT_MAX" => { EXPR: "USHRT_MAX" },
58 "INT_MAX" => { EXPR: "INT_MAX", SIGNED: true },
59 "INT_MIN" => { EXPR: "INT_MIN", SIGNED: true },
60 "UINT_MAX" => { EXPR: "UINT_MAX" },
61 "LONG_MAX" => { EXPR: "LONG_MAX", SIGNED: true },
62 "LONG_MIN" => { EXPR: "LONG_MIN", SIGNED: true },
63 "ULONG_MAX" => { EXPR: "ULONG_MAX" },
64 "SIL_ENDIAN_BIG" \
65 => { EXPR: "true", BOOL: true, CONDITION: "defined(SIL_ENDIAN_BIG)" },
66 "SIL_ENDIAN_LITTLE" \
67 => { EXPR: "true", BOOL: true, CONDITION: "defined(SIL_ENDIAN_LITTLE)" }
68}
69
70#
71# 静的APIテーブルへの固定登録
72#
73$apiDefinition = { "INCLUDE" =>
74 { :PARAM => [ { :NAME => :file, :STRING_LITERAL => true }]}}
75
76#
77# 静的APIテーブルの読み込み
78#
79def ReadApiTableFile
80 $apiTableFileNames.each do |apiTableFileName|
81 if /^(.+):(\w+)$/ =~ apiTableFileName
82 apiTableFileName = $1
83 apiPhase = $2.to_sym
84 end
85
86 if !File.exist?(apiTableFileName)
87 error_exit("`#{apiTableFileName}' not found")
88 next
89 end
90
91 apiFile = File.open(apiTableFileName)
92 apiFile.each do |line|
93 next if /^#/ =~ line # コメントをスキップ
94
95 fields = line.split(/\s+/) # フィールドに分解
96
97 apiName = fields.shift # API名の取り出し
98 if /^(.+)\[(.+)\]$/ =~ apiName
99 apiName = $1
100 apiDef = { APINAME: apiName, API: $2 }
101 else
102 apiDef = { APINAME: apiName, API: apiName }
103 end
104 if !apiPhase.nil?
105 apiDef[:PHASE] = apiPhase
106 end
107
108 apiParams = []
109 fields.each do |param|
110 case param
111 when /^(\W*)(\w+)(\W*)$/
112 prefix = $1
113 name = $2
114 postfix = $3
115 apiParam = { :NAME => name }
116
117 case prefix
118 when "#" # オブジェクト識別名(定義)
119 apiParam[:ID_DEF] = true
120 when "%" # オブジェクト識別名(参照)
121 apiParam[:ID_REF] = true
122 when "." # 符号無し整数定数式パラメータ
123 apiParam[:EXPTYPE] = "unsigned_t"
124 when "+" # 符号付き整数定数式パラメータ
125 apiParam[:EXPTYPE] = "signed_t"
126 apiParam[:SIGNED] = true
127 when "^" # ポインタ整数定数式パラメータ
128 apiParam[:EXPTYPE] = "uintptr_t"
129 apiParam[:INTPTR] = true
130 when "&" # 一般整数定数式パラメータ
131 # do nothing
132 when "$" # 文字列定数式パラメータ
133 apiParam[:STRING] = true
134 apiParam[:EXPTYPE] = "char *"
135 else
136 error_exit("`#{param}' is invalid")
137 end
138
139 case postfix
140 when "*" # キーを決めるパラメータ
141 apiDef[:KEYPAR] = name
142 when "?" # オプションパラメータ
143 apiParam[:OPTIONAL] = true
144 when "\.\.\." # リストパラメータ
145 apiParam[:LIST] = true
146 end
147
148 when "{" # {
149 apiParam = { :BRACE => "{" }
150 when "{?" # {?
151 apiParam = { :BRACE => "{", :OPTBRACE => true }
152
153 when "}" # }
154 apiParam = { :BRACE => "}" }
155
156 else
157 error_exit("`#{param}' is invalid")
158 end
159 apiParams.push(apiParam)
160 end
161 apiDef[:PARAM] = apiParams
162 $apiDefinition[apiName] = apiDef
163 end
164 apiFile.close
165 end
166end
167
168#
169# 値取得シンボルテーブルの読み込み
170#
171def ReadSymvalTable
172 $symvalTableFileNames.each do |symvalTableFileName|
173 if !File.exist?(symvalTableFileName)
174 error_exit("`#{symvalTableFileName}' not found")
175 next
176 end
177
178 symvalCsv = CSV.open(symvalTableFileName,
179 { skip_blanks: true, skip_lines: /^#/ })
180 symvalCsv.each do |record|
181 symbol = {}
182
183 # 変数名
184 if record[0].nil?
185 error_exit("invalid variable name in " \
186 "`#{symvalTableFileName}:#{symvalCsv.to_io.lineno}'")
187 elsif /^(.+)\[(.+)\]$/ =~ record[0]
188 variable = $1
189 symbol[:NUMSTRVAR] = $2
190 else
191 variable = record[0]
192 end
193
194 # 式
195 if record[1].nil? || record[1].empty?
196 symbol[:EXPR] = variable
197 else
198 symbol[:EXPR] = record[1]
199 end
200
201 # 式の型
202 if !record[2].nil? && !record[2].empty?
203 case record[2]
204 when /^[bB]/ # 真偽値
205 symbol[:BOOL] = true
206 when /^[iI]/ # ポインタ整数値
207 symbol[:INTPTR] = true
208 when /^[uU]/ # 符号無し整数値
209 # 何も設定しない
210 else # 符号付き整数値
211 symbol[:SIGNED] = true
212 end
213 end
214
215 # コンパイル条件
216 if !record[3].nil? && !record[3].empty?
217 symbol[:CONDITION] = record[3]
218 end
219
220 # 条件が成立しない時の式
221 if !record[4].nil? && !record[4].empty?
222 symbol[:ELSE_EXPR] = record[4]
223 end
224
225 $symbolValueTable[variable] = symbol
226 end
227 symvalCsv.close
228 end
229end
230
231#
232# システムコンフィギュレーションファイルからの読み込みクラス
233#
234class ConfigFile
235 def initialize(fileName)
236 @cfgFileName = fileName
237 begin
238 @cfgFile = File.open(@cfgFileName)
239 rescue Errno::ENOENT, Errno::EACCES => ex
240 abort(ex.message)
241 end
242 @lineNo = 0
243 @withinComment = false
244 end
245
246 def close
247 @cfgFile.close
248 end
249
250 def getNextLine(withinApi)
251 line = @cfgFile.gets
252 return(nil) if line.nil?
253
254 line.encode!("UTF-16BE", "UTF-8", # 不正なバイト列を除外する
255 :invalid => :replace,
256 :undef => :replace,
257 :replace => '?').encode!("UTF-8")
258 @lineNo += 1
259
260 line.chomp!
261 if @withinComment
262 case line
263 when /\*\// # C言語スタイルのコメント終了
264 line.sub!(/^.*?\*\//, "") # 最初の*/にマッチさせる */
265 @withinComment = false
266 else
267 line = ""
268 end
269 end
270 if !@withinComment
271 line.gsub!(/\/\*.*?\*\//, "") # C言語スタイルのコメントの除去
272 # 最初の*/にマッチさせる */
273 case line
274 when /^\s*#/ # プリプロセッサディレクティブ
275 if withinApi
276 parse_error(self, \
277 "preprocessor directive must not be within static API")
278 line = ""
279 end
280 when /\/\*/ # C言語スタイルのコメント開始
281 line.sub!(/\/\*.*$/, "")
282 @withinComment = true
283 when /\/\// # C++言語スタイルのコメント
284 line.sub!(/\/\/.*$/, "")
285 end
286 end
287 return(line)
288 end
289
290 def getFileName
291 return(@cfgFileName)
292 end
293
294 def getLineNo
295 return(@lineNo)
296 end
297end
298
299#
300# システムコンフィギュレーションファイルのパーサークラス
301#
302class CfgParser
303 @@lastApiIndex = 0
304 @@currentDomain = nil
305 @@currentClass = nil
306 @@nestDC = []
307
308 def initialize
309 @line = ""
310 @skipComma = false # 次が,であれば読み飛ばす
311 end
312
313 #
314 # 文字列末まで読む
315 #
316 def parseString(cfgFile)
317 string = ""
318 begin
319 case @line
320 when /^([^"]*\\\\)(.*)$/ # \\まで読む
321 string += $1
322 @line = $2
323 when /^([^"]*\\\")(.*)$/ # \"まで読む
324 string += $1
325 @line = $2
326 when /^([^"]*\")(.*)$/ # "まで読む
327 string += $1
328 @line = $2
329 return(string)
330 else # 行末まで読む
331 string += @line + "\n"
332 @line = cfgFile.getNextLine(true)
333 end
334 end while (@line)
335 error_exit("unterminated string meets end-of-file")
336 return(string)
337 end
338
339 #
340 # 文字末まで読む
341 #
342 def parseChar(cfgFile)
343 string = ""
344 begin
345 case @line
346 when /^([^']*\\\\)(.*)$/ # \\まで読む
347 string += $1
348 @line = $2
349 when /^([^']*\\\')(.*)$/ # \'まで読む
350 string += $1
351 @line = $2
352 when /^([^']*\')(.*)$/ # 'まで読む
353 string += $1
354 @line = $2
355 return(string)
356 else # 行末まで読む
357 string += @line + "\n"
358 @line = cfgFile.getNextLine(true)
359 end
360 end while (@line)
361 error_exit("unterminated string meets end-of-file")
362 return(string)
363 end
364
365 #
366 # 改行と空白文字を読み飛ばす
367 #
368 def skipSpace(cfgFile, withinApi)
369 loop do
370 return if @line.nil? # ファイル末であればリターン
371 @line.lstrip! # 先頭の空白を削除
372 return if @line != "" # 空行でなければリターン
373 @line = cfgFile.getNextLine(withinApi) # 次の行を読む
374 end
375 end
376
377 #
378 # 次の文字まで読み飛ばす
379 #
380 def skipToToken(cfgFile, withinApi=true)
381 skipSpace(cfgFile, withinApi)
382 if @line.nil? # ファイル末であればエラー終了
383 error_exit("#{cfgFile.getFileName}: unexpeced end-of-file")
384 end
385 end
386
387 #
388 # パラメータを1つ読む
389 #
390 # @lineの先頭からパラメータを1つ読んで,それを文字列で返す.読んだパ
391 # ラメータは,@lineからは削除する.パラメータの途中で行末に達した時は,
392 # cfgFileから次の行を取り出す.ファイル末に達した時は,nilを返す.
393 #
394 def parseParam(cfgFile)
395 param = "" # 読んだ文字列
396 parenLevel = 0 # 括弧のネストレベル
397 skipComma = @skipComma
398 @skipComma = false
399
400 skipToToken(cfgFile) # 次の文字まで読み飛ばす
401 begin
402 if parenLevel == 0
403 case @line
404 when /^(\s*,)(.*)$/ # ,
405 @line = $2
406 if param == "" && skipComma
407 skipComma = false
408 return(parseParam(cfgFile)) # 再帰呼び出し
409 else
410 return(param.strip)
411 end
412 when /^(\s*{)(.*)$/ # {
413 if param != ""
414 return(param.strip)
415 else
416 @line = $2
417 return("{")
418 end
419 when /^(\s*\()(.*)$/ # (
420 param += $1
421 @line = $2
422 parenLevel += 1
423 when /^(\s*([)}]))(.*)$/ # }か)
424 if param != ""
425 return(param.strip)
426 else
427 @line = $3
428 @skipComma = true if $2 == "}"
429 return($2)
430 end
431 when /^(\s*\")(.*)$/ # "
432 @line = $2
433 param += $1 + parseString(cfgFile)
434 when /^(\s*\')(.*)$/ # '
435 @line = $2
436 param += $1 + parseChar(cfgFile)
437 when /^(\s*[^,{}()"'\s]+)(.*)$/ # その他の文字列
438 param += $1
439 @line = $2
440 else # 行末
441 param += " "
442 @line = cfgFile.getNextLine(true)
443 end
444 else
445 # 括弧内の処理
446 case @line
447 when /^(\s*\()(.*)$/ # "("
448 param += $1
449 @line = $2
450 parenLevel += 1
451 when /^(\s*\))(.*)$/ # ")"
452 param += $1
453 @line = $2
454 parenLevel -= 1
455 when /^(\s*\")(.*)$/ # "
456 @line = $2
457 param += $1 + parseString(cfgFile)
458 when /^(\s*\')(.*)$/ # '
459 @line = $2
460 param += $1 + parseChar(cfgFile)
461 when /^(\s*[^()"'\s]+)(.*)$/ # その他の文字列
462 param += $1
463 @line = $2
464 else # 行末
465 param += " "
466 @line = cfgFile.getNextLine(true)
467 end
468 end
469 end while (@line)
470 return(param.strip)
471 end
472
473 def getParam(apiParam, param, cfgFile)
474 if param == ""
475 if !apiParam.has_key?(:OPTIONAL)
476 parse_error(cfgFile, "unexpected `,'")
477 end
478 return(param)
479 end
480
481 if apiParam.has_key?(:ID_DEF) || apiParam.has_key?(:ID_REF)
482 if (/^[A-Za-z_]\w*$/ !~ param)
483 parse_error(cfgFile, "`#{param}' is illegal object ID")
484 end
485 return(param)
486 end
487
488 if apiParam.has_key?(:STRING_LITERAL)
489 return(param.unquote)
490 else
491 return(param)
492 end
493 end
494
495 def parseApi(cfgFile, apiName)
496 # 静的APIの読み込み
497 staticApi = {}
498 tooFewParams = false
499 skipUntilBrace = 0
500
501 skipToToken(cfgFile) # 次の文字まで読み飛ばす
502 if (/^\((.*)$/ =~ @line)
503 @line = $1
504
505 staticApi[:APINAME] = apiName
506 staticApi[:_FILE_] = cfgFile.getFileName
507 staticApi[:_LINE_] = cfgFile.getLineNo
508 apiDef = $apiDefinition[apiName]
509 param = parseParam(cfgFile)
510
511 apiDef[:PARAM].each do |apiParam|
512 return(staticApi) if param.nil? # ファイル末であればリターン
513
514 if skipUntilBrace > 0
515 # API定義を}までスキップ中
516 if apiParam.has_key?(:BRACE)
517 case apiParam[:BRACE]
518 when "{"
519 skipUntilBrace += 1
520 when "}"
521 skipUntilBrace -= 1
522 end
523 end
524 elsif apiParam.has_key?(:OPTIONAL)
525 if /^([{})])$/ !~ param
526 store_param = getParam(apiParam, param, cfgFile)
527 if store_param != ""
528 staticApi[apiParam[:NAME]] = store_param
529 end
530 param = parseParam(cfgFile)
531 end
532 elsif apiParam.has_key?(:LIST)
533 staticApi[apiParam[:NAME]] = []
534 while /^([{})])$/ !~ param
535 staticApi[apiParam[:NAME]].push(getParam(apiParam, param, cfgFile))
536 param = parseParam(cfgFile)
537 break if param.nil? # ファイル末の場合
538 end
539 elsif apiParam.has_key?(:OPTBRACE)
540 if param == apiParam[:BRACE]
541 param = parseParam(cfgFile)
542 break if param.nil? # ファイル末の場合
543 else
544 if param == ""
545 param = parseParam(cfgFile)
546 break if param.nil? # ファイル末の場合
547 elsif /^([})])$/ !~ param
548 parse_error(cfgFile, "`{...}' expected before #{param}")
549 end
550 skipUntilBrace += 1 # API定義を}までスキップ
551 end
552 elsif !apiParam.has_key?(:BRACE)
553 if /^([{})])$/ !~ param
554 staticApi[apiParam[:NAME]] = getParam(apiParam, param, cfgFile)
555 param = parseParam(cfgFile)
556 elsif !tooFewParams
557 parse_error(cfgFile, "too few parameters before `#{$1}'")
558 tooFewParams = true
559 end
560 elsif param == apiParam[:BRACE]
561 param = parseParam(cfgFile)
562 tooFewParams = false
563 else
564 parse_error(cfgFile, "`#{apiParam[:BRACE]}' expected before #{param}")
565 # )かファイル末まで読み飛ばす
566 loop do
567 param = parseParam(cfgFile)
568 break if (param.nil? || param == ")")
569 end
570 break
571 end
572 end
573
574 # 期待されるパラメータをすべて読んだ後の処理
575 if param != ")"
576 begin
577 param = parseParam(cfgFile)
578 return(staticApi) if param.nil? # ファイル末であればリターン
579 end while param != ")"
580 parse_error(cfgFile, "too many parameters before `)'")
581 end
582 else
583 parse_error(cfgFile, "syntax error: #{@line}")
584 @line = ""
585 end
586 return(staticApi)
587 end
588
589 def parseOpenBrace(cfgFile)
590 # {の読み込み
591 skipToToken(cfgFile) # 次の文字まで読み飛ばす
592 if (/^\{(.*)$/ =~ @line)
593 @line = $1
594 else
595 parse_error(cfgFile, "`{' expected before #{@line}")
596 end
597 end
598
599 def parseFile(cfgFileName)
600 cfgFiles = [ ConfigFile.new(cfgFileName) ]
601 @line = ""
602 loop do
603 cfgFile = cfgFiles.last
604
605 skipSpace(cfgFile, false) # 改行と空白文字を読み飛ばす
606 if @line.nil?
607 # ファイル末の処理
608 cfgFiles.pop.close
609 if cfgFiles.empty?
610 break # パース処理終了
611 else
612 @line = "" # 元のファイルに戻って続ける
613 end
614 elsif /^;(.*)$/ =~ @line
615 # ;は読み飛ばす
616 @line = $1
617 elsif /^#/ =~ @line
618 # プリプロセッサディレクティブを読む
619 case @line
620 when /^#(include|ifdef|ifndef|if|endif|else|elif)\b/
621 directive = {}
622 directive[:DIRECTIVE] = @line.strip
623 directive[:_FILE_] = cfgFile.getFileName
624 directive[:_LINE_] = cfgFile.getLineNo
625 $cfgFileInfo.push(directive)
626 else
627 parse_error(cfgFile, "unknown preprocessor directive: #{@line}")
628 end
629 @line = ""
630 elsif (/^([A-Z_][A-Z0-9_]*)\b(.*)$/ =~ @line)
631 apiName = $1
632 @line = $2
633
634 case apiName
635 when "KERNEL_DOMAIN"
636 if !$supportDomain
637 parse_warning(cfgFile, "`KERNEL_DOMAIN' is not supported")
638 end
639 if !@@currentDomain.nil?
640 parse_error(cfgFile, "`DOMAIN' must not be nested")
641 end
642 @@currentDomain = "TDOM_KERNEL"
643 parseOpenBrace(cfgFile)
644 @@nestDC.push("domain")
645 when "DOMAIN"
646 if !$supportDomain
647 parse_warning(cfgFile, "`DOMAIN' is not supported")
648 end
649 if !@@currentDomain.nil?
650 parse_error(cfgFile, "`DOMAIN' must not be nested")
651 end
652 domid = parseParam(cfgFile).sub(/^\((.+)\)$/m, "\\1").strip
653 if (/^[A-Za-z_]\w*$/ !~ domid)
654 parse_error(cfgFile, "`#{domid}' is illegal domain ID")
655 else
656 if !$domainId.has_key?(domid)
657 if $inputObjid.has_key?(domid)
658 # ID番号入力ファイルに定義されていた場合
659 $domainId[domid] = $inputObjid[domid]
660 if $domainId[domid] > 32
661 error_exit("domain ID for `#{domid}' is too large")
662 end
663 else
664 $domainId[domid] = nil
665 end
666 end
667 @@currentDomain = domid
668 end
669 parseOpenBrace(cfgFile)
670 @@nestDC.push("domain")
671 when "CLASS"
672 if !$supportClass
673 parse_warning(cfgFile, "`CLASS' is not supported")
674 end
675 if !@@currentClass.nil?
676 parse_error(cfgFile, "`CLASS' must not be nested")
677 end
678 @@currentClass = parseParam(cfgFile).sub(/^\((.+)\)$/m, "\\1").strip
679 @@classFile = cfgFile.getFileName
680 @@classLine = cfgFile.getLineNo
681 parseOpenBrace(cfgFile)
682 @@nestDC.push("class")
683 else
684 if $apiDefinition.has_key?(apiName)
685 # 静的APIを1つ読む
686 staticApi = parseApi(cfgFile, apiName)
687 if staticApi.empty?
688 # ファイル末か文法エラー
689 elsif (staticApi[:APINAME] == "INCLUDE")
690 # INCLUDEの処理
691 includeFilePath = SearchFilePath(staticApi[:file])
692 if includeFilePath.nil?
693 error = {}
694 error[:DIRECTIVE] = "#error '#{staticApi[:file]}' not found."
695 error[:_FILE_] = cfgFile.getFileName
696 error[:_LINE_] = cfgFile.getLineNo
697 $cfgFileInfo.push(error)
698 else
699 $dependencyFiles.push(includeFilePath)
700 cfgFiles.push(ConfigFile.new(includeFilePath))
701 end
702 else
703 # 静的APIの処理
704 if !@@currentDomain.nil?
705 staticApi[:DOMAIN] = @@currentDomain
706 end
707 if !@@currentClass.nil?
708 staticApi[:CLASS] = @@currentClass
709 staticApi[:CLASS_FILE_] = @@classFile
710 staticApi[:CLASS_LINE_] = @@classLine
711 end
712 staticApi[:INDEX] = (@@lastApiIndex += 1)
713 $cfgFileInfo.push(staticApi)
714 end
715
716 # ";"を読む
717 skipToToken(cfgFile, false) # 次の文字まで読み飛ばす
718 if (/^\;(.*)$/ =~ @line)
719 @line = $1
720 else
721 parse_error(cfgFile, "`;' expected after static API")
722 end
723 else
724 parse_error(cfgFile, "unknown static API: #{apiName}")
725 end
726 end
727 elsif (/^\}(.*)$/ =~ @line)
728 # }の処理
729 if @@nestDC.size > 0
730 case @@nestDC.pop
731 when "domain"
732 @@currentDomain = nil
733 when "class"
734 @@currentClass = nil
735 end
736 else
737 error_exit("unexpected `}'")
738 end
739 @line = $1
740 else
741 parse_error(cfgFile, "syntax error: #{@line}")
742 @line = ""
743 end
744 end
745 end
746end
747
748#
749# cfg1_out.cの生成
750#
751module Cfg1OutC
752 #
753 # 静的APIのファイル名と行番号の出力
754 #
755 def self.OutLineNumber(cfgInfo)
756 @cfg1Out.add("#line #{cfgInfo[:_LINE_]} \"#{cfgInfo[:_FILE_]}\"")
757 end
758
759 #
760 # クラス記述のファイル名と行番号の出力
761 #
762 def self.OutClassLineNumber(cfgInfo)
763 @cfg1Out.add("#line #{cfgInfo[:CLASS_LINE_]} \"#{cfgInfo[:CLASS_FILE_]}\"")
764 end
765
766 #
767 # パラメータに関する定義の出力
768 #
769 def self.OutParamDef(param, index, apiParam, cfgInfo)
770 if apiParam.has_key?(:ID_DEF)
771 @cfg1Out.add("#define #{param}\t(<>)")
772 elsif apiParam.has_key?(:EXPTYPE)
773 OutLineNumber(cfgInfo)
774 @cfg1Out.add("const #{apiParam[:EXPTYPE]} #{CFG1_PREFIX}valueof_" \
775 "#{apiParam[:NAME]}_#{index} = " \
776 "(#{apiParam[:EXPTYPE]})(#{param});")
777 end
778 end
779
780 #
781 # cfg1_out.cの生成(メインの処理)
782 #
783 def self.Generate
784 @cfg1Out = GenFile.new(CFG1_OUT_C)
785
786 @cfg1Out.append(<<EOS)
787/* #{CFG1_OUT_C} */
788#define TOPPERS_CFG1_OUT
789#include "kernel/kernel_int.h"
790EOS
791
792 # インクルードディレクティブ(#include)の生成
793 $cfgFileInfo.each do |cfgInfo|
794 if cfgInfo.has_key?(:DIRECTIVE)
795 OutLineNumber(cfgInfo)
796 @cfg1Out.add(cfgInfo[:DIRECTIVE])
797 end
798 end
799
800 @cfg1Out.add(<<EOS)
801
802#ifdef INT64_MAX
803 typedef int64_t signed_t;
804 typedef uint64_t unsigned_t;
805#else
806 typedef int32_t signed_t;
807 typedef uint32_t unsigned_t;
808#endif
809
810#include "#{CFG1_OUT_TARGET_H}"
811
812const uint32_t #{CFG1_MAGIC_NUM} = 0x12345678;
813const uint32_t #{CFG1_SIZEOF_SIGNED} = sizeof(signed_t);
814const uint32_t #{CFG1_SIZEOF_INTPTR} = sizeof(intptr_t);
815const uint32_t #{CFG1_SIZEOF_CHARPTR} = sizeof(char *);
816EOS
817
818 # 値取得シンボルの処理
819 $symbolValueTable.each do |symbolName, symbolData|
820 if symbolData.has_key?(:BOOL)
821 type = "signed_t"
822 elsif symbolData.has_key?(:INTPTR)
823 type = "uintptr_t"
824 elsif symbolData.has_key?(:SIGNED)
825 type = "signed_t"
826 else
827 type = "unsigned_t"
828 end
829 if symbolData.has_key?(:CONDITION)
830 @cfg1Out.add("#if #{symbolData[:CONDITION]}")
831 end
832 @cfg1Out.add("const #{type} #{CFG1_PREFIX}#{symbolName} = " \
833 "(#{type})(#{symbolData[:EXPR]});")
834 if symbolData.has_key?(:ELSE_EXPR)
835 @cfg1Out.add("#else")
836 @cfg1Out.add("const #{type} #{CFG1_PREFIX}#{symbolName} = " \
837 "(#{type})(#{symbolData[:ELSE_EXPR]});")
838 end
839 if symbolData.has_key?(:CONDITION)
840 @cfg1Out.add("#endif")
841 end
842 end
843 @cfg1Out.add
844
845 # ドメインIDの定義の生成
846 $domainId.each do |domainName, domainVal|
847 if domainVal > 0
848 @cfg1Out.add("#define #{domainName} #{domainVal}")
849 end
850 end
851 @cfg1Out.add
852
853 # 静的API/プリプロセッサディレクティブの処理
854 $cfgFileInfo.each do |cfgInfo|
855 if cfgInfo.has_key?(:DIRECTIVE)
856 # 条件ディレクティブを出力
857 if cfgInfo[:DIRECTIVE] =~ /^#(ifdef|ifndef|if|endif|else|elif)\b/
858 OutLineNumber(cfgInfo)
859 @cfg1Out.add2(cfgInfo[:DIRECTIVE])
860 end
861 else
862 apiDef = $apiDefinition[cfgInfo[:APINAME]]
863 apiIndex = cfgInfo[:INDEX]
864 OutLineNumber(cfgInfo)
865 @cfg1Out.add("const unsigned_t #{CFG1_PREFIX}static_api_" \
866 "#{apiIndex} = #{apiIndex};")
867 apiDef[:PARAM].each do |apiParam|
868 next unless apiParam.has_key?(:NAME)
869 paramName = apiParam[:NAME]
870 next unless cfgInfo.has_key?(paramName) # パラメータがない場合
871 paramData = cfgInfo[paramName]
872
873 if apiParam.has_key?(:LIST)
874 paramData.each.with_index(1) do |param, index|
875 OutParamDef(param, "#{apiIndex}_#{index}", apiParam, cfgInfo)
876 end
877 else
878 OutParamDef(paramData, "#{apiIndex}", apiParam, cfgInfo)
879 end
880 end
881 if cfgInfo.has_key?(:CLASS)
882 # クラスIDの取得のための処理
883 OutClassLineNumber(cfgInfo)
884 @cfg1Out.add("const signed_t #{CFG1_PREFIX}valueof_CLASS_" \
885 "#{apiIndex} = (signed_t)(#{cfgInfo[:CLASS]});")
886 end
887 @cfg1Out.add
888 end
889 end
890 end
891end
892
893#
894# パス1の処理
895#
896def Pass1
897 #
898 # タイムスタンプファイルの指定
899 #
900 $timeStampFileName = CFG1_OUT_TIMESTAMP
901
902 #
903 # 静的APIテーブルの読み込み
904 #
905 ReadApiTableFile()
906
907 #
908 # 値取得シンボルテーブルの読み込み
909 #
910 ReadSymvalTable()
911
912 #
913 # システムコンフィギュレーションファイルの読み込み
914 #
915 $cfgFileInfo = []
916 $dependencyFiles = $configFileNames.dup
917 $domainId = { "TDOM_KERNEL" => -1, "TDOM_NONE" => -2 }
918 $configFileNames.each do |configFileName|
919 CfgParser.new.parseFile(configFileName)
920 end
921 abort if $errorFlag # エラー発生時はabortする
922
923 #
924 # ドメインIDの割当て処理
925 #
926 nextDomainId = 1
927 $domainId.each do |domainName, domainVal|
928 if domainVal.nil?
929 while $domainId.has_value?(nextDomainId)
930 nextDomainId += 1
931 end
932 $domainId[domainName] = nextDomainId
933 if nextDomainId > 32
934 error_exit("too large number of user domains")
935 end
936 nextDomainId += 1
937 end
938 end
939
940 #
941 # cfg1_out.cの生成
942 #
943 Cfg1OutC::Generate()
944
945 #
946 # 依存関係の出力
947 #
948 if !$dependencyFileName.nil?
949 if $dependencyFileName == ""
950 depFile = STDOUT
951 else
952 begin
953 depFile = File.open($dependencyFileName, "w")
954 rescue Errno::ENOENT, Errno::EACCES => ex
955 abort(ex.message)
956 end
957 end
958
959 depFile.print("#{CFG1_OUT_TIMESTAMP}:")
960 $dependencyFiles.each do |fileName|
961 depFile.print(" #{fileName}")
962 end
963 depFile.puts("")
964
965 if $dependencyFileName != ""
966 depFile.close
967 end
968 end
969
970 #
971 # パス2に引き渡す情報をファイルに生成
972 #
973 if !$omitOutputDb
974 db = PStore.new(CFG1_OUT_DB)
975 db.transaction do
976 db[:apiDefinition] = $apiDefinition
977 db[:symbolValueTable] = $symbolValueTable
978 db[:cfgFileInfo] = $cfgFileInfo
979 db[:domainId] = $domainId
980 end
981 end
982end
Note: See TracBrowser for help on using the repository browser.