컴파일러 작성 컴파일러-사용 및 기능에 대한 이해


10

이것은 언어 프로젝트에 사용 된 개념을 프레임 워크 형태로 추상화하는 것을 목표로하는 추상화 프로젝트의 자매 프로젝트에 중점을 둔 일련의 질문의 일부입니다. 자매 프로젝트는 OILexer라고하며 일치하는 코드 삽입을 사용하지 않고 문법 파일에서 구문 분석기를 구성합니다.

구조 입력과 관련하여 다음 질문에 관련된 일부 다른 페이지는 볼 수 있습니다 여기에 , 사용의 용이성, 발견 여기에 . 프레임 워크에 대한 문의 및 적절한 게시 장소와 관련된 메타 주제는 여기 에서 찾을 수 있습니다 .

주어진 문법에서 구문 분석 트리를 추출하기 시작한 시점에 도달했습니다. 그런 다음 DFA를 사용하여 순방향 경로를 식별하는 재귀 하강 파서가 나옵니다 (ANTLR 4의 LL (*)과 유사). 통찰력을 얻기 위해 그것을 열 것이라고 생각했습니다.

파서 컴파일러에서 어떤 종류의 기능이 이상적입니까?

지금까지 구현 된 내용에 대한 간략한 개요는 다음과 같습니다.

  1. 템플릿
  2. 주어진 시점에서 무엇이 유효한지 미리 예측해보십시오.
  3. '리터럴 화'규칙은 규칙 내에서 리터럴을 가져 와서 어떤 토큰을 사용했는지 확인합니다.
  4. 비 결정적 오토마타
  5. 결정 론적 오토마타
  6. 토큰 인식을위한 간단한 어휘 상태 머신
  7. 토큰 자동화 방법 :
    • 스캔-주석에 유용합니다. 주석 : = "/ *"Scan ( "* /");
    • 빼기-식별자에 유용합니다. 식별자 : = 빼기 (IdentifierBody, Keyword);
      • 식별자가 키워드를 허용하지 않도록합니다.
    • 인코딩-기본 N 전환의 시리즈 X 카운트로 자동화를 인코딩합니다.
      • UnicodeEscape : = "\\ u"BaseEncode (IdentifierCharNoEscape, 16, 4);
        • 16 진수 4 전환을 사용하여 유니 코드 이스케이프를 16 진수로 만듭니다. 이 코드와 [0-9A-Fa-f] {4}의 차이점은 Encode를 사용한 자동화 결과로, 허용 된 16 진수 값 세트가 IdentifierCharNoEscape 범위로 제한됩니다. 따라서 \ u005c를 지정하면 인코딩 버전이 값을 허용하지 않습니다. 이와 같은 것들에는 심각한 경고가 있습니다. 결과 자동화는 상당히 복잡 할 수 있습니다.

구현되지 않은 것은 CST 생성입니다.이 작업을 수행하기 위해 적절한 컨텍스트를 전달하도록 결정적 자동화를 조정해야합니다.

관심있는 사람이라면 누구나 원래 형식의 T * y♯ 프로젝트를 꽤나 올렸습니다 . 각 파일은 다른 모든 파일에 연결되어야하며 개별 규칙에서 연결하기 시작하여 너무 오래 걸렸지 만 (자동화하기가 더 쉬웠을 것입니다!)

더 많은 컨텍스트가 필요한 경우 그에 따라 게시하십시오.

편집 5-14-2013 : 주어진 언어 내에서 상태 시스템에 대한 GraphViz 그래프를 작성하는 코드를 작성했습니다. AssemblyPart의 GraphViz digraph는 다음과 같습니다 . 언어 설명에 링크 된 멤버는 상대 규칙에 해당 규칙의 digraph와 함께 rulename.txt가 있어야합니다. 예제를 게시 한 후 일부 언어 설명이 변경되었습니다. 이는 문법에 대한 사항을 단순화했기 때문입니다. 흥미로운 graphviz 이미지가 있습니다.


8
Wall o 'text. 이것을 잘못된 방법으로 사용하지 마십시오. 철저히 설명 된 문제에 감사드립니다. 이 경우에는 단순히 너무 장황하다. 내가 수집 한 것부터 문법 구문 분석기에 어떤 기능을 포함 해야하는지 또는 처음부터 시작하지 않고 기능을 만드는 방법을 묻고 있습니까? 다음 질문에 대한 답변을 편집하십시오 (다시 작성할 필요가없고 요약 내용을 끝에 추가하면됩니다). 문제가 무엇입니까? 문제점에 대한 가능한 솔루션에서 어떤 제약 조건을 준수해야합니까 (빠르거나 LL * 등이어야 함)?
Neil

1
기능 세트에 대한 통찰력을 요구하고 있습니다. 사용 편의성에 중점을 둡니다. 어려움은 프로젝트를 모르는 사람이 프로젝트에 대한 통찰력을 갖도록하는 데 초점을 맞 춥니 다. 나는 '방법'을 요구하지 않고 사용 성과 관련하여 묻습니다. 질문을 정리하는 방법에 대한 제안을 부탁드립니다.
Allen Clark Copeland Jr

1
나에게, 프로젝트가 무엇에 관한 것인지는 분명하지 않습니다. 예를 들어, yacc 시절부터 우리는 많은 파서 생성기를 보았습니다. OILexer의 차이점은 무엇입니까? 새로운 것은 무엇입니까?
Ingo

1
이 프로젝트의 목표는 파서 ​​생성을 단순화하는 것입니다. YACC / Bison 및 FLEX / LEX와 유사합니다. 가장 큰 차이점은 해당 프로그램과 관련된 복잡성을 피하는 것입니다. 일을 간단하고 정확하게 유지하는 것이 주요 목표입니다. 그렇기 때문에 이상한 섹션이없는 형식을 만들었지 만 언어 개발에만 국한된 일반 프로그래밍과 비슷하게 만드는 것이 목표입니다. 토큰은 이름 뒤에 ': ='를 사용하여 정의되고, 규칙은 이름 뒤에 :: =를 사용하여 정의됩니다. 템플릿은 규칙 구문을 공유하므로 인수에 '<'및 '>'를 사용하고 뒤에 ":: ="를 사용합니다.
Allen Clark Copeland Jr

3
파싱에 대한이 지옥의 초점은 잘못 놓인 것 같습니다. 잘 해결 된 문제이며 프로그래밍 언어를 처리하는 데 필요한 것을 거의 알아 내지 못합니다. "구문 분석 후의 삶"에 대한 나의 에세이를위한 Google.
Ira Baxter

답변:


5

이것은 훌륭한 질문입니다.

최근에 많은 파싱 작업을 해왔으며 IMHO의 주요 기능 중 일부는 다음과 같습니다.

  • 프로그래밍 방식의 API-라이브러리를 가져 오기만하면 프로그래밍 언어 내에서 사용할 수 있습니다. GUI 또는 BNF와 같은 인터페이스도 가질 수 있지만 툴링, IDE, 정적 분석, 테스트, 언어 추상화 기능, 프로그래머 친숙성, 문서 생성기, 빌드 프로세스, 또한 작은 파서를 사용하여 대화식으로 재생할 수 있으므로 학습 곡선이 크게 줄어 듭니다. 이러한 이유로 인해 "중요 기능"목록의 맨 위에 배치됩니다.

  • @guysherman이 언급했듯이 오류보고. 오류가 발견되면 오류가 발생한 위치와 오류가 발생한 시점을 알고 싶습니다. 불행히도, 나는 역 추적을 할 때 적절한 오류를 생성하는 방법을 설명하는 좋은 자료를 찾지 못했습니다. (아래 @ Sk-logic의 의견에 유의하십시오).

  • 부분 결과. 구문 분석이 실패하면 오류 위치 이전의 입력 부분에서 구문 분석 된 내용을 볼 수 있기를 원합니다.

  • 추출. 충분한 기능을 구축 할 수 없으며 사용자는 항상 더 많은 기능이 필요하므로 가능한 모든 기능을 미리 알아내는 것은 실패로 끝납니다. 이것이 템플릿의 의미입니까?

  • 나는 당신의 # 2 (미리 예측)에 동의합니다. 좋은 오류 보고서를 생성하는 데 도움이된다고 생각합니다. 다른 것에 유용합니까?

  • 구문 분석이 발생할 때 구문 분석 트리 작성 지원 :

    • 구체적인 구문 트리는 트리의 구조가 문법에 직접 대응하며 이후 단계의 오류보고를위한 레이아웃 정보를 포함합니다. 이 경우 클라이언트는 올바른 트리 구조를 얻기 위해 아무 것도 하지 않아도됩니다 . 문법에 직접 의존해야합니다.
    • 추상 구문 트리 이 경우 사용자는 모든 파싱 트리를 사용하여 바이올린을 칠 수 있습니다.
  • 어떤 종류의 로깅. 나는 이것에 대해 확신하지 못한다. 구문 분석기가 시도한 규칙의 추적을 표시하거나 공백 또는 주석과 같은 정크 토큰을 추적하기 위해 (예를 들어) 토큰을 사용하여 HTML 문서를 생성하려는 경우가 있습니다.

  • 상황에 맞는 언어를 처리하는 능력. 이 언어가 얼마나 중요한지 확실하지 않습니다. 실제로 언어의 수퍼 세트를 컨텍스트가없는 문법으로 구문 분석 한 다음 나중에 추가 패스에서 컨텍스트 감지 제약 조건을 확인하는 것이 더 깔끔해 보입니다.

  • 특정 상황에서 오류 보고서를 조정하고 문제를보다 신속하게 이해하고 수정할 수 있도록 사용자 정의 오류 메시지.

다른 한편으로, 현재 진행 상황에 대해 최신 정보는 아니지만 오류 수정이 특히 중요하지 않습니다. 내가 목격 한 문제는 도구가 제공하는 잠재적 인 수정 사항이 1) 너무 많고 2) 실제 실수와 일치하지 않으므로 그다지 도움이되지 않는다는 것입니다. 이 상황이 개선되기를 바랍니다 (또는 이미 그렇게했을 것입니다).


'템플릿'이라는 글 머리 기호에 PrecedenceHelper에 대한 링크를 포함하도록 질문 본문을 편집했습니다. 매개 변수 배열 튜플을 허용하므로 매개 변수 배열이 각각 4 개인 경우 템플리트는 4의 인수 세트에서 사용해야합니다.
Allen Clark Copeland Jr

CST를 구성하는 주된 이유는 구문 분석 된 파일의 전체 레이아웃입니다. 문서 를 예쁘게 인쇄 하려면 AST에 CST가 캡처 할 홀수 간격을 처리 할 정보가 없기 때문에 CST를 사용하는 것이 가장 좋습니다. CST가 좋은 경우 CST 변환은 일반적으로 매우 쉽습니다.
Allen Clark Copeland Jr

사용할 수있는 내장 함수 주제에 대한 질문을 다시 편집했습니다.
Allen Clark Copeland Jr

나는 템플릿 / 함수에 대한 요점을 표현하는 데 큰 도움이되지 않았다고 생각했다. 자신의.

1
무한 역 추적 (Packrat)을 사용하여 오류보고에 특히 유용한 한 가지 접근 방법을 찾았습니다. 각 생산 규칙에는 오류 메시지 ( "blah-blah-blah expect"로 표시됨)가 주석으로 표시되고 실패시 이러한 메시지가 동일한 방식으로 스트림에 저장됩니다 메모 토큰으로. 모든 장애를 복구 할 수없는 경우 (스트림 끝에 도달하기 전에 구문 분석이 종결 됨) 가장 오른쪽에있는 오류 메시지 (또는 이러한 메시지 모음)가 가장 적합합니다. 그것은 가장 쉬운 방법입니다. 물론 더 많은 주석으로 더 구체화하는 방법이 있습니다.
SK-logic

5

나는 언어 디자인에 경험이 없지만 게임 엔진을 만들 때 IDE를 만들 때 한 번 파서를 작성했습니다.

제 생각에는 최종 사용자에게 중요한 것은 말이되는 오류 메시지입니다. 특히 지구를 산산조각내는 것은 아니지만, 거꾸로 따라 가면 이것의 주요 의미 중 하나는 오 탐지를 피할 수 있어야한다는 것입니다. 거짓 긍정은 어디에서 오는가? 파서는 첫 번째 오류에서 넘어져서 완전히 회복되지 않습니다. C / C ++는 이것으로 유명합니다 (최신 컴파일러는 조금 더 똑똑하지만).

그래서 대신에 무엇이 필요합니까? 나는 어떤 시점에서 유효하지 않은 / 무효를 아는 것보다는 유효하지 않은 것을 가져 와서 최소한으로 변경하여 유효하게 만들기 위해 최소한의 변경을해야한다고 생각합니다. 당신의 재귀 하강에 혼란스러워. 이 정보를 생성 할 수있는 파서를 만들 수 있으면 매우 강력한 파서를 얻을 수있을뿐만 아니라 파서를 사용하는 소프트웨어에 대한 환상적인 기능이 열립니다.

나는 이것이 사실이라면 정말 어려우거나 어리석은 것을 암시 할 수 있음을 알고 있습니다. 이것이 당신이 찾고있는 종류가 아닌 경우, 나는 행복하게 답변을 삭제합니다.


이것은 내가 계획하고있는 것 중 하나입니다. 도메인에 대한 나의 지식을 돕기 위해 내 친구가 실제 파서를 작성하여 자동화하는 것을 제안했습니다. 내가 매우 빨리 깨달은 한 가지는 : 파서는 복잡하고 프로세스를 단순화하는 수작업으로하는 일이다. 규칙과 템플릿은 동일한 구문을 공유합니다. 그러나 템플릿에는 유효하지만 규칙에는 적용되지 않는 언어 요소가 있으며이 작업을 처리하는 내부 상태가 있습니다. 아이디어가 떠 올랐습니다. 규칙은 하위 규칙을보다 쉽게 ​​공유 할 수 있도록 경로 보조 도구를 지정할 수 있어야합니다.
Allen Clark Copeland Jr

... 이것은 자동화로 넘어가는 것이 매우 간단해야하지만 자동화에는 상태 기반 조건이 있어야합니다. 이 작업을하고 다시 연락 드리겠습니다. ANTLR은 유한 상태 자동화를 사용하여 "T"*의주기를 처리합니다. 여기서는 규칙에 800 개 이상의 변형이있을 때 감소가 상태로 더 깨끗해야하기 때문에 대부분의 구문 분석 프로세스를 처리하는 데 사용합니다. 신속하게 표준 경우 / 다른 형태의 스파게티 코드로).
알렌 클라크 코플랜드 주니어

0

문법에는 "재귀 규칙을 남기지 마십시오"와 같은 제한이 없어야합니다. 오늘날 널리 사용되는 도구가 이것을 가지고 있으며 yacc 가 올바르게 수행 한지 거의 50 년이 지나서 LL 문법을 빨아들이는 것만 이해할 수 있다는 것은 우스운 일입니다 .

올바른 재귀에 대한 예 (yacc 구문 사용) :

list: 
      elem                  { $$ = singleton($1); }
    | elem ',' list         { $$ = cons($1, $2);  }
    ;

왼쪽 재귀의 예 (yacc synatx 사용) :

funapp:
    term                    { $$ = $1; }
    | funapp term           { $$ = application($1, $2); }
    ;

이제 이것은 다른 것으로 "리팩토링"될 수 있지만 두 경우 모두 특정 종류의 재귀는 이것을 작성하는 "올바른"방법입니다. (예제 언어에서) 목록은 재귀 적이지만 함수 응용 프로그램은 재귀 적입니다. .

고급 도구를 사용하면 도구가 하나에 부과하는 모든 것을 왼쪽 / 오른쪽 재귀로 "리팩토링"하는 대신 자연스럽게 물건을 쓸 수있는 방법을 지원한다고 기대할 수 있습니다.


그렇습니다. 그러한 제한이없는 것이 좋습니다. 그러나 반복 연산자 (예 : 정규식 *또는 +수량 자) 로 대체 할 수없는 왼쪽 재귀의 예는 무엇 입니까? 나는이 분야에 대한 나의 지식이 제한적이라는 것을 자유롭게 인정하지만, 반복으로 리팩토링 할 수없는 왼쪽 재귀를 사용하지는 않았다. 그리고 나는 반복 버전도 더 분명하다는 것을 알았습니다 (단지 개인적인 취향 일지라도).

1
@MattFenwick 내 편집 내용을 참조하십시오. 구문 지시문이 구문 트리 작성을위한 단순하고 자연스러운 의미 론적 조치 (예 :)를 유발하는 방법에 주목하십시오. 반복 (yacc, btw에서는 사용할 수 없음)을하는 동안 빈 목록, 싱글 톤 등이 있는지 자주 확인해야한다고 생각합니다.
Ingo

답변 주셔서 감사합니다. 내가 아니라 그 예를 작성하는 것을 선호 - 나는 지금 더 잘 이해 생각 list = sepBy1(',', elem)하고 funapp = term{+}(물론을 sepBy1하고 +왼쪽 / 오른쪽 재귀의 관점에서 구현 될 것이며, 표준 구문 트리를 생성). 따라서 왼쪽 및 오른쪽 재귀가 나쁘다고 생각하는 것이 아니라 저수준이라고 느끼고 가능한 한 더 높은 수준의 추상화를 사용하여 더 명확하게 만듭니다. 다시 감사합니다!

1
@MattFenwick을 환영합니다. 그러나 그것은 아마도 맛의 문제 일 것입니다. 저에게 재귀는 (자연적으로는 재귀 적이거나 전혀 무관 한 언어의 맥락에서) 더 자연스럽게 생각하는 방식입니다. 또한 트리는 재귀 데이터 구조이므로 재귀를 시뮬레이션하기 위해 반복으로 넘어갈 필요가 없습니다 . 그러나 물론 선호도는 다릅니다.
Ingo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.