racc で xvcd を生成することを試し始めた (その2)
前回の投稿では、xfy の xvcd には書式が似ていても正しくない出力だった。
前回の出力内容例
---------------
<instruction:variable name="message" select="'test ok'"/>
<instruction:message>
<xvcd:value-of>abc</xvcd:value-of>
<xvcd:value-of>xyz</xvcd:value-of>
</instruction:message>
今回は、xvcd の一部分としてはそれなりに正しい出力が得られようにした。
今回の出力内容例
---------------
<instruction:variable name="message" select="'test ok'"/>
<instruction:message-box>
<xvcd:value-of select="'abc'"/>
<xvcd:value-of select="'xyz'"/>
</instruction:message-box>
<instruction:message-box>
<xvcd:value-of select="$message"/>
</instruction:message-box>
これを生成する入力ソースはこれ。
message = "test ok"
puts( "abc", "xyz" )puts( message )
今回は、
- ソース中の空行を無視するようにする
- select="..." の中を'文字列' とか $変数名 と出力する
ようにした。
racc ソースはこれ。(変更部は #-- katoy で印をつけた)
class IntpParser
ruleprogram :
| program stmt EOL
| program EOL #-- katoystmt : funcall
| assignfuncall : IDENT '(' args ')'
{
result = do_funcall( val[0], val[2] )
}
| IDENT '(' ')'
{
result = do_funcall( val[0], [] )
}args : primary
{
result = val
}
| args ',' primary
{
result.push val[2]
}assign : IDENT '=' primary
{
result = do_assign( val[0], val[2] )
}primary : IDENT
{
result = do_varref( result )
}
| NUMBER
{
result = "'" + val[0] + "'"
}
| STRING
{
result = "'" + val[0] + "'"
}end
---- inner
require 'rubygems'
require 'builder'
require 'pp'def initialize
@builder = Builder::XmlMarkup.new(:target=>STDOUT, :indent=>2)
@vtable = {}
enddef parse( f )
@q = []f.each do |line|
line.strip!
until line.empty? do
case line
when /¥A¥s+/, /¥A¥#.*/
;
when /¥A[a-zA-Z_]¥w*/
@q.push [ :IDENT, $&.intern ]
when /¥A¥d+/
@q.push [ :NUMBER, $&.to_i ]
when /¥A"(?:[^"¥¥]+|¥¥.)*"/
@q.push [ :STRING, eval($&) ]
when /¥A./
@q.push [ $&, $& ]
else
raise RuntimeError, 'must not happen'
end
line = $'
end
@q.push [ :EOL, nil ]
enddo_parse
enddef next_token
@q.shift
enddef do_funcall( func, args )
#-- katoy
if func == :puts
@builder.tag!("instruction:message-box") {
args.each do |k|
@builder.tag!("xvcd:value-of", "select"=> k)
end
}
end
enddef do_assign( vname, val )
#-- katoy
@vtable[ vname ] = '$' + vname.to_s
@builder.tag!("instruction:variable", "name"=>"#{vname}", "select"=>"#{val}")
enddef do_varref( vname )
@vtable[ vname ] or raise NameError, "un-initialized variable #{vname}"
end---- footer
parser = IntpParser.new
if ARGV[0] then
File.open( ARGV[0] ) do |f|
parser.parse f
end
else
parser.parse $stdin
end
次は、if else の条件文、関数定義 を追加しよう。
xfy/xvcd での <xvcd:choose> <xvcd:when>...</xvcd:otherwise> は書くのも読むのもちょっとシンドイ。これを少しでも簡易できればと思う。
for ループや while ループは、まずどのような xvcd を生成すべきかを検討する必要があるので、すぐには出来そうにないけど、if else は比較的簡単にできるだろうと予想している。
« ピックアップ:XML Pipeline Language, BitTorrentなアーケードゲーム, etc... | トップページ | ピックアップ:社内ブログ/社内SNS失敗学, Ruby で debug する7つの方法, etc ... »
この記事へのコメントは終了しました。
« ピックアップ:XML Pipeline Language, BitTorrentなアーケードゲーム, etc... | トップページ | ピックアップ:社内ブログ/社内SNS失敗学, Ruby で debug する7つの方法, etc ... »
コメント