前回は2進数リテラルのパーサを書いた。
今回はそれを拡張して整数型をパースするパーサを書いてみる。
8進型と16進型
この2種類については 2 進数と digit の種類及び base 識別子が変わるのみで
ほかは変わりが無い。そこで、2進数の定義部分を関数にして一括で定義してみる。
# 前回見落としていた、不定値とHi-Zのリテラル
rule(:x_digit){ match('[xX]') }
rule(:z_digit){ match('[zZ?]') }
rule(:underscore){ str('_') }
rule(:nz_dec_digit){ match('[0-9]') }
rule(:dec_digit) { str('0') | nz_dec_digit }
rule(:nz_uint) { nz_dec_digit >> (underscore | dec_digit).repeat }
# よく使うルールを先に定義
rule(:size?) { nz_uint.maybe.as(:size) }
rule(:signed_base) { match('[sS]') }
rule(:quote) { str('\'') }
# 2, 8, 16 進数のルールを定義する関数
def self.num_rule(define)
define.each do |d|
rule("#{d[:name]}_digit") { x_digit | z_digit | match(d[:digit]) }
rule("#{d[:name]}_val") {
eval("#{d[:name]}_digit") >> (underscore | eval("#{d[:name]}_digit")).repeat
}
rule("#{d[:name]}_base") {
signed_base.maybe >> match(d[:base])
}
rule("#{d[:name]}_number") {
size? >> quote >>
self.instance_eval("#{d[:name]}_base").as(:base) >>
self.instance_eval("#{d[:name]}_val").as(:value)
}
end
end
途中で定義したルールを呼び出す際に eval
している。digit 部分を rule
で定義せずに
digits = x_digit | z_digit | match(d[:digit])
と出来ないかと試してみたが、x_digit
がundefined local variable
と怒らたために上記のように
定義した。
10進数のルール
Verilog で 10進数の定義は2種類あり、
10'd1023; //10bitの整数 1023
1023; //32bitの整数 1023
4'dx__; //4bitの不定値
4'dz_; //4bitのHi-Z
なので、bit幅とbase指示子の無い場合も考慮する必要がある。また、数値部分も10進数では
数値と x
, z
の文字が混ざる事が無い。とりあえず以下の用に定義。
どうやら rule
ブロックの中では代入演算が可能なようだ。
rule(:unsigned_number){ dec_digit >> (underscore | dec_digit).repeat }
rule(:decimal_base) { signed_base.maybe >> match('[dD]') }
rule(:decimal_number) {
dec_number = unsigned_number.as(:value)
dec_number = dec_number | size? >> quote >> decimal_base >> unsigned_number.as(:value)
dec_number = dec_number | size? >> quote >> decimal_base >>
x_digit.as(:value) >> underscore.repeat
dec_number = dec_number | size? >> quote >> decimal_base >> z_digit >> underscore.repeat
dec_number
}
整数型のルールをまとめる
これで出来た2,8,10,16進を一つの :integral_number
としてルールにする。
rule(:integral_number){
hex_number | decimal_number | octal_number | binary_number
}
今回作った整数パーサ
今回作った Verilog の整数パーサのソースを gistに載せておく。