将ANTLR生成的.tokens文件重格式化(Ruby版)-20080626更新

相关链接:
[url=http://rednaxelafx.iteye.com/blog/177089]将ANTLR生成的.tokens文件重格式化(C++版)[/url]
[url=http://rednaxelafx.iteye.com/blog/177092]将ANTLR生成的.tokens文件重格式化(C#版)[/url]

ANTLR在对.g的语法文件生成Java代码的同时,还会生成一个.tokens文件来方便别的parser(例如说接在source parser后的tree parser)使用同样的token定义。
不过这tokens文件看起来不总是那么方便。举例来说,[url=http://rednaxelafx.iteye.com/blog/176524]昨天发的帖[/url]里Dolphin.g,对应的Dolphin.tokens文件如下:
Dolphin.tokens:
[code]FUNCTION=4
NullLiteral=31
WHILE=18
FloatTypeSuffix=38
OctalLiteral=33
CharacterLiteral=28
LBRACE=11
LineComment=44
FOR=19
DO=17
Exponent=37
RelationalOperator=24
HexDigit=35
BREAK=20
Identifier=5
LPAREN=6
IF=16
AssignmentOperator=15
RPAREN=7
CONTINUE=21
Comment=43
COMMA=8
AddOperator=25
RETURN=22
TypeSpecifier=10
VAR=13
HexLiteral=32
RBRACE=12
IntegerTypeSuffix=36
SEMICOLON=14
DecimalLiteral=34
AssignmentShorthandOperator=23
COLON=9
StringLiteral=29
WS=42
UnicodeEscape=40
FloatingPointLiteral=27
MulOperator=26
EscapeSequence=39
OctalEscape=41
BooleanLiteral=30[/code]

当我知道期望的token类型的名字时,上面的tokens文件可以帮我找到对应的数值常量;但当我在Eclipse里调试时,看到的只有"type",也就是token类型对应的数值常量,要找对应的名字就比较麻烦了。上上下下看得眼花。

于是我自然希望顺序能颠倒一下,数值常量在前,名字在后,并且按照数值常量的大小按升序排序。像这样:
Dolphin.tokens.txt:
[code]4=FUNCTION
5=Identifier
6=LPAREN
7=RPAREN
8=COMMA
9=COLON
10=TypeSpecifier
11=LBRACE
12=RBRACE
13=VAR
14=SEMICOLON
15=AssignmentOperator
16=IF
17=DO
18=WHILE
19=FOR
20=BREAK
21=CONTINUE
22=RETURN
23=AssignmentShorthandOperator
24=RelationalOperator
25=AddOperator
26=MulOperator
27=FloatingPointLiteral
28=CharacterLiteral
29=StringLiteral
30=BooleanLiteral
31=NullLiteral
32=HexLiteral
33=OctalLiteral
34=DecimalLiteral
35=HexDigit
36=IntegerTypeSuffix
37=Exponent
38=FloatTypeSuffix
39=EscapeSequence
40=UnicodeEscape
41=OctalEscape
42=WS
43=Comment
44=LineComment[/code]

这种苦力事情显然不值得开动笨重的Java或者C#,哦别提C++和C了。这个时候最能让我偷懒的办法就是最好的办法 XD

于是写了这样的一段Ruby脚本:
reformat.rb:
#!/usr/bin/env ruby
# reformat.rb

## Reformat a token file produced by ANTLR to the format:
## token_number=token_name

def reformat( infile, outfile )
lines = []

File.open infile, "r" do |file|
file.each do |line|
lines << "#{$2}=#{$1}" if line.chomp =~ /^([^=]+)=([0-9]+)$/
end
end

# yeah, i know this is slow, but we're not
# pushing for speed anyway
lines = lines.sort_by do |line|
line =~ /^[0-9]+/
$&.to_i
end

File.open outfile, "w" do |file|
lines.each { |line| file.puts line }
end
end

if ARGV.size != 2
puts "Usage: #{$0} [token file] [output file]"
exit
end

infile, outfile = ARGV
reformat infile, outfile


好吧,这段代码一点也不美。要是能把读写文件放在同一个循环里,顺带能排序就好了。这段代码仅有的好处就是没花多少时间去写而且功能符合我的需要,以后还可以继续用。
Ruby才刚开始用,希望有高手能指点指点怎么改进一下这代码~~

[color=blue](20080328更新:加入了下面的版本的代码。避免在传给sort_by的block中使用正则表达式。虽然在循环里用了to_i还是稍嫌不爽)
(20080329更新:发觉应该用Enumerable#grep的。也不用在sort_by的block里用to_i了。很好,更简洁了)
(20080626更新:File.open还是用带block的方式好。IO对象不关掉始终是不放心。另外,原本定义了一个类当作tuple用,想想其实没必要定义个类,直接用数组就够了)[/color]
reformat.rb:
#!/usr/bin/env ruby
# reformat.rb

## Reformat a token file produced by ANTLR to the format:
## token_number=token_name

def reformat( infile, outfile )
lines = []
File.open infile, "r" do |file|
file.grep /^([^=]+)=([0-9]+)$/ do |line|
lines.push [ $1, $2.to_i ] # name, value = $1, $2
end
end
lines = lines.sort_by { |pair| pair[1] }
File.open outfile, "w" do |file|
lines.each { |pair| file.puts "#{pair[1]}=#{pair[0]}" }
end
end

if ARGV.size != 2
puts "Usage: #{$0} [token file] [output file]"
exit
end

infile, outfile = ARGV
reformat infile, outfile


[color=blue](20100812更新:
当初写的Ruby跟现在写的Ruby果然还是比较不一样……)[/color]
#!/usr/bin/env ruby

def reformat(infile, outfile)
lines = File.readlines(infile).map {|l| l.chomp.split '='}.sort_by {|l| l.last.to_i}
File.open(outfile, 'w') {|f| f.puts lines.map {|l| l.reverse.join('=')}}
end

$*.size != 2 || reformat(*$*) and puts "Usage: #{$0} [token file] [output file]"

[color=blue]本来还是写ARGV比较好,不过能凑出(*$*)这么可爱的表情实在是忍不住想把ARGV写成$*啊 =_=|||[/color]

====================================================================

P.S. 当然这东西不用Ruby还有更快的实现方法,直接用UltraEdit就行。
首先确保UltraEdit的Advanced->Configuration->Search->Regular Expression Engine里,"Perl compatible Regular Expressions"打上了钩。(我不熟悉UE自己定义的Regex的规格,试了好几次都不行,放弃了,换回相对熟悉些的Perl系Regex)
然后Ctrl+R(或者Search->Replace),在Find What里输入
[code]^([^=]+)=([0-9]+)$[/code]
在Replace With里输入
[code]\2=\1[/code]
接着File->Sort->Advanced Sort/Options...,选Numeric Sort,完事。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值