2016-09-01 7 views
1

私はRuby::Parsletを使用しています。Ruby:システムVerilogインタフェースパーサーのパレット

私は例えば、SVインターフェースに似た文書を解析しています:ここで

interface my_intf; 
    protocol validonly; 

    transmit [Bool] valid; 
    transmit [Bool] pipeid; 
    transmit [5:0] incr; 
    transmit [Bool] sample; 

endinterface 

は私のパーサーです:

class myParse < Parslet::Parser 
    rule(:lparen)  { space? >> str('(') >> space? } 
    rule(:rparen)  { space? >> str(')') >> space? } 
    rule(:lbox)  { space? >> str('[') >> space? } 
    rule(:rbox)  { space? >> str(']') >> space? } 
    rule(:lcurly)  { space? >> str('{') >> space? } 
    rule(:rcurly)  { space? >> str('}') >> space? } 
    rule(:comma)  { space? >> str(',') >> space? } 
    rule(:semicolon) { space? >> str(';') >> space? } 
    rule(:eof)  { any.absent? } 
    rule(:space)  { match["\t\s"] } 
    rule(:whitespace) { space.repeat } 
    rule(:space?)  { whitespace.maybe } 
    rule(:blank_line) { space? >> newline.repeat(1) } 
    rule(:newline) { str("\n") } 

    # Things 
    rule(:integer) { space? >> match('[0-9]').repeat(1).as(:int) >> space? } 
    rule(:identifier) { match['a-z'].repeat(1) } 


    rule(:intf_start)  { space? >> str('interface') >> space? >> (match['a-zA-Z_'].repeat(1,1) >> match['[:alnum:]_'].repeat(0)).as(:intf_name) >> space? >> str(';') >> space? >> str("\n") } 
    rule(:protocol)  { space? >> str('protocol') >> whitespace >> (str('validonly').maybe).as(:protocol) >> space? >> str(';') >> space? >> str("\n") } 
    rule(:bool)   { lbox >> space? >> str('Bool').as(:bool) >> space? >> rbox } 
    rule(:transmit_width) { lbox >> space? >> match('[0-9]').repeat.as(:msb) >> space? >> str(':') >> space? >> match('[0-9]').repeat.as(:lsb) >> space? >> rbox } 
    rule(:transmit)  { space? >> str('transmit') >> whitespace >> (bool | transmit_width) >> whitespace >> (match['a-zA-Z_'].repeat(1,1) >> match['[:alnum:]_'].repeat(0)).as(:transmit_name) >> space? >> str(';') >> space? >> str("\n") } 
    rule(:interface_body) { (protocol | blank_line.maybe) } 
    rule(:interface)  { intf_start >> interface_body } 

    rule(:expression)  { (interface).repeat } 

    root :expression 
end 

私はinterface_bodyのためのルールを作る問題を抱えています。

それは0以上transmitラインおよび0または1 ラインと複数の空白を持つことができ、コメントなど

は、誰かが私をしてください助けることはできますか?私がコードスニペットで書いたルールは、transmitというシングルとという単一のもので動作します。つまり、それらは適切に一致しますが、インターフェイス全体を解析すると機能しません。

ありがとうございます。

答えて

1

Ok ...これは、あなたが言及したファイルを解析します。私は希望のフォーマットを理解していないので、それはあなたのすべてのファイルに対してうまくいくとは言いませんが、うまくいけば、これはあなたを始めるでしょう。

require 'parslet' 

class MyParse < Parslet::Parser 
    rule(:lparen)  { space? >> str('(') } 
    rule(:rparen)  { space? >> str(')') } 
    rule(:lbox)  { space? >> str('[') } 
    rule(:rbox)  { space? >> str(']') } 
    rule(:lcurly)  { space? >> str('{') } 
    rule(:rcurly)  { space? >> str('}') } 
    rule(:comma)  { space? >> str(',') } 
    rule(:semicolon) { space? >> str(';') } 
    rule(:eof)  { any.absent? } 
    rule(:space)  { match["\t\s"] } 
    rule(:whitespace) { space.repeat(1) } 
    rule(:space?)  { space.repeat(0) } 
    rule(:blank_line) { space? >> newline.repeat(1) } 
    rule(:newline) { str("\n") } 

    # Things 
    rule(:integer) { space? >> match('[0-9]').repeat(1).as(:int) >> space? } 
    rule(:identifier) { match['a-z'].repeat(1) } 

    def line(expression) 
    space? >> 
    expression >> 
    space? >> 
    str(';') >> 
    space? >> 
    str("\n")  
    end 

    rule(:expression?) { (interface).repeat(0) } 

    rule(:interface)  { intf_start >> interface_body.repeat(0) >> intf_end } 

    rule(:interface_body) { 
    intf_end.absent? >> 
    interface_bodyline >> 
    blank_line.repeat(0) 
    } 

    rule(:intf_start) { 
    line ( 
     str('interface') >> 
     space? >> 
     (match['a-zA-Z_'].repeat(1,1) >> 
     match['[:alnum:]_'].repeat(0)).as(:intf_name) 
    ) 
    } 

    rule(:interface_bodyline) { 
    line (protocol | transmit) 
    } 

    rule(:protocol)  { 
    str('protocol') >> whitespace >> 
    (str('validonly').maybe).as(:protocol) 
    } 

    rule(:transmit)  {  
    str('transmit') >> whitespace >> 
    (bool | transmit_width) >> whitespace >> 
    name.as(:transmit_name) 
    } 

    rule(:name) { 
    match('[a-zA-Z_]') >> 
    (match['[:alnum:]'] | str("_")).repeat(0) 
    } 

    rule(:bool)   { lbox >> str('Bool').as(:bool) >> rbox } 

    rule(:transmit_width) { 
    lbox >> 
    space? >> 
    match('[0-9]').repeat(1).as(:msb) >> 
    space? >> 
    str(':') >> 
    space? >> 
    match('[0-9]').repeat(1).as(:lsb) >> 
    space? >> 
    rbox 
    } 

    rule(:intf_end)  { str('endinterface') } 

    root :expression? 
end 

    require 'rspec' 
    require 'parslet/rig/rspec' 

    RSpec.describe MyParse do 
    let(:parser) { MyParse.new } 
    context "simple_rule" do 
     it "should consume protocol line" do 
     expect(parser.interface_bodyline).to parse(' protocol validonly; 
') 
     end 
     it 'name' do 
     expect(parser.name).to parse('valid') 
     end 
     it "bool" do 
     expect(parser.bool).to parse('[Bool]') 
     end 
     it "transmit line" do 
     expect(parser.transmit).to parse('transmit [Bool] valid') 
     end 
     it "transmit as bodyline'" do 
     expect(parser.interface_bodyline).to parse(' transmit [Bool] valid; 
') 
     end 
    end 
    end 

    RSpec::Core::Runner.run(['--format', 'documentation']) 


begin 
    doc = File.read("test.txt") 
    MyParse.new.parse(doc) 
    rescue Parslet::ParseFailed => error 
    puts error.cause.ascii_tree 
    end 

主な変更点...

  • は、あなたのトークンの両方の側面を空白消費しないでください。 "[Bool] valid"をLBOX BOOL RBOX SPACEとして解析した式がありましたか?別のWHITESPACEが期待されましたが、それを見つけることができませんでした(以前のルールがそれを消費したため)。

  • 式がゼロ長(たとえばrepeat(0)のあるもの)として有効に解析され、誰が書き込んだかに問題がある場合は、奇妙なエラーが発生します。ルールは合格し、何も一致しない場合、通常は次のルールは失敗します。私は明示的に 'ボディライン'を 'エンドラインではない'とマッチさせたので、エラーで失敗するでしょう。

  • 'repeat'のデフォルトは(0)ですが、変更したいです。私はこの周りの間違いを常に見ます。

  • x.repeat(1,1)は1つの一致を意味します。それはxを持つことと同じです。 :)

  • は、より多くの空白の問題が

ので....

はトップからあなたのパーサーが書き留めました。下から上へテストを書く。 テストが終了したら、完了です! :)

幸運。

関連する問題