파서 생성기를 사용해야합니까, 아니면 내 자신의 렉서 및 파서 코드를 굴려야합니까?


답변:


78

실제로는 세 가지 옵션이 있습니다. 세 가지 옵션 모두 서로 다른 상황에서 선호됩니다.

옵션 1 : 파서 ​​생성기 또는 '일부 언어를 구문 분석해야하며 작동하게하고 싶습니다.

예를 들어, 지금 고대 데이터 형식에 대한 파서를 작성하라는 요청을 받았습니다. 또는 파서가 빠를 필요가 있습니다. 또는 파서를 쉽게 유지 관리 할 수 ​​있어야합니다.

이 경우 파서 생성기를 사용하는 것이 가장 좋습니다. 세부 사항을 살펴볼 필요가 없으며 올바르게 작동하기 위해 복잡한 코드를 많이 얻을 필요가 없으며 입력이 준수 할 문법을 작성하고 처리 코드를 작성하고 인스턴트 파서를 작성하십시오.

장점은 분명합니다.

  • 특히 입력 형식이 너무 이상하지 않은 경우 (일반적으로) 사양을 작성하는 것이 매우 쉽습니다 (옵션 2 인 경우 더 좋습니다).
  • 문법 정의는 일반적으로 코드보다 훨씬 자연스럽게 흐릅니다.
  • 좋은 파서 생성기에서 생성 된 파서는 일반적으로 직접 작성한 코드보다 훨씬 빠릅니다. 손으로 쓴 코드 더 빠를 있지만, 여러분이 알고있는 경우에만 가능합니다. 이것이 가장 널리 사용되는 컴파일러가 손으로 쓴 재귀 강하 파서를 사용하는 이유입니다.

파서 생성기에서는주의해야 할 것이 있습니다. 문법을 거부 할 수도 있습니다. 여러 유형의 파서에 대한 개요와 이들이 어떻게 물릴 수 있는지 알아 보려면 여기 에서 시작 하십시오 . 여기 에서 많은 구현과 그들이 받아들이는 문법 유형에 대한 개요를 찾을 수 있습니다.

옵션 2 : 손으로 쓴 파서 또는 '자신 만의 파서를 만들고 싶어하며 사용자 친화적 인 것을 좋아합니다'

파서 생성기는 훌륭하지만 사용자 (최종 사용자가 아닌)에게 친숙하지는 않습니다. 일반적으로 좋은 오류 메시지를 제공하거나 오류 복구를 제공 할 수 없습니다. 아마도 언어가 매우 이상하고 파서는 문법을 거부하거나 생성기가 제공하는 것보다 더 많은 제어가 필요합니다.

이러한 경우 수기 재귀-하강 파서를 사용하는 것이 가장 좋습니다. 올바르게 작성하는 것은 복잡 할 수 있지만 파서를 완벽하게 제어 할 수 있으므로 파서 생성기로 할 수없는 모든 종류의 멋진 작업 (예 : 오류 메시지 및 오류 복구) (C # 파일에서 모든 세미콜론 제거 시도)을 수행 할 수 있습니다 : C # 컴파일러는 불평하지만 세미콜론의 존재 여부에 관계없이 대부분의 다른 오류를 감지합니다).

손으로 쓴 파서는 또한 파서의 품질이 충분히 높다고 가정 할 때 일반적으로 생성 된 파서보다 성능이 좋습니다. 반면에 경험, 지식 또는 디자인의 부족으로 인해 좋은 파서를 작성하지 못하면 성능이 느려집니다. 어휘 분석기의 경우는 정반대입니다. 일반적으로 생성 된 어휘 분석기는 테이블 조회를 사용하여 (대부분의) 직접 작성하는 것보다 빠릅니다.

교육적인면에서 직접 파서를 작성하면 생성기를 사용하는 것보다 더 많은 것을 배울 수 있습니다. 결국 점점 더 복잡한 코드를 작성해야하며 언어를 구문 분석하는 방법을 정확하게 이해해야합니다. 반면에, 자신의 언어를 만드는 방법을 배우고 싶다면 (언어 디자인에 대한 경험을 얻으십시오), 옵션 1 또는 옵션 3을 사용하는 것이 좋습니다. 언어를 개발하는 경우 언어가 많이 바뀌고 옵션 1과 3은 더 쉬운 시간을 제공합니다.

옵션 3 : 손으로 쓴 파서 생성기 또는 '이 프로젝트에서 많은 것을 배우려고 노력하고 있으며 많은 재사용 할 수있는 멋진 코드로 끝나지 않아도됩니다'

이것이 내가 현재 걷고있는 길 입니다. 자신의 파서 생성기 를 작성 하십시오 . 매우 사소한 일이지만, 이렇게하면 아마도 가장 많이 가르 칠 것입니다.

이와 같은 프로젝트를 수행하는 데 필요한 아이디어를 제공하기 위해 본인의 진도에 대해 알려 드리겠습니다.

렉서 생성기

먼저 내 자신의 렉서 생성기를 만들었습니다. 나는 일반적으로 코드가 어떻게 사용되는지로 소프트웨어를 디자인하므로 코드를 어떻게 사용하고 싶었는지 생각 하고이 코드를 작성했습니다 (C #에 있음).

Lexer<CalculatorToken> calculatorLexer = new Lexer<CalculatorToken>(
    new List<StringTokenPair>()
    { // This is just like a lex specification:
      //                    regex   token
        new StringTokenPair("\\+",  CalculatorToken.Plus),
        new StringTokenPair("\\*",  CalculatorToken.Times),
        new StringTokenPair("(",    CalculatorToken.LeftParenthesis),
        new StringTokenPair(")",    CalculatorToken.RightParenthesis),
        new StringTokenPair("\\d+", CalculatorToken.Number),
    });

foreach (CalculatorToken token in
             calculatorLexer.GetLexer(new StringReader("15+4*10")))
{ // This will iterate over all tokens in the string.
    Console.WriteLine(token.Value);
}

// Prints:
// 15
// +
// 4
// *
// 10

입력 문자열 토큰 쌍은 산술 스택의 아이디어를 사용하여 나타내는 정규식을 설명하는 해당 재귀 구조로 변환됩니다. 그런 다음 NFA (비 결정적 유한 오토 마톤)로 변환되고 DFA (결정적 유한 오토 마톤)로 변환됩니다. 그런 다음 DFA와 문자열을 일치시킬 수 있습니다.

이런 식으로 렉서가 정확히 어떻게 작동하는지 좋은 아이디어를 얻습니다. 또한 올바른 방법으로 수행하면 어휘 분석기 생성기의 결과가 전문적인 구현만큼이나 빠를 수 있습니다. 또한 옵션 2에 비해 표현력을 잃지 않고 옵션 1에 비해 표현력을 잃지 않습니다.

1600 줄 이상의 코드로 렉서 생성기를 구현했습니다. 이 코드는 위의 작업을 수행하지만 프로그램을 시작할 때마다 즉시 어휘 분석기를 생성합니다. 어느 시점에서 디스크에 코드를 작성하는 코드를 추가하겠습니다.

당신이 당신의 자신의 렉서를 작성하는 방법을 알고 싶다면, 시작하기에 좋은 장소입니다.

파서 생성기

그런 다음 파서 생성기를 작성하십시오. 나는 다른 종류의 파서에 대한 개요를 다시 여기에서 참조한다. 경험상, 파싱이 많을수록 더 느리다.

속도가 문제가되지 않기 때문에 Earley 파서를 구현하기로 결정했습니다. Earley 파서의 고급 구현은 다른 파서 유형보다 약 두 배 느린 것으로 나타났습니다 .

그 속도에 대한 대가로, 모든 종류의 문법, 심지어 모호한 문법 을 파싱 할 수 있습니다. 즉, 파서에 왼쪽 재귀가 있는지 또는 시프트 감소 충돌이 무엇인지 걱정할 필요가 없습니다. 1 + 2 + 3을 (1 + 2) +3 또는 1로 구문 분석하는지 여부와 같이 결과 구문 분석 트리가 중요하지 않은 경우 모호한 문법을 ​​사용하여 문법을보다 쉽게 ​​정의 할 수도 있습니다. + (2 + 3).

파서 생성기를 사용하는 코드는 다음과 같습니다.

Lexer<CalculatorToken> calculatorLexer = new Lexer<CalculatorToken>(
    new List<StringTokenPair>()
    {
        new StringTokenPair("\\+",  CalculatorToken.Plus),
        new StringTokenPair("\\*",  CalculatorToken.Times),
        new StringTokenPair("(",    CalculatorToken.LeftParenthesis),
        new StringTokenPair(")",    CalculatorToken.RightParenthesis),
        new StringTokenPair("\\d+", CalculatorToken.Number),
    });

Grammar<IntWrapper, CalculatorToken> calculator
    = new Grammar<IntWrapper, CalculatorToken>(calculatorLexer);

// Declaring the nonterminals.
INonTerminal<IntWrapper> expr = calculator.AddNonTerminal<IntWrapper>();
INonTerminal<IntWrapper> term = calculator.AddNonTerminal<IntWrapper>();
INonTerminal<IntWrapper> factor = calculator.AddNonTerminal<IntWrapper>();

// expr will be our head nonterminal.
calculator.SetAsMainNonTerminal(expr);

// expr: term | expr Plus term;
calculator.AddProduction(expr, term.GetDefault());
calculator.AddProduction(expr,
                         expr.GetDefault(),
                         CalculatorToken.Plus.GetDefault(),
                         term.AddCode(
                         (x, r) => { x.Result.Value += r.Value; return x; }
                         ));

// term: factor | term Times factor;
calculator.AddProduction(term, factor.GetDefault());
calculator.AddProduction(term,
                         term.GetDefault(),
                         CalculatorToken.Times.GetDefault(),
                         factor.AddCode
                         (
                         (x, r) => { x.Result.Value *= r.Value; return x; }
                         ));

// factor: LeftParenthesis expr RightParenthesis
//         | Number;
calculator.AddProduction(factor,
                         CalculatorToken.LeftParenthesis.GetDefault(),
                         expr.GetDefault(),
                         CalculatorToken.RightParenthesis.GetDefault());
calculator.AddProduction(factor,
                         CalculatorToken.Number.AddCode
                         (
                         (x, s) => { x.Result = new IntWrapper(int.Parse(s));
                                     return x; }
                         ));

IntWrapper result = calculator.Parse("15+4*10");
// result == 55

(IntWrapper는 C #이 클래스 여야한다는 점을 제외하고는 단순히 Int32라는 점에 유의하십시오. 따라서 래퍼 클래스를 소개해야했습니다)

위의 코드가 매우 강력하다는 것을 알기를 바랍니다. 모든 문법을 파싱 할 수 있습니다. 많은 작업을 수행 할 수있는 문법에 임의의 코드 비트를 추가 할 수 있습니다. 이 모든 것이 제대로 작동하게되면 결과 코드를 재사용하여 많은 작업을 매우 쉽게 수행 할 수 있습니다.이 코드를 사용하여 명령 줄 인터프리터를 구축하는 것을 상상해보십시오.


3
고성능 파서와 어휘 분석기를 만드는 데 필요한 작업량을 과소 평가한다고 생각합니다.

나는 이미 내 자신의 렉서 생성기를 구축하고 다른 알고리즘을 대신하기로 결정했을 때 내 자신의 파서 생성기를 구축하는 것과 상당히 멀리 있었다. 모든 것이 제대로 작동하는 데 오랜 시간이 걸리지 않았지만 다시 '고성능', '좋은 성능'및 '엄 근한 점근 적 성능'을 목표로하지 않았습니다. C #을 사용하면 이미 성능 오버 헤드가 발생합니다.
Alex ten Brink

아주 좋은 대답입니다. 귀하의 선택에 동의합니다 Nr. 위에서 언급 한 모든 이유로 3. 그러나 필자의 경우와 마찬가지로 언어 디자인에 대해 매우 진지한 경우 직접 언어를 만들려고 할 때 파서 생성기를 사용해야 할 수도 있습니다. 따라서 언어 문제에 대해 먼저 시작할 수 있고 언어를보다 빠르게 이해할 수 있습니다
Lefteris

1
네 번째 옵션 인 파서 콤비 네이터가 있습니다.
YuriAlbuquerque

@AlextenBrink 우연히 github 계정이 있습니까? 나는 그 렉서 / 파서에 손을 대고 싶다. 당신이 만든 인상적인 것.
Behrooz

22

파서를 쓴 적이 없다면 나는 그것을 추천한다. 재밌고 일이 어떻게 작동하는지 배우고 파서와 렉서 생성기가 다음 에 파서를 필요로 할 때 절약하는 노력에 감사하는 법을 배웁니다 .

또한 http://compilers.iecc.com/crenshaw/ 를 읽는 것이 좋습니다 .


2
좋은 제안과 매우 유용한 링크.
Maniero

14

자체 재귀 강하 파서를 작성하면 구문 오류에 대해 고품질 오류 메시지 를 생성 할 수 있다는 장점이 있습니다. 파서 생성기를 사용하면 특정 지점에서 오류를 생성하고 사용자 지정 오류 메시지를 추가 할 수 있지만 파서 생성기는 구문 분석을 완벽하게 제어 할 수있는 능력과 일치하지 않습니다.

직접 작성하는 또 다른 장점은 문법과 일대일로 대응되지 않는 간단한 표현으로 구문 분석하기가 더 쉽다는 것입니다.

문법이 고정되어 있고 오류 메시지가 중요한 경우 직접 롤링하거나 최소한 필요한 오류 메시지를 제공하는 파서 생성기를 사용하는 것이 좋습니다. 문법이 계속 바뀌면 파서 생성기를 대신 사용해야합니다.

Bjarne Stroustrup은 C ++의 첫 번째 구현에 YACC를 사용한 방법에 대해 설명합니다 (C ++ 의 디자인 및 진화 참조 ). 첫 번째 경우에, 그는 대신 자신의 재귀 강하 파서를 작성하기를 원했습니다!


나는 첫 번째 실험이 파서 생성기를 사용해야한다는 것을 간신히 확신합니다. 당신은 나에게 맞춤형 솔루션으로 교체 할 수있는 몇 가지 장점을 주었다. 아직 아무것도 결정하지 않았지만 도움이되는 유용한 답변입니다.
Maniero

++이 대답은 내가 말하고자하는 것입니다. 나는 많은 언어를 만들었고 거의 항상 재귀 강하를 사용했습니다. 필자는 필요한 언어가 C 또는 C ++ (또는 Lisp) 위에 매크로를 계층화하여 가장 간단하게 구축 된 시간이 있다고 덧붙였습니다.
마이크 던 라비

JavaCC는 최상의 오류 메시지가 있다고 주장합니다. 또한 V8 및 Firefox에서 JavaScript 오류 및 경고 메시지를 확인했습니다. 파서 생성기를 사용하지 않은 것 같습니다.
Ming-Tang

2
@ SHiNKiROU : 실제로 JavaCC가 재귀 하향 구문 분석을 사용하는 것은 우연이 아닙니다.
Macneil

10

옵션 3 : 둘 다 (자신의 파서 생성기 롤링)

사용하지 않는 이유가해서 ANTLR , 들소 , 코코 / R , Grammatica , JavaCC에 , 레몬 , 살짝 데친 , SableCC , Quex , 등이 - 그 즉시 자신의 파서 + 렉서 롤해야 의미하지 않는다.

이러한 모든 도구가 충분하지 않은 이유를 파악 하십시오. 목표를 달성 할 수없는 이유는 무엇입니까?

다루는 문법의 이상한 점이 독특하지 않다면 단 하나의 맞춤식 파서 + 렉서를 만들면 안됩니다. 대신 원하는 것을 만들 수 있지만 향후 요구를 충족시키는 데 사용할 수있는 도구를 만든 다음 다른 사람들이 자신과 같은 문제를 겪지 않도록 자유 소프트웨어로 릴리스하십시오.


1
먼저 파서 생성기를 시도한 다음 사용자 지정 솔루션을 시도하지만 어떤 특정 (단점) 장점에 동의합니까? 이것은 거의 일반적인 조언입니다.
Maniero

1
일반적인 조언이지만 일반적인 질문을했습니다. : P 나는 내일 장단점에 대해 좀 더 구체적인 생각으로 확장 할 것이다.
피터 Boughton

1
사용자 정의 파서와 어휘 분석기를 만드는 데 필요한 작업량을 과소 평가한다고 생각합니다. 특히 재사용 가능한 것.

8

자신의 파서를 굴리면 언어의 복잡성에 대해 직접 생각하게됩니다. 언어를 파싱하기 어렵다면 아마도 이해하기 어려울 것입니다.

초기에는 파서 생성기에 관심이 많았으며, 고도로 복잡한 (일부는 "고문") 언어 구문에 의해 동기가 부여되었습니다. JOVIAL은 특히 나쁜 예입니다. 다른 모든 것이 최대 하나의 기호를 필요로 할 때 두 개의 기호를 미리보아야했습니다. 이로 인해 JOVIAL 컴파일러의 파서를 생성하는 것이 예상보다 어려워졌습니다 (General Dynamics / Fort Worth Division은 F-16 프로그램을 위해 JOVIAL 컴파일러를 조달 할 때 어려운 방법을 배웠습니다).

오늘날 재귀 강등은 보편적으로 선호되는 방법입니다. 컴파일러 작성자가 더 쉽기 때문입니다. 재귀 하강 컴파일러는 복잡하고 지저분한 언어보다 단순하고 깨끗한 언어에 대한 재귀 하강 파서를 작성하는 것이 훨씬 쉽다는 점에서 단순하고 깨끗한 언어 설계에 강력하게 보상합니다.

마지막으로, 언어를 LISP에 포함시키고 LISP 통역사가 귀하를 위해 많은 노력을 기울 이도록 하시겠습니까? AutoCAD는 그렇게했으며 삶이 훨씬 쉬워졌습니다. 약간의 가벼운 LISP 인터프리터가 있으며 일부는 임베디드 가능합니다.


커스텀 솔루션을 출시한다는 것은 흥미로운 주장입니다.
Maniero

1
아주 좋아요 나는 단지 포트란이 JOVIAL 이전에 사물을 파싱하기 위해 거의 임의의 (전선) lookahead가 필요하다는 정보의 지점으로 추가 할 것입니다. 그러나 당시에는 언어를 만드는 방법에 대해 다른 아이디어가 없었습니다.
Macneil

걷는 것은 가장 좋은 교통 수단으로,가는 곳으로가는 것이 실제로 가치가 있는지 생각할 시간을줍니다. 건강하다.
babou

6

상용 응용 프로그램 용 구문 분석기를 한 번 작성했으며 yacc을 사용했습니다 . 개발자가 C ++로 모든 것을 손으로 쓴 경쟁 프로토 타입이 있었고 약 5 배 느리게 작동했습니다.

이 파서의 어휘 분석기는 전적으로 직접 작성했습니다. 거의 10 년 전이어서 죄송합니다 . C 에서는 약 1000 줄 정도 입니다.

내가 직접 어휘 분석기를 작성한 이유는 파서의 입력 문법이었다. 필자가 디자인 한 것과는 달리 파서 구현이 준수 해야하는 요구 사항이었습니다. (물론 나는 그것을 다르게 설계했을 것이다. 그리고 더 낫다!) 문법은 상황에 따라 심각하고 어휘 분석은 어떤 장소에서는 의미론에 의존했다. 예를 들어, 세미콜론은 한 곳에서는 토큰의 일부이지만 다른 곳에서는 분리자가 될 수 있습니다. 이전에 파싱 된 일부 요소의 의미 론적 해석을 기반으로합니다. 그래서 필자가 직접 작성한 어휘 분석기에서 이러한 의미 론적 의존성을 "매장"시켰고, yacc에서 쉽게 구현할 수 있는 상당히 간단한 BNF를 갖게되었습니다.

ADDED 에 대한 응답으로 맥닐 은 yacc는 프로그래머를 할 수있는 매우 강력한 추상화를 제공 같은 단말기, 비 터미널, 제작 및 재료의 관점에서 생각. 또한 yylex()함수 를 구현할 때 현재 토큰을 반환하는 데 집중하고 전후에 무엇이 있는지 걱정하지 않아도되었습니다. C ++ 프로그래머는 이러한 추상화의 이점없이 문자 수준에서 작업했으며 더 복잡하고 덜 효율적인 알고리즘을 만들었습니다. 우리는 느린 속도는 C ++ 자체 나 다른 라이브러리와 아무 관련이 없다고 결론지었습니다. 메모리에로드 된 파일로 순수한 파싱 속도를 측정했습니다. 파일 버퍼링 문제가 발생하면 yacc가이를 해결하기위한 도구가되지 않을 것입니다.

추가해야 할 사항 : 이것은 일반적으로 파서를 작성하는 레시피가 아니며 특정 상황에서 어떻게 작동했는지에 대한 예일뿐입니다.


수작업으로 5 배 느린 C ++ 구현이 궁금합니다. 파일 버퍼링이 좋지 않았을 수 있습니다. 큰 차이를 만들 수 있습니다.
Macneil

@ Macneil : 내 답변에 추가 내용을 게시하겠습니다. 댓글이 너무 깁니다.
azheglov

1
++ 좋은 경험. 나는 성능에 너무 많은 비중을 두지 않을 것입니다. 그렇지 않으면 좋은 프로그램이 어리 석고 불필요한 것에 의해 느려질 수 있습니다. 나는하지 말아야 할 것을 알기 위해 재귀 강하 파서를 충분히 작성 했으므로 훨씬 빠른 것이 있는지 의심합니다. 결국, 문자를 읽어야합니다. 테이블을 실행하는 파서가 약간 느릴 지 모르지만 아마 눈치 채지 못할 것입니다.
마이크 던 라비

3

그것은 전적으로 구문 분석해야 할 것에 달려 있습니다. 어휘 분석기의 학습 곡선에 도달 할 수있는 것보다 더 빨리 자신을 굴릴 수 있습니까? 나중에 결정을 후회하지 않을 정도로 구문 분석 할 내용이 정적인가? 기존 구현이 지나치게 복잡하다고 생각하십니까? 그렇다면 스스로 배우는 재미가 있지만 학습 곡선을 피하지 않는 경우에만 가능합니다.

최근에 나는 레몬 파서 를 정말 좋아했다 . 이것은 내가 사용했던 것 중 가장 간단하고 쉬운 것입니다. 유지 관리하기 쉽도록 대부분의 요구에 사용합니다. SQLite는 다른 주목할만한 프로젝트뿐만 아니라 그것을 사용합니다.

그러나, 나는 렉서에 전혀 관심이 없으며, 내가 그것을 사용해야 할 때 방해가되지 않습니다 (따라서 레몬). 당신은 아마도 그렇게한다면 왜 그렇게하지 않겠습니까? 나는 당신이 존재하는 것을 다시 사용하게 될 느낌이 있지만, 당신이해야한다면 가려움증을 긁습니다 :)


3
"어휘 분석기의 학습 곡선에 도달 할 수있는 것보다 빠르게 자신을 굴릴 수 있습니까?"+1
보바

그래, 좋은 지적이야
Maniero

3

목표가 무엇인지에 달려 있습니다.

파서 / 컴파일러 작동 방식을 배우려고 노력하고 있습니까? 그런 다음 처음부터 직접 작성하십시오. 그것이 그들이하는 일의 모든 내용에 대해 감사하는 법을 배우는 유일한 방법입니다. 나는 지난 몇 달 동안 글을 썼는데, 흥미롭고 가치있는 경험이었고, 특히 '아, 그래서 언어 X가 이것을하는 이유는 ...'순간이었습니다.

마감일에 응용 프로그램을 위해 신속하게 무언가를 정리해야합니까? 그런 다음 파서 도구를 사용하십시오.

향후 10 년, 20 년, 심지어 30 년 동안 확장하고 싶은 것이 필요하십니까? 직접 작성하고 시간을 가지십시오. 그만한 가치가 있습니다.


컴파일러에 대한 첫 번째 작업, 학습 / 실험 및 오랫동안 그것을 유지하려는 의도입니다.
Maniero

3

Martin Fowlers 언어 워크 벤치 접근법 을 고려 했습니까 ? 기사에서 인용

언어 워크 벤치가 방정식을 만드는 가장 명백한 변화는 외부 DSL을 쉽게 만들 수 있다는 것입니다. 더 이상 파서를 작성할 필요가 없습니다. 추상 구문을 정의해야하지만 실제로는 매우 간단한 데이터 모델링 단계입니다. 또한 DSL은 강력한 IDE를 제공하지만 편집기를 정의하는 데 약간의 시간을 소비해야합니다. 발전기는 여전히해야 할 일이며 내 감각은 그 어느 때보 다 훨씬 쉽지 않다는 것입니다. 그러나 우수하고 간단한 DSL을위한 생성기를 구축하는 것이 가장 쉬운 방법 중 하나입니다.

그것을 읽으면, 나는 자신의 파서를 작성하는 시대가 끝났 으며 사용 가능한 라이브러리 중 하나를 사용하는 것이 좋습니다. 라이브러리를 마스터 한 후에는 나중에 만드는 모든 DSL이 해당 지식을 활용할 수 있습니다. 또한 다른 사람들은 구문 분석에 대한 접근 방식을 배울 필요가 없습니다.

주석 (및 수정 된 질문)을 포함하도록 편집

자신의 롤링의 장점

  1. 당신은 파서를 소유하고 복잡한 일련의 문제를 통해 사랑스런 사고 경험을 얻습니다.
  2. 아무도 생각하지 않은 특별한 것을 생각해 낼 수 있습니다 (아마도 그러나 당신은 영리한 녀석처럼 보입니다)
  3. 그것은 당신이 흥미로운 문제를 계속 차지할 것입니다

한마디로, 당신은 당신이 강하게 동기를 느끼게하는 심각하게 어려운 문제의 창자에 깊이 빠져들고 싶을 때 자신을 굴려야합니다.

다른 사람의 라이브러리를 사용할 때의 장점

  1. 휠을 다시 발명하지 않아도됩니다 (프로그래밍의 일반적인 문제)
  2. 최종 결과에 집중할 수 있고 (새 언어를 빛나게 함) 구문 분석 방법에 대해 너무 걱정하지 않아도됩니다.
  3. 당신은 당신의 언어가 훨씬 빨리 작동하는 것을 보게 될 것입니다.

따라서 빠른 결과를 원하면 다른 사람의 라이브러리를 사용하십시오.

전반적으로, 이것은 당신이 문제를 얼마나 많이 소유하고 싶은지 선택하여 솔루션을 결정합니다. 당신이 그것을 원한다면 자신의 롤.


사고에 대한 훌륭한 대안입니다.
Maniero

1
@bigown 편집은 더 나은 귀하의 질문에 대답
게리 로우

2

자신의 글을 쓰는 것의 가장 큰 장점은 자신의 글을 쓰는 방법을 알 수 있다는 것입니다. yacc와 같은 도구를 사용하면 얻을 수있는 가장 큰 장점은 도구 사용법을 알 수 있다는 것입니다. 나는 초기 탐사를위한 나무 꼭대기 의 팬입니다 .


특별히 도움이되지 않습니다. “운전을 배우는 것의 장점은 운전할 수 있다는 것입니다. 자전거 타는 법을 배우는 것의 장점은 자전거를 타는 것입니다.”
Zearin

1

왜 오픈 소스 파서 생성기를 포크하여 직접 만들지 않겠습니까? 파서 생성기를 사용하지 않으면 언어 구문을 크게 변경하면 코드를 유지하기가 매우 어려워집니다.

파서에서 정규 표현식 (Perl 스타일)을 사용하여 토큰 화하고 편리한 함수를 사용하여 코드 가독성을 높였습니다. 그러나, 파서 생성 된 코드는 빠른 상태 테이블과 긴함으로써 할 수 있습니다 switch- case당신이하지 않는 소스 코드의 크기를 증가시킬 수의, .gitignore그들.

다음은 사용자 정의 작성 파서의 두 가지 예입니다.

https://github.com/SHiNKiROU/DesignScript- 기본 방언으로, 배열 표기법으로 미리보기를 작성하기에는 너무 게으 르기 때문에 오류 메시지 품질을 희생했습니다 https://github.com/SHiNKiROU/ExprParser- 수식 계산기. 이상한 메타 프로그래밍 트릭에 주목하십시오


0

"이 시도되고 테스트 된 '바퀴'를 사용하거나 다시 만들어야합니까?"


1
이 "바퀴"는 무엇입니까? ;-)
Jason Whitehorn

IMO 이것은이 질문에 대한 좋은 의견이 아닙니다. 이것은 특정 경우에 적합하지 않은 일반적인 조언입니다. area51.stackexchange.com/proposals/7848 제안서가 조기 종료 된 것으로 의심 됩니다.
Maniero

2
바퀴가 다시 발명되지 않았다면, 우리는 매일 100kmph 이상의 속도로 주행하지 않을 것입니다. 너무 많은 차량?
피터 Boughton

그것은 올바른 의견이며 올바른 직관입니다. 특정 장점이나 단점을 나열 할 수 있다면이 답변이 더 도움이 될 것이라고 생각합니다. 이러한 종류의 상황은 전적으로 상황에 달려 있기 때문입니다.
Macneil

@Peter : 무언가를 재창조하는 것이 한 가지이지만 (완전히 다른 의미를 가짐) 기존 요구 사항을 추가 요구 사항에 맞게 수정하는 것이 좋습니다. 나는 모두 '개선'에 대한 것이지만 이미 해결 된 문제에 대해 드로잉 보드로 돌아가는 것은 잘못된 것 같습니다.
JBR 윌킨슨
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.