Changeset 318 for asp3_gr_sakura/trunk/tecsgen/tecslib/core/bnf.tab.rb
- Timestamp:
- Aug 3, 2017, 10:46:41 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
asp3_gr_sakura/trunk/tecsgen/tecslib/core/bnf.tab.rb
-
Property svn:mime-type
changed from
text/x-ruby
totext/x-ruby; charset=UTF-8
r317 r318 94 94 } 95 95 96 # æå®å '[]' å 97 ã§ã®ã¿ä½¿ç¨ã§ãããã¼ã¯ã¼ã 96 # 指定子 '[]' 内でのみ使用できるキーワード 98 97 RESERVED2 = { 99 98 # specifier … … 112 111 # port (entry) 113 112 'inline' => :INLINE, 114 'ref_desc' => :REF_DESC, # call ãå¯113 'ref_desc' => :REF_DESC, # call も可 115 114 116 115 # port (call) … … 156 155 } 157 156 158 # å帰çãªãã¼ãµã®ããã®ã¹ã¿ãã¯157 # 再帰的なパーサのためのスタック 159 158 @@generator_nest = -1 160 159 @@generator_stack = [] 161 160 @@current_locale = [] 162 161 163 # import_C ä¸ã§ãã162 # import_C 中である 164 163 @@import_C = false 165 164 166 # ãã¹ã¦ã®æ§æ解æãå®äºãã165 # すべての構文解析が完了した 167 166 @@b_end_all_parse = false 168 167 169 168 def self.parse( file_name, plugin = nil, b_reuse = false ) 170 # ãã¼ãµã¤ã³ã¹ã¿ã³ã¹ãçæ(å¥ãã¼ãµã§èªã¿è¾¼ã)169 # パーサインスタンスを生成(別パーサで読み込む) 171 170 parser = Generator.new 172 171 173 # plugin ãã import ããã¦ããå ´åã® plugin è¨å®172 # plugin から import されている場合の plugin 設定 174 173 parser.set_plugin plugin 175 174 176 # reuse ãã©ã°ãè¨å®175 # reuse フラグを設定 177 176 parser.set_reuse b_reuse 178 177 179 # cdl ããã¼ã¹178 # cdl をパース 180 179 parser.parse( [file_name] ) 181 180 182 # çµæåããã¼ãµã¹ã¿ãã¯ãæ»ã181 # 終期化 パーサスタックを戻す 183 182 parser.finalize 184 183 end … … 200 199 def self.get_plugin 201 200 if @@generator_stack[@@generator_nest] then 202 # tecsgen å¼æ°ã® cdl ã import ãããå ´åã¯nil201 # tecsgen 引数の cdl が import される場合は nil 203 202 return @@generator_stack[@@generator_nest].get_plugin 204 203 else … … 217 216 def self.is_reuse? 218 217 if @@generator_stack[@@generator_nest] then 219 # tecsgen å¼æ°ã® cdl ã import ãããå ´åã¯nil218 # tecsgen 引数の cdl が import される場合は nil 220 219 return @@generator_stack[@@generator_nest].is_reuse? 221 220 else … … 247 246 b_in_string = false 248 247 249 # euc ã®ã³ã¡ã³ãã utf8 ã¨ãã¦æ±ãã¨ãã³ã¡ã³ãã®çµããã誤ãåé¡ã®å¯¾ç248 # euc のコメントを utf8 として扱うと、コメントの終わりを誤る問題の対策 250 249 TECS_LANG::set_kcode_binary 251 250 … … 257 256 TECSIO.foreach(file) {|line| 258 257 col = 1 259 # line.rstrip! æ¹è¡å«ãæååãæ±ãããã«ãªã£ãã®ã§ãããã§ç©ºç½ãåãé¤ããªããªã£ã258 # line.rstrip! 改行含む文字列を扱うようになったので、ここで空白を取り除けなくなった 260 259 261 260 until line.empty? … … 263 262 if b_in_comment 264 263 case line 265 # ã³ã¡ã³ãçµäº264 # コメント終了 266 265 when /\A\*\// 267 266 b_in_comment = false 268 267 when /\A./ 269 268 ; 270 when /\s+/ # line.rstrip! ãæ¢ãããã \n ãªã©ã®ç©ºç½æåã¨ã¾ã£ã¡ããã«ã¼ã«ãå¿ 271 è¦ã«ãªã£ã 269 when /\s+/ # line.rstrip! を止めたため \n などの空白文字とまっちするルールが必要になった 272 270 ; 273 271 end … … 277 275 @q << [:STRING_LITERAL, Token.new(string, file, lineno, col)] 278 276 b_in_string = false 279 elsif line =~ /\A.*\\\n/ # æ¹è¡ \n 㯠'.' ã«ãããããªã277 elsif line =~ /\A.*\\\n/ # 改行 \n は '.' にマッチしない 280 278 string += $& 281 elsif line =~ /\A.*\n/ # æ¹è¡ \n 㯠'.' ã«ãããããªã279 elsif line =~ /\A.*\n/ # 改行 \n は '.' にマッチしない 282 280 string += line 283 # ãã®ä½ç½®ã§ã¯ error ã¡ã½ããã¯ä½¿ããªã (token èªåºãå)281 # この位置では error メソッドは使えない (token 読出し前) 284 282 puts "error: #{file} line #{lineno}: string literal has newline without escape" 285 283 @@n_error += 1 … … 287 285 else 288 286 case line 289 # 空ç½ãããªããã»ã¹ãã£ã¬ã¯ãã£ã287 # 空白、プリプロセスディレクティブ 290 288 when /\A\s+/ 291 289 ; 292 # èå¥å290 # 識別子 293 291 when /\A[a-zA-Z_]\w*/ 294 292 word = $& 295 293 @q << [RESERVED[word] || :IDENTIFIER, Token.new(word.intern, file, lineno, col)] 296 # 16 é²æ°å®æ°294 # 16 進数定数 297 295 when /\A0x[0-9A-Fa-f]+/ 298 296 @q << [:HEX_CONSTANT, Token.new($&, file, lineno, col)] 299 # 8 é²æ°å®æ°297 # 8 進数定数 300 298 when /\A0[0-7]+/ 301 299 @q << [:OCTAL_CONSTANT, Token.new($&, file, lineno, col)] 302 # æµ®åå°æ°å®æ°300 # 浮動小数定数 303 301 when /\A[0-9]+\.([0-9]*)?([Ee][+-]?[0-9]+)?/ 304 302 @q << [:FLOATING_CONSTANT, Token.new($&, file, lineno, col)] 305 # æ´æ°å®æ°303 # 整数定数 306 304 when /\A\d+/ 307 305 @q << [:INTEGER_CONSTANT, Token.new($&.to_i, file, lineno, col)] 308 # æåå®æ°306 # 文字定数 309 307 when /\A'(?:[^'\\]|\\.)'/ 310 308 @q << [:CHARACTER_LITERAL, Token.new($&, file, lineno, col)] 311 # æåå312 # "#include #include #include \"../systask/logtask.cfg\" æå¾ã® " å¿ã)ã§ç¡éã«ã¼ã309 # 文字列 310 # "#include #include #include \"../systask/logtask.cfg\" 最後の " 忘れ)で無限ループ 313 311 # when /\A"(?:[^"\\]+|\\.)*"/ 314 when /\A"(?:[^"\\]|\\.)*"/ # ããã¯ãã¾ãè¡ãããã312 when /\A"(?:[^"\\]|\\.)*"/ # これはうまく行くようだ 315 313 @q << [:STRING_LITERAL, Token.new($&, file, lineno, col)] 316 # æåå (æ¹è¡ãã)314 # 文字列 (改行あり) 317 315 when /\A"(?:[^"\\]|\\.)*\\\n$/ 318 316 string = $& 319 317 b_in_string = true 320 # æåå (æ¹è¡ãã, escape ãªã)318 # 文字列 (改行あり, escape なし) 321 319 when /\A("(?:[^"\\]|\e\.)*)\n$/ 322 320 string = $1 + "\\\n" 323 321 b_in_string = true 324 # ãã®ä½ç½®ã§ã¯ error ã¡ã½ããã¯ä½¿ããªã (token èªåºãå) # mikan cdl_error ã§ã¯ãªã322 # この位置では error メソッドは使えない (token 読出し前) # mikan cdl_error ではない 325 323 puts "error: #{file} line #{lineno}: string literal has newline without escape" 326 324 @@n_error += 1 327 # å±±æ¬å¼§ã§å²ã¾ããæåå325 # 山括弧で囲まれた文字列 328 326 when /\A<[0-9A-Za-z_\. \/]+>/ # AB: angle bracke 329 327 @q << [:AB_STRING_LITERAL, Token.new($&, file, lineno, col)] 330 # è¡ã³ã¡ã³ã328 # 行コメント 331 329 when /\A\/\/.*$/ 332 # èªã¿é£ã°ãã ã333 # ã³ã¡ã³ãéå§330 # 読み飛ばすだけ 331 # コメント開始 334 332 when /\A\/\*/ 335 333 b_in_comment = true 336 # '>>', '<<' ãªã©334 # '>>', '<<' など 337 335 when /\A>>/, /\A<</, /\A==/, /\A!=/, /\A\&\&/, /\A\|\|/ 338 336 @q << [$&, Token.new($&, file, lineno, col)] 339 337 when /\A::/, /\A=>/, /\A<=/, /\A>=/ 340 338 @q << [$&, Token.new($&, file, lineno, col)] 341 # '(', ')' ãªã©ä¸æåã®è¨å·ãã¾ãã¯æªç¥ã®è¨å·339 # '(', ')' など一文字の記号、または未知の記号 342 340 when /\A./ 343 341 @q << [$&, Token.new($&, file, lineno, col)] … … 363 361 } 364 362 365 # çµäºã®å°363 # 終了の印 366 364 @q << nil 367 365 … … 383 381 384 382 if token[0] == :IDENTIFIER then 385 # TYPE_NAME ãã¼ã¯ã³ã¸ç½®æã383 # TYPE_NAME トークンへ置換え 386 384 if Namespace.is_typename?( token[1].val ) then 387 385 token[0] = :TYPE_NAME 388 386 elsif @in_specifier && RESERVED2[ token[1].val.to_s ] then 389 # æå®åãã¼ã¯ã¼ãï¼ '[', ']' å 390 ã§ã®ã¿æå¹) 387 # 指定子キーワード( '[', ']' 内でのみ有効) 391 388 token[0] = RESERVED2[ token[1].val.to_s ] 392 389 end 393 390 end 394 391 395 if $debug then # 070107 token ç¡å¹æãããéããªããããã (through å¯¾å¿ -d ã®æã«ä¾å¤çºç)392 if $debug then # 070107 token 無効時ここを通さないようした (through 対応 -d の時に例外発生) 396 393 locale = @@current_locale[@@generator_nest] 397 394 if token then … … 424 421 @@n_warning = 0 425 422 426 # ãã®ã¡ã½ããã¯æ§æ解æãæå³è§£æããã®ã¿å¼åºãå¯ï¼ã³ã¼ãçæã§ã¨ã©ã¼çºçã¯ä¸é©åï¼423 # このメソッドは構文解析、意味解析からのみ呼出し可(コード生成でエラー発生は不適切) 427 424 def self.error( msg, *arg ) 428 425 locale = nil … … 434 431 435 432 msg = TECSMsg.get_error_message( msg ) 436 # $1, $2, ... ã arg ã§ç½®æ433 # $1, $2, ... を arg で置換 437 434 count = 1 438 435 arg.each{ |a| … … 442 439 } 443 440 444 # import_C ã®ä¸ã§ã®ã¨ã©ã¼ï¼441 # import_C の中でのエラー? 445 442 if @@import_C then 446 443 C_parser.error( msg ) 447 444 else 448 445 449 # Node ã®è¨æ¶ãã ä½ç½® (locale) ã使ç¨ããå ´åãå¤æ´ä»¥åã«æ¯ã¹ã450 # åé¡çºçç®æã¨ç°ãªãä½ç½®ã«ã¨ã©ã¼ãåºããããæ§æ解æä¸ã®ã¨ã©ã¼451 # ã¯ã解æä¸ã®ä½ç½®ãåºåããï¼(new_XXX 㧠owner ãåè¦ç´ ã®ãã§ã452 # ã¯ããã㨠owner ã®è¡çªå·ãåºã¦ãã¾ãç¹ã§ããããçãã¦ãã)446 # Node の記憶する 位置 (locale) を使用した場合、変更以前に比べ、 447 # 問題発生箇所と異なる位置にエラーが出るため、構文解析中のエラー 448 # は、解析中の位置を出力する.(new_XXX で owner が子要素のチェッ 449 # クをすると owner の行番号が出てしまう点で、ずれが生じている) 453 450 454 451 if @@b_end_all_parse == false || locale == nil then … … 463 460 end 464 461 465 # ãã®ã¡ã½ããã¯æ§æ解æãæå³è§£æããã®ã¿å¼åºãå¯ï¼ã³ã¼ãçæã§ã¦ã©ã¼ãã³ã°çºçã¯ä¸é©åï¼462 # このメソッドは構文解析、意味解析からのみ呼出し可(コード生成でウォーニング発生は不適切) 466 463 def self.warning( msg, *arg ) 467 464 locale = nil … … 473 470 474 471 msg = TECSMsg.get_warning_message( msg ) 475 # $1, $2, ... ã arg ã§ç½®æ472 # $1, $2, ... を arg で置換 476 473 count = 1 477 474 arg.each{ |a| … … 481 478 } 482 479 483 # import_C ã®ä¸ã§ã®ã¦ã©ã¼ãã³ã°ï¼480 # import_C の中でのウォーニング? 484 481 if @@import_C then 485 482 C_parser.warning( msg ) … … 508 505 end 509 506 510 #=== '[' specifier å§ã507 #=== '[' specifier 始め 511 508 def set_in_specifier 512 509 # p "set_in_specifier" … … 514 511 end 515 512 516 #=== ']' specifier çµãã513 #=== ']' specifier 終わり 517 514 def unset_in_specifier 518 515 # p "unset_in_specifier" … … 520 517 end 521 518 522 # statement_specifier ã¯æ§æ解ééä¸ã§åç 523 §ããããã 519 # statement_specifier は構文解釈途中で参照したいため 524 520 @@statement_specifier_stack = [] 525 521 def self.add_statement_specifier( ss ) … … 538 534 end 539 535 540 #=== ãã¹ã¦ã®æ§æ解æãå®äºãããã¨ãå ±å536 #=== すべての構文解析が完了したことを報告 541 537 def self.end_all_parse 542 538 @@b_end_all_parse = true … … 2264 2260 module_eval(<<'.,.,', 'bnf.y.rb', 76) 2265 2261 def _reduce_13(val, _values, result) 2266 # é£æ¥ããæååã1ã¤ã®æååã«ã¾ã¨ãã2262 # 連接した文字列を1つの文字列にまとめる 2267 2263 str = "\"" + val[0].val.gsub( /\"(.*)\"/, "\\1" ) + val[1].val.gsub( /\"(.*)\"/, "\\1" ) + "\"" 2268 2264 result = Token.new( str, val[0].file, val[0].lineno, val[0].col ) … … 3159 3155 def _reduce_153(val, _values, result) 3160 3156 val[0].add_param( val[2] ) 3161 # result = val[0] ä¸è¦3157 # result = val[0] 不要 3162 3158 3163 3159 result … … 3314 3310 result = val[1] 3315 3311 else 3316 # ã¨ã©ã¼ï¼ä»®ã§ val[0] ãè¿ã3312 # エラー:仮で val[0] を返す 3317 3313 result = val[0] 3318 3314 end … … 3458 3454 obj = val[3] 3459 3455 if obj.kind_of?( Cell ) || obj.kind_of?( Signature ) || obj.kind_of?( Celltype ) || obj.kind_of?( CompositeCelltype )then 3460 # cell, signature 以å¤ã¯ãæå®åãç½®ããªã3456 # cell, signature 以外は、指定子を置けない 3461 3457 else 3462 Generator.get_statement_specifier # ã¯ãªã¢3458 Generator.get_statement_specifier # クリア 3463 3459 Generator.error( "G1009 unexpected specifier" ) 3464 3460 end … … 3831 3827 val[1].check 3832 3828 else 3833 # mikan é¢æ°ã®é 3834 åã以ä¸ã®ã¡ãã»ã¼ã¸ã«ãªã 3829 # mikan 関数の配列も以下のメッセージになる 3835 3830 Generator.error( "G1010 Not function" ) 3836 3831 result = nil … … 3887 3882 def _reduce_264(val, _values, result) 3888 3883 if val[3].kind_of? Port then 3889 val[3].set_specifier val[1] # è¨å®é åºãã3884 val[3].set_specifier val[1] # 設定順序あり 3890 3885 Celltype.new_port( val[3] ) 3891 3886 else 3892 # Port 以å¤ã§ã¯æå®åã¯ã¨ã©ã¼3887 # Port 以外では指定子はエラー 3893 3888 Generator.error( "G1012 $1 : cannot put specifier here" , val[1] ) 3894 3889 end … … 4095 4090 def _reduce_297(val, _values, result) 4096 4091 val[3].each{ |i| # i:Decl 4097 i.set_kind( :ATTRIBUTE ) # è¨å®é åºãã4092 i.set_kind( :ATTRIBUTE ) # 設定順序あり 4098 4093 i.set_specifier_list( [val[1]] ) 4099 4094 i.check … … 4177 4172 def _reduce_308(val, _values, result) 4178 4173 val[3].each{ |i| # i:Decl 4179 i.set_kind( :VAR ) # è¨å®é åºãã4174 i.set_kind( :VAR ) # 設定順序あり 4180 4175 i.set_specifier_list( [val[1]] ) 4181 4176 i.check … … 4458 4453 def _reduce_353(val, _values, result) 4459 4454 if val[0].kind_of?( Port ) then 4460 CompositeCelltype.new_port( val[0] ) # é 4461 延ãã¦ç»é² 4455 CompositeCelltype.new_port( val[0] ) # 遅延して登録 4462 4456 end 4463 4457 … … 4469 4463 def _reduce_354(val, _values, result) 4470 4464 if val[3].kind_of?( Port ) then 4471 # port ä»¥å¤ val[3] ã«æå¹ãªå¤ãå 4472 ¥ã£ã¦ããªãã®ã§ã以ä¸ã®ã¡ã½ãããé©ç¨ã§ããªã 4473 # ç¾ç¶ port, cell 以å¤ã¯æå®åãåãä»ããªã 4474 # ï¼ãããå°æ¥ä»ã®æãæå®åãåãä»ããå¯è½æ§ãããã®ã§ããã®ä½ç½®ã«è¨è¿°ããï¼ 4465 # port 以外 val[3] に有効な値が入っていないので、以下のメソッドを適用できない 4466 # 現状 port, cell 以外は指定子を受け付けない 4467 # (しかし将来他の文も指定子を受け付ける可能性があるので、この位置に記述する) 4475 4468 val[3].set_specifier( Generator.get_statement_specifier ) 4476 CompositeCelltype.new_port( val[3] ) # é 4477 延ãã¦ç»é² (set_specifier å¾) 4469 CompositeCelltype.new_port( val[3] ) # 遅延して登録 (set_specifier 後) 4478 4470 elsif val[3].kind_of?( Cell ) then 4479 # Cell.end_of_parse ã«ã¦è¨å®4471 # Cell.end_of_parse にて設定 4480 4472 else 4481 Generator.get_statement_specifier # ã¯ãªã¢4473 Generator.get_statement_specifier # クリア 4482 4474 Generator.error( "G1013 unexpected specifier" ) 4483 4475 end … … 4756 4748 if obj.kind_of?( Cell ) then 4757 4749 else 4758 Generator.get_statement_specifier # ã¯ãªã¢4750 Generator.get_statement_specifier # クリア 4759 4751 Generator.error( "G9999 unexpected specifier" ) 4760 4752 end … … 4854 4846 4855 4847 4856 # ãã¡ã¤ã« => INCLUDE("header")ã®é 4857 å 4848 # ファイル => INCLUDE("header")の配列 4858 4849 Include = Hash.new {|hash, key| hash[key] = []} 4859 4850 … … 4909 4900 4910 4901 #= TECSIO 4911 # Ruby2.0(1.9) 対å¿ã«ä¼´ãå°å 4912 ¥ããã¯ã©ã¹ 4913 # SJIS 以å¤ã§ã¯ãASCII-8BIT ã¨ãã¦å 4914 ¥åãã 4902 # Ruby2.0(1.9) 対応に伴い導入したクラス 4903 # SJIS 以外では、ASCII-8BIT として入力する 4915 4904 class TECSIO 4916 def self.foreach(file) # ãããã¯å¼æ° { |line| } 4917 pr = Proc.new # ãã®ã¡ã½ããã®ãããã¯å¼æ°ã pr ã«ä»£å 4918 ¥ 4905 def self.foreach(file) # ブロック引数 { |line| } 4906 pr = Proc.new # このメソッドのブロック引数を pr に代入 4919 4907 if $b_no_kcode then 4920 4908 msg = "E".encode $Ruby19_File_Encode 4921 4909 if( $Ruby19_File_Encode == "Shift_JIS" ) 4922 4910 4923 # Shift JIS ã¯ããã£ãã Windows-31J ã¨ãã¦èªã¿è¾¼ã¾ããShift_JIS ã«å¤æãããï¼4924 # ã³ã¡ã³ãçã«å«ã¾ãã SJIS ã«ä¸é©åãªæåã³ã¼ã㯠'?' ã¾ã㯠REPLACEMENT CHARACTER ã«å¤æãããï¼4925 # EUC ã UTF-8 ã§è¨è¿°ããã CDL ãæ··å¨ãã¦ãã¦ããRuby ä¾å¤ãçºçãããã¨ãªãå¦çãé²ãããã¨ãã§ããï¼4926 # æåã³ã¼ãæå®ã SJIS ã§ãã£ã¦ãæååãªãã©ã«ã®ä¸ã«ãæåã³ã¼ããSJIS 以å¤ã®é ASCII ãå«ã¾ãã¦ããå ´åã4927 # Ruby 1.8 ã® tecsgen ã§ã¯æåã³ã¼ãæå®ã«å½±é¿ãªãå¦çããããã®ããRuby 1.9 以éã§ã¯ '?' ã«ç½®ãæããå¯è½æ§ãããï¼4911 # Shift JIS は、いったん Windows-31J として読み込ませ、Shift_JIS に変換させる. 4912 # コメント等に含まれる SJIS に不適切な文字コードは '?' または REPLACEMENT CHARACTER に変換される. 4913 # EUC や UTF-8 で記述された CDL が混在していても、Ruby 例外が発生することなく処理を進めることができる. 4914 # 文字コード指定が SJIS であって、文字列リテラルの中に、文字コードがSJIS 以外の非 ASCII が含まれている場合、 4915 # Ruby 1.8 の tecsgen では文字コード指定に影響なく処理されたものが、Ruby 1.9 以降では '?' に置き換わる可能性がある. 4928 4916 4929 4917 mode = "r:Windows-31J" … … 4949 4937 end 4950 4938 4951 #=== æåã³ã¼ããç¸éããå ´åä¸è´ããã4952 # msg 㨠str ã®æåã³ã¼ããç¸éããå ´åãstr ã msg ã®æåã³ã¼ãã«å¤æãã4953 # å¤æä¸å¯ã®æåã³ã¼ã㯠'?' (utf-8 ã®å ´å U+FFFD (REPLACEMENT CHARACTER )) ã«å¤æ4939 #=== 文字コードが相違する場合一致させる 4940 # msg と str の文字コードが相違する場合、str を msg の文字コードに変換する 4941 # 変換不可の文字コードは '?' (utf-8 の場合 U+FFFD (REPLACEMENT CHARACTER )) に変換 4954 4942 # 4955 # ãã®ã¡ã½ããã¯ãã¨ã©ã¼ã¡ãã»ã¼ã¸åºåã§ã使ç¨ããã¦ãããã¨ã«æ³¨æï¼4943 # このメソッドは、エラーメッセージ出力でも使用されていることに注意. 4956 4944 # 4957 4945 #msg_enc::Encode | String 4958 4946 def self.str_code_convert( msg, str ) 4959 4947 if $b_no_kcode == false then 4960 return str # Ruby V1.8 ã¾ã§4948 return str # Ruby V1.8 まで 4961 4949 end 4962 4950 if msg.encoding != str.encoding then 4963 option = { :invalid => :replace, :undef => :replace } # ä¾å¤ãçºçãããã'?' ã«å¤æãã(utf-8 ã¯0xfffd)4951 option = { :invalid => :replace, :undef => :replace } # 例外を発生させず、'?' に変換する(utf-8 は 0xfffd) 4964 4952 # return str.encode( msg.encoding, option ) 4965 4953 str = str.encode( "utf-8", option ) -
Property svn:mime-type
changed from
Note:
See TracChangeset
for help on using the changeset viewer.