2016-09-01 2 views
1

Ruby::Parslet을 사용하고 있습니다.Ruby : 시스템 Verilog 인터페이스 파서에 대한 파슬

내가 SV 인터페이스와 유사한 문서, 예를 들어 분석하고 있습니다 :

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에 대한 규칙을 만드는 문제를 겪고 : 여기

interface my_intf; 
    protocol validonly; 

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

endinterface 

나의 파서입니다.

그것은 등 0 개 이상의 transmit 라인과 0 또는 1 라인과 여러 공백, 주석을 가질 수

누군가가 제발 도와 줄래? 코드 스 니펫에 작성한 규칙은 transmit 및 과 같이 작동합니다. 즉, 올바르게 일치하지만, 전체 인터페이스를 구문 분석하면 작동하지 않습니다.

미리 감사드립니다.

답변

1

좋아요 ... 이것은 당신이 언급 한 파일을 분석합니다. 원하는 형식을 이해할 수 없어 모든 파일에서 작동한다고 말할 수 없지만 잘하면이 작업을 시작할 수 있습니다.

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로 구문 분석 한 표현식이 있습니까? 그리고 나서 다른 화이트 테이블을 기대했지만 하나를 찾을 수 없었습니다 (이전 규칙이 그것을 소비했기 때문에).

  • 표현식이 0 길이 (예 : repeat (0)가있는 무언가)로 유효하게 구문 분석되고 작성된 사람에게 문제가있는 경우 이상한 오류가 발생합니다. 규칙은 통과하고 아무것도 일치하지 않으며, 다음 규칙은 일반적으로 실패합니다. 나는 'body line'을 'end line이 아니라'명시 적으로 'match'했으므로 오류가 발생하여 실패합니다.

  • '반복'기본값은 (0)으로 변경하고 싶습니다. 나는이 모든 시간에 실수를 보았다.

  • x.repeat (1,1)는 일치하는 것을 의미합니다. 그것은 x를 갖는 것과 같습니다. :) 더 공백 문제

그래서

이 .... 있었다

  • 은 위에서 아래로 파서를 작성합니다. 아래에서 위로 테스트를 작성하십시오. 테스트가 끝나면 완료됩니다! :)

    행운을 빈다.

  • 관련 문제