2017-12-10 10 views
3

Superpower으로 파서를 만들려고합니다. 나는 repo에서 찾은 샘플을 이미 살펴 봤지만, 적어도 나 같은 초보자는 이해하기가 약간 어렵다. 그래서 나는이 작은 도전을했다.초강력으로 간단한 텍스트 문법을 구문 분석

저는 배우기 위해 아주 기본적인 문법을 발명했습니다. 나는 올라가고, 내려 가서 기다릴 지침 목록을 따르는 엘리베이터를 생각해 보았다.

예 :

(UP 100), 
(DOWN 200), 
(DOWN 100), 
(DOWN @1), 
(UP @3), 
(WAIT), 
(UP 300) 

보는 바와 같이, 예를 들어, 엘리베이터를 이동 쉼표로 구분 동사의리스트로 구성된다.

  • 동사는 또는 DOWN WAIT UP이다.
  • 마다 동사는 호로되어 ()는
  • UP은 DOWN절대 값 또는 엘리베이터가 이동되어야하는 층을 나타내는 상대 번호, 어느 하나를 필요로한다. 상대방 층 번호는 숫자 앞에 @ 기호가 붙습니다.
  • WAIT은 엘리베이터를 잠시 중지하기 때문에 숫자를 허용하지 않습니다.

SuperPower 사용법을 이해하기 위해이 문법의 토큰 기반 파서를 처음 만드는 방법을 배우고 싶습니다.

아무도 도와 주시겠습니까?

미리 감사드립니다.

+0

[this] (https://github.com/datalust/superpower/tree/dev/sample/DateTimeTextParser)? [readme] (https://github.com/datalust/superpower/blob/dev/README.md) 이외에도 많은 문서가 없지만 몇 가지 샘플과 문법 작성 방법을 보여주는 테스트가 있습니다. – dlatikay

+0

@PatrickArtner StackOverflow를 더 좋은 곳으로 만들어 주셔서 감사합니다. – SuperJMN

+0

@dlatikay 감사합니다. 나는 그 샘플을 알고 있지만 여전히 그것을 처리 할 수 ​​없습니다. 그래서 어리석은 샘플을 만들었습니다. 배우기 위해서였습니다. 기존 문서를 사용하여 요청한 파서를 만들 수 있다면 공유하십시오. – SuperJMN

답변

5

Superpower 파서를 작성하는 단계 1은 토큰 종류가 무엇인지 파악하는 것입니다.

// ECL - Elevator Control Language ;-) 
enum EclToken { 
    LParen, 
    RParen, 
    UpKeyword, 
    DownKeyword, 
    WaitKeyword, 
    AtSymbol, 
    Number, 
    Comma 
} 

2 단계,Tokenizer<EclToken> 쓰기 : 당신은 뭔가를 가지고있다. 이것은 Superpower v1에 의해 직접적인 프로그래밍 작업으로 남겨집니다 - 기댈 수있는 도우미가 많지 않으므로 the examples과 같이 코드를 작성하면됩니다.

tokenizer는 입력 문자열을 가져 와서 공백을 제거하고 토큰 시퀀스가 ​​무엇인지 파악합니다.

하여 예시적인 입력의

첫번째 줄 것이다 : 콘텐츠가 Number 같은 토큰

// (UP 100), 
LParen, UpKeyword, Number, RParen, Comma 

에서, Result<EclToken>와 연관된 기간 토큰에 대응하는 입력 문자열의 일부를 가리킬 것이다. 이 행의 번호는 TextSpan이고 100입니다.

단계 3으로 구문 분석하려는 것입니다. 중첩 된 표현식이있는 프로그래밍 언어의 경우 일반적으로 AST입니다.

struct ElevatorCommand {   
    public int Distance; // + or - 
    public bool IsRelative; 
} 

4 단계 파서 : 당신이 그것을 줄일 수 있도록 ECL 샘플의 경우, 매우 간단합니다. 이것은 일반적으로 정적 클래스에 포함됩니다. 파서의 임무는 더 간단한 결과 (숫자, 이동)에서 더 복잡한 결과 (여기서는 ElevatorCommand[])를 작성하는 것입니다.

이것은 Superpower가 특히 기대와 오류와 관련하여 과중한 작업을 수행하는 곳입니다.

static class EclParser 
{ 
    static TokenListParser<EclToken, int> Number = 
     Token.EqualTo(EclToken.Number).Apply(Numerics.IntegerInt32); 
} 

가장 먼저 할 일은 숫자에 대한 파서를 정의하는 것입니다. 이 중 하나는 을 EclToken.Number 범위의 콘텐츠에 적용합니다.

더 많은 구문 분석 기계를 this example에서 볼 수 있습니다.

몇 가지 더 단서 (/ 컴파일 말할 것도없고, 확인 테스트 구문되지 않음) 당신이 방법을 찾을 수 있도록 :

static TokenListParser<EclToken, ElevatorCommand> Up = 
     from _ in Token.EqualTo(EclToken.UpKeyword) 
     from distance in Number 
     select new ElevatorCommand { 
      Distance = distance, 
      IsRelative = false 
     }; 

    static TokenListParser<EclToken, ElevatorCommand> Command = 
     from lp in Token.EqualTo(EclToken.LParen) 
     from command in Up // .Or(Down).Or(Wait) 
     from rp in Token.EqualTo(EclToken.RParen) 
     select command; 

    static TokenListParser<EclToken, ElevatorCommand[]> Commands = 
     Command.ManyDelimitedBy(Token.EqualTo(EclToken.Comma)); 
} 

Commands은 입력에 적용 할 수있는 완성 된 파서입니다.

파서를 점진적으로 구축하고 각 작은 파서를 구문 분석 할 입력 덩어리에 대해 테스트하는 것이 가장 좋습니다.

+0

그래, 이해할 것 같아. 지금 당장 파서를 만들려고합니다 :) 지금은 의심 스럽습니다. ElevatorCommand는 거리 만 있고 상대 명령인지 여부 만 모델링했습니다. 그러나 WAIT 명령은 어떻게 표현 될까요? – SuperJMN

+1

'슈퍼 파워'의 'p'는 소박한 니트 피커 모서리에서 머리 위로 올라간다 :-) –

+1

쿨! 미안, 내 파스칼 케이스 마니아라고 생각해 .-P – SuperJMN

1

좋아, 나는 마침내 그것을 얻을 수 있었다. @Nicholas Blumhardt 's guidance :

시나리오를 설명하기 위해 a project in GitHub을 만들었습니다. 클래스는 게시물에 대한 큰이기 때문에, 나는 파일에 링크하고 있습니다 :