C ++에 컨텍스트가 없거나 컨텍스트에 민감합니까?


405

나는 종종 C ++이 상황에 맞는 언어라는 주장을 듣는다. 다음 예제를 보자.

a b(c);

변수 정의 또는 함수 선언입니까? 그것은 상징의 의미에 달려 c있습니다. 경우 cA는 변수가 다음 a b(c);라는 변수 정의 b유형을 a. 로 직접 초기화됩니다 c. 하지만 cA는 유형 , 다음 a b(c);라는 함수 선언 b을 소요 c하고를 반환합니다 a.

문맥이없는 언어의 정의를 찾아 보면 기본적으로 모든 문법 규칙에 정확히 하나의 비단 말 기호로 구성된 왼쪽이 있어야 함을 알 수 있습니다. 반면 상황에 맞는 문법은 왼쪽에 임의의 문자열 문자열과 비 터미널 기호를 허용합니다.

"C ++ 프로그래밍 언어"의 부록 A를 살펴보면 왼쪽에 터미널이 아닌 단일 기호 외에 다른 문법 규칙이 없었습니다. 그것은 C ++에 컨텍스트가 없음을 의미합니다. 물론, 모든 문맥이없는 언어는 문맥이없는 언어가 문맥에 맞는 언어의 부분 집합을 형성한다는 점에서 문맥에 민감하지만, 요점이 아닙니다.

그렇다면 C ++ 컨텍스트가 없거나 컨텍스트에 민감합니까?


12
@CarlNorum 왼쪽에 단일 비단 말 기호로 구성되지 않은 C ++의 단일 문법 규칙을 보여 주시면 즉시 믿습니다.
fredoverflow 2018 년

9
IIUC 상황에 맞는 선을 그리는 위치에 따라 다릅니다. 필자는 CFG 구문 분석 도구를 사용하여 실제 컴파일러를 작성할 수 없기 때문에 거의 모든 정적으로 유형이 지정된 프로그래밍 언어가 상황에 따라 달라진다고 주장했지만 이러한 구현은 일부 잘못된 프로그램을 구문 분석하여 "속임수" 유형 검사 중에 나중에 거부합니다. 따라서 잘못된 유형의 프로그램이 CS 언어, 즉 문자열 집합과 같은 언어가 아닌 것으로 간주하는 경우 구문 분석기는 C ++보다 더 많은 언어가 문맥을 인식해야합니다.

6
@DeadMG : 아니오, 당신은 틀 렸습니다. 공식 언어 이론에는 "구문 분석"이나 "의미론"이 전혀 없으며 단지 문자열 집합 인 "언어"입니다.
jpalecek

27
지금까지 어떤 답변도 "문맥없는 문법"에 대한 귀하의 정의를 다루지 않았습니다. 제 생각에이 질문에 대한 정답은 여러분의 정의에 맞지 않는 부록 A의 작품을 인용하거나 귀하의 정의가 잘못되었거나 불충분하다는 것을 보여줍니다. 당신의 입장을 고수!
궤도에서 가벼움 경주

8
D의 문법에 실제로 문맥이 없는가?를 참조하십시오 . . 사실, 여기있는 모든 사람들이 그 질문과 답변을 읽어야 한다고 생각 합니다!
궤도에서 가벼움 경주

답변:


341

아래는 C ++ 구문 분석이 (아마도) Turing-complete 인 이유에 대한 (현재) 가장 좋아하는 데모입니다 . 왜냐하면 주어진 정수가 소수 인 경우에만 구문 상 올바른 프로그램을 보여주기 때문입니다.

따라서 C ++은 컨텍스트가없고 컨텍스트에 민감하지 않다고 주장 합니다 .

프로덕션의 양쪽에 임의의 기호 시퀀스를 허용하면 Chomsky 계층 구조 에서 Type-0 문법 ( "제한되지 않음")을 생성합니다 . 이는 문맥에 맞는 문법보다 강력합니다. 무제한 문법은 Turing-complete입니다. 상황에 맞는 (유형 -1) 문법을 사용하면 제작물의 왼쪽에 여러 컨텍스트의 심볼이 허용되지만 제작의 오른쪽에 동일한 컨텍스트가 표시되어야합니다 (따라서 "문맥에 민감한"이라는 이름). 상황에 맞는 문법은 선형 경계 튜링 기계 와 동일합니다 .

예제 프로그램에서 프라임 계산은 선형 바운드 Turing machine에 의해 수행 될 수 있으므로 Turing 동등성을 입증 할 수는 없지만 구문 분석기가 구문 분석을 수행하려면 계산을 수행해야합니다. 템플릿 인스턴스화로 표현할 수있는 계산 일 수 있었으며 C ++ 템플릿 인스턴스화가 Turing-complete라고 믿는 모든 이유가 있습니다. 예를 들어 Todd L. Veldhuizen의 2003 논문을 참조하십시오 .

그럼에도 불구하고 C ++은 컴퓨터에 의해 구문 분석 될 수 있으므로 튜링 머신에 의해 구문 분석 될 수 있습니다. 결과적으로 무제한 문법으로 인식 할 수 있습니다. 실제로 이러한 문법을 ​​작성하는 것은 실용적이지 않기 때문에 표준이 그렇게하지 않습니다. (아래 참조)

특정 표현의 "모호성"문제는 주로 붉은 청어입니다. 우선 모호성은 언어가 아닌 특정 문법의 기능입니다. 언어에 모호한 문법이없는 것으로 입증 될 수 있지만 문맥이없는 문법으로 인식 될 수 있으면 문맥이없는 것입니다. 마찬가지로 문맥이없는 문법으로는 인식 할 수 없지만 문맥에 맞는 문법으로는 인식 할 수 있으면 문맥에 민감합니다. 모호성은 관련이 없습니다.

그러나 auto b = foo<IsPrime<234799>>::typen<1>();아래 프로그램의 21 행 (예 :)과 같은 경우에는 표현이 전혀 모호하지 않습니다. 문맥에 따라 단순히 다르게 구문 분석됩니다. 문제를 가장 간단히 표현할 때 특정 식별자의 구문 범주는 선언 된 방식 (예 : 유형 및 함수)에 따라 달라집니다. 즉, 공식 언어는 두 개의 임의 길이 문자열이 동일한 프로그램이 동일합니다 (선언 및 사용). 이것은 "복사"문법으로 모델링 할 수 있는데, 이는 동일한 단어의 연속 된 두 개의 정확한 사본을 인식하는 문법입니다. 펌핑 보조로 쉽게 증명할 수 있습니다.이 언어는 상황에 맞는 것이 아닙니다. 이 언어의 상황에 맞는 문법이 가능하며이 질문에 대한 답변으로 Type-0 문법이 제공됩니다./math/163830/context-sensitive-grammar-for-the-copy-language .

C ++를 구문 분석하기 위해 상황에 맞는 (또는 제한되지 않은) 문법을 작성하려고 시도하면 우주에 낙서를 채울 수 있습니다. C ++를 파싱하기 위해 튜링 머신을 작성하는 것은 똑같이 불가능한 일입니다. C ++ 프로그램을 작성하는 것조차 어렵고 내가 아는 한 올바른 것이 입증되지 않았습니다. 이것이 표준이 완전한 공식 문법을 제공하지 않는 이유와 구문 분석 규칙 중 일부를 기술 영어로 작성하는 이유입니다.

C ++ 표준에서 공식 문법처럼 보이는 것은 C ++ 언어 구문의 완전한 공식 정의가 아닙니다. 사전 처리 후 언어의 완전한 공식적인 정의조차 아니기 때문에 공식화가 더 쉬울 수 있습니다. (그러나 언어는 아닙니다. 표준에 의해 정의 된 C ++ 언어는 전처리기를 포함하며, 전 처리기의 동작은 문법적으로 형식적으로 표현하기가 매우 어렵 기 때문에 알고리즘으로 설명됩니다. 어휘 분해가 설명 된 표준 (한 번 이상 적용해야하는 규칙 포함)

다양한 문법 (어휘 분석을위한 두 개의 겹치는 문법, 하나는 전처리 전에 발생하고 다른 하나는 필요한 경우 이후에 "구문"문법)과 함께이 중요한 참고 사항과 함께 부록 A에 수집됩니다 (강조 추가).

이 C ++ 구문 요약은 이해를 돕기위한 것입니다. 언어에 대한 정확한 진술은 아닙니다 . 특히, 여기에 설명 된 문법 은 유효한 C ++ 구문상위 집합을 허용합니다 . 표현과 선언을 구별하려면 명확성 규칙 (6.8, 7.1, 10.2)을 적용해야합니다. 또한 구문 제어가 가능하지만 의미가없는 구성을 제거하려면 액세스 제어, 모호성 및 유형 규칙을 사용해야합니다.

마지막으로 약속 된 프로그램이 있습니다. 21 행은 N in IsPrime<N>이 소수 인 경우에만 구문 상 정확합니다 . 그렇지 않으면, typen템플리트가 아닌 정수이므로 구문 적으로 유효한 표현식이 아니기 때문에 구문 상 올바르지 않은 것으로 구문 typen<1>()분석됩니다 .(typen<1)>()()

template<bool V> struct answer { answer(int) {} bool operator()(){return V;}};

template<bool no, bool yes, int f, int p> struct IsPrimeHelper
  : IsPrimeHelper<p % f == 0, f * f >= p, f + 2, p> {};
template<bool yes, int f, int p> struct IsPrimeHelper<true, yes, f, p> { using type = answer<false>; };
template<int f, int p> struct IsPrimeHelper<false, true, f, p> { using type = answer<true>; };

template<int I> using IsPrime = typename IsPrimeHelper<!(I&1), false, 3, I>::type;
template<int I>
struct X { static const int i = I; int a[i]; }; 

template<typename A> struct foo;
template<>struct foo<answer<true>>{
  template<int I> using typen = X<I>;
};
template<> struct foo<answer<false>>{
  static const int typen = 0;
};

int main() {
  auto b = foo<IsPrime<234799>>::typen<1>(); // Syntax error if not prime
  return 0;
}

[1]보다 기술적으로 표현하려면 상황에 맞는 문법의 모든 작품은 다음과 같은 형식이어야합니다.

αAβ → αγβ

여기서 A비 단자되고 α, β가능한 문법 심볼 빈 서열, 그리고 γ비어 있지 않은 시퀀스이다. 문법 기호는 터미널 또는 비 터미널 일 수 있습니다.

A → γ컨텍스트에서만 읽을 수 있습니다 [α, β]. 문맥이없는 (유형 2) 문법에서, α그리고 β비어 있어야합니다.

"모노 토닉"제한을 사용하여 문법을 제한 할 수도 있습니다. 여기서 모든 프로덕션은 다음 형식이어야합니다.

α → β여기서 |α| ≥ |β| > 0  ( |α|는 "길이"를 의미 α)

단조 문법으로 인식되는 언어 세트가 상황에 맞는 문법으로 인식되는 언어 세트와 정확히 동일하다는 것을 증명할 수 있으며, 단조 문법에 근거를 두는 것이 더 쉬운 경우가 종종 있습니다. 결과적으로 "문맥"을 의미하는 것처럼 "문맥에 민감한"을 사용하는 것이 일반적입니다.


27
따라서 상황에 따라 달라질 수있을뿐만 아니라 템플릿으로 표현할 수있는 모든 상황 (Turing-complete)에 따라 달라질 수 있습니다.
강아지

7
@mehrdad, OP는 상황에 맞는 문법이 아니라 "문맥에 맞는 언어"라고 말합니다. 모호성은 언어가 아닌 문법의 기능입니다. 언어는 실제로 상황에 따라 다르지만 특정 문법이 모호하기 때문에 아닙니다.
rici

2
내 예는 모호 하지 않습니다 . 유효한 프로그램을 명확하게 표현한 것입니다. 21 행에서 값을 변경하면 잘못 구성 될 수 있습니다. 그러나 두 경우 모두 모호합니다.
rici

5
나는 의심의 여지가있다 : 당신이 보여 주듯이, 템플릿 평가의 결과는 잘 구성된 프로그램과 잘못된 프로그램의 차이를 만들 수있다. 템플릿 평가가 완료되었습니다. 따라서 문자열이 언어 (C ++)인지 여부를 정확하게 결정하지 못하면 터링 완료가 필요합니까? 당신이 말했듯이, 상황에 맞는 언어는 "그냥" "선형 경계 오토 마톤"이며, 이는 완전하지 않은 AFAIK입니다. 또는 C ++ 표준이 템플릿 평가 심도를 포함한 몇 가지 사항에 적용하는 한계를 사용하고 있습니까?

4
@AntonGolov : 그 예제의 원래 버전은 그렇게했습니다 ( 간단한 예제를 위해 0내부 에 넣음으로써 그것을 달성 할 수 있습니다 ()). 그러나 나는이 방법이 더 흥미 롭다고 생각합니다. 문자열은 구문 상 올바른 C ++ 프로그램입니다. 두 가지가 모두 컴파일되면 차이가 "의미 적"이라는 주장에 이의를 제기하기 위해 더 열심히 노력해야 할 것입니다. 흥미롭게도, 나는 "구문법"을 정의하는 데 종종 어려움을
겪지 만, 아무도

115

첫째, 당신은 당연히 문법 그래서, C ++ 표준의 끝에 문법에는 상황에 맞는 규칙이 없다는 관측 이다 문맥 자유.

그러나이 문법은 다음과 같은 비 C ++ 프로그램을 생성하기 때문에 C ++ 언어를 정확하게 설명하지 않습니다.

int m() { m++; }

또는

typedef static int int;

"잘 구성된 C ++ 프로그램 세트"로 정의 된 C ++ 언어는 문맥에 맞지 않습니다 (선언 할 변수 만 요구한다는 것을 보여줄 수 있습니다). 이론적으로 템플릿으로 Turing-complete 프로그램을 작성하고 결과에 따라 잘못된 프로그램을 만들 수 있다고 가정하면 상황에 따라 달라지지 않습니다.

이제 (무지한) 사람들 (일반적으로 언어 이론가는 아니지만 파서 디자이너)은 일반적으로 다음과 같은 의미에서 "컨텍스트가없는"을 사용합니다.

  • 모호한
  • 들소와 파싱 할 수 없습니다
  • LL (k), LR (k), LALR (k) 또는 선택한 파서 정의 언어 클래스가 아님

표준 뒤의 문법은 이러한 범주를 만족시키지 못합니다 (즉, LL (k) ...가 아니라 모호합니다). 그래서 C ++ 문법은 "문맥이 없습니다" 그리고 어떤면에서는 작동하는 C ++ 파서를 생성하는 것이 매우 어렵다는 것이 맞습니다.

여기서 사용되는 속성은 컨텍스트가없는 언어와 약하게 연결되어 있습니다. 모호성은 컨텍스트 감도와 관련이 없으며 (실제로 컨텍스트 구분 규칙은 일반적으로 제작을 명확하게하는 데 도움이 됨) 다른 두 개는 컨텍스트의 하위 집합 일뿐입니다. 무료 언어. 컨텍스트없는 언어를 구문 분석하는 것은 선형 프로세스가 아닙니다 (결정 론적 구문을 구문 분석하는 것임).


7
ambiguity doesn't have anything to do with context-sensitivity이것은 나의 직감이기도했기 때문에 누군가 (a) 동의하고 (b) 내가 할 수없는 곳에서 설명하는 것을 보게되어 기쁘다. 나는 그것이 근거한 모든 논증을 실격 a b(c);으로 여기고, 문맥 민감도에 대한 "대부분의"주장이 모호함에 기인한다고 주장하는 원래의 질문을 부분적으로 만족 시킨다고 생각한다. 특히 문법에 대해 실제로 모호성이없는 경우 MVP.
궤도에서 가벼움 경주

6
@KonradRudolph : 표준에 따르면 "재귀 인스턴스화의 전체 깊이에 대한 제한을 지정하는 구현 정의 수량이 있습니다. 여기에는 두 개 이상의 템플릿이 포함될 수 있습니다. 인스턴스화에서 무한 재귀의 결과는 정의되지 않습니다." (14.7.1p15) 나는 재귀 깊이가 너무 큰 프로그램이 유효하지 않다는 것이 아니라 구현이 모든 유효한 c ++ 프로그램을 이해하는 데 필요한 것은 아니라는 것을 해석한다. 유효하지 않은 것으로 표시된 유일한 것은 재귀 깊이가 무한한 것입니다.
rici

3
@ KonradRudolph : 나는 그것이 "일반적인 참조"라고 논박한다. 내가 그 복잡한 기사를 읽고이 작은 사실을 알아 내기에 충분히 이해하지 못한다는 사실은 그것을 증명하기에 충분해야합니다. "컴퓨터가 일반적으로 전기를 사용합니다"또는 "비트가 참 또는 거짓 일 수 있습니다"와 같은 말은 아닙니다.
궤도에서 가벼움 경주

3
이 사실이 실제로 널리 알려져 있다면, 그것이 제공되어야하는지의 여부에 관해 긴 논쟁 거리보다 주장에 대한 참조를 찾는 것이 훨씬 쉽다고 생각합니다. 건설적인 것은 말할 것도 없습니다.
Samuel Edwin Ward

5
내가 말할 수있는 한, @Konrad는 "컨텍스트 인식은 Turing complete와 동일합니다."라고 말했을 때 착각했습니다. (적어도 "Turing complete"에서 "재귀 적으로 열거 가능"을 나타내는 경우)이 오류를 인식 할 수 없었습니다. 여기에 관련된 적절한 포함 포함 관계에 대한 참조가 있습니다. en.wikipedia.org/wiki/Chomsky_hierarchy
pnkfelix

61

예. 다음 표현식은 유형 확인 컨텍스트 에 따라 다른 순서로 조작 됩니다 .

편집 : 실제 작업 순서가 다를 경우, 꾸미기 전에 AST를 구문 분석하는 "일반"컴파일러를 사용하기가 매우 어렵습니다 (유형 정보 전파). 언급 된 상황에 민감한 다른 것들은 이것에 비해 "쉬운"것입니다 (템플릿 평가가 전혀 쉬운 것은 아닙니다).

#if FIRST_MEANING
   template<bool B>
   class foo
   { };
#else
   static const int foo = 0;
   static const int bar = 15;
#endif

뒤에 :

static int foobar( foo < 2 ? 1 < 1 : 0 > & bar );

어떤 유형 정의가 범위 내에 있는지를 기억하여 C와 같은 문제를 해결할 수없는 이유는 무엇입니까?
Blaisorblade

1
@Blaisorblade : 컴파일러를 "깨끗하게"만드는 방법 중 하나는 입력에서 구문 분석 트리를 만든 다음 형식 분석을 수행하는 단계와 같이 작업을 체인의 독립적 인 단계로 분리하는 것입니다. C ++은 1)이 단계들을 하나 또는 2 개로 병합합니다. 2) 가능한 모든 해석에 따라 문서를 구문 분석하고 형식 해석 단계에서 정확한 해석으로 범위를 좁 힙니다.
Sam Harwell

@ 280Z28 : 동의하지만 C의 경우도 마찬가지입니다. 이 질문에 대한 좋은 대답은 C ++가 C보다 나쁜 이유를 보여 주어야한다고 생각합니다. 여기에 연결된 박사 학위 논문은 다음과 같이합니다 : stackoverflow.com/a/243447/53974
Blaisorblade

26

질문에 대답하려면 두 가지 다른 질문을 구별해야합니다.

  1. 거의 모든 프로그래밍 언어의 구문은 컨텍스트가 없습니다. 일반적으로 확장 된 Backus-Naur 양식 또는 컨텍스트가없는 문법으로 제공됩니다.

  2. 그러나 프로그램이 프로그래밍 언어로 정의 된 컨텍스트없는 문법을 준수하더라도 반드시 유효한 프로그램 은 아닙니다 . 유효한 프로그램이 되려면 프로그램이 만족해야하는 많은 문맥이없는 poperty가 있습니다. 예를 들어, 가장 간단한 속성은 변수의 범위입니다.

결론적으로 C ++에 컨텍스트가 없는지 여부는 묻는 질문에 따라 다릅니다.


5
프로그래밍 언어에 대한 CFG를 얻기 위해 "단순한 구문"수준을 예상보다 낮게 배치해야한다는 점이 흥미 롭습니다. 예를 들어 C를 사용하십시오. 당신은 C에서 간단한 변수 선언에 대한 문법 규칙이 될 것이라고 생각 VARDECL : TYPENAME IDENTIFIER하지만, 당신은 할 수없는 당신이 CF 수준에서 다른 식별자의 유형 이름을 구별 할 수 없기 때문에, 그 있습니다. 또 다른 예 : CF 레벨에서 a*b변수 선언 ( b포인터 유형 a) 또는 곱셈 으로 구문 분석 할 것인지 결정할 수 없습니다 .
LaC

2
@LaC : 예, 이것을 지적 해 주셔서 감사합니다! 그건 그렇고, 나는 단순한 구문에 대해 더 일반적으로 사용되는 기술 용어가 있다고 확신 합니다 . 누구든지 올바른 용어입니까?
Dan

4
@ Dan : 당신이 말하는 것은 문맥이없는 문법으로 주어진 언어의 근사치입니다. 물론 이러한 근사값은 정의상 coontext-free입니다. 이것은 프로그래밍 언어를 논의 할 때 종종 "구문"이 사용되는 의미입니다.
reinierpost

13

Bjarne Stroustrup 의 C ++의 디자인 및 진화를 살펴볼 수 있습니다 . 여기에서는 yacc (또는 유사한)를 사용하여 초기 버전의 C ++을 구문 분석하고 재귀 적 하강을 대신 사용하려는 그의 문제에 대해 설명합니다.


와우 고마워. 정말 할 의미합니다 있을까 생각 어떤 인공 언어를 구문 분석 할 CFG보다 더 강력한 것을 사용에 대한합니다.
Dervin Thunk

C ++의 이유를 이해하기위한 훌륭한 책. C ++의 작동 방식을 이해하려면 Lippman의 C ++ 객체 모델 내부를 권장합니다. 둘 다 약간 날짜가 있지만 여전히 잘 읽습니다.
매트 가격

"Meta-S"는 Quinn Tyler Jackson의 상황에 맞는 구문 분석 엔진입니다. 나는 그것을 사용하지 않았지만 인상적인 이야기를 들려줍니다. comp.compilers에서 그의 의견을 확인하고 rnaparse.com/MetaS%20defined.htm
Ira Baxter를 방문하십시오

@IraBaxter : 귀하의 x-ref는 오늘날 MIA이며 소프트웨어에 대한 견고한 참조는 찾기 어려운 것 같습니다 (Google 검색은 'site : rnaparse.com meta-s'또는 'quinn jackson meta- s '; 비트와 조각이 있지만 meta-s.com 은 정보가없는 웹 사이트로 연결됩니다).
Jonathan Leffler

@Jonathan : 잠시 동안 불만을 발견했습니다. 왜 링크가 나쁜지 모르겠다, 나는 그것을 쓸 때 그것이 좋았다고 생각했다. Quinn은 comp.compiler에서 꽤 활발했습니다. Google은 결함 이있는 것 같습니다. groups.google.com/group/comp.compilers/browse_thread/thread/… IIRC, 그는 MetaS에 대한 권리를 하와이의 일부 복장에 재판매하기 위해 서명했습니다. 이 기술이 얼마나 기묘한지를 감안할 때 IMHO는 사형 영장에 서명하고 있습니다. 매우 영리한 계획처럼 들렸습니다.
Ira Baxter

12

예 C ++은 상황에 민감하고 상황에 매우 민감합니다. 컨텍스트 프리 파서를 사용하여 파일을 간단히 구문 분석하여 구문 트리를 빌드 할 수없는 경우가 있습니다. 경우에 따라 이전 지식의 기호를 결정해야합니다 (예 : 구문 분석 중에 심볼 테이블 작성).

첫 번째 예 :

A*B;

이것이 곱셈 표현입니까?

또는

이것은 B변수 의 선언이 유형의 포인터 A입니까?

A가 변수이면 표현식이고 A가 유형이면 포인터 선언입니다.

두 번째 예 :

A B(bar);

함수 프로토 타입이 타입의 인수를 취 bar합니까?

또는

이것은 B유형의 변수 를 선언 하고 초기화 자로 상수를 사용하여 AA의 생성자를 호출 bar합니까?

bar기호 테이블의 변수인지 또는 유형 인지 다시 알아야 합니다.

세 번째 예 :

class Foo
{
public:
    void fn(){x*y;}
    int x, y;
};

x와 y의 선언이 함수 정의 뒤에 오기 때문에 구문 분석하는 동안 기호 테이블을 작성하는 것이 도움이되지 않는 경우입니다. 따라서 클래스 정의를 먼저 스캔하고 두 번째 단계에서 메소드 정의를 살펴보고 x * y가 포인터 선언이 아닌 표현식이라는 것을 말해야합니다.


1
A B();함수 정의에서도 함수 선언입니다. 가장
까다로운

""FALSE 파일을 구문 분석하여 구문 트리를 작성할 수 없습니다. 내 대답을 참조하십시오.
Ira Baxter

10

C ++은 GLR 파서로 구문 분석됩니다. 즉, 소스 코드를 구문 분석하는 동안 구문 분석기에 모호성 발생할 있지만 나중에 사용할 문법 규칙을 계속 결정해야합니다 .

또한 봐

C ++을 LR (1) 파서로 파싱 할 수없는 이유는 무엇입니까?


문맥이없는 문법 프로그래밍 언어 구문의 모든 규칙을 설명 할 수는 없습니다 . 예를 들어, 속성 문법은 표현식 유형의 유효성을 검사하는 데 사용됩니다.

int x;
x = 9 + 1.0;

당신은 할 수없는 문맥 자유 문법 다음과 같은 규칙을 설명 : 과제의 오른쪽은 왼쪽의 동일한 유형이어야합니다.


4
대부분의 C ++ 파서는 GLR 파싱 기술을 사용하지 않습니다. GCC는 그렇지 않습니다. 일부는 그렇습니다. semanticdesigns.com/Products/FrontEnds/CppFrontEnd.html 을 참조하십시오 .
Ira Baxter

10

나는 "문맥에 민감한"의 공식적인 정의와 "문맥에 민감한"의 비공식적 인 사용 사이에 약간의 혼동이 있다고 생각한다. 전자는 잘 정의 된 의미를 가지고 있습니다. 후자는 "입력을 구문 분석하기 위해 컨텍스트가 필요합니다"라고 말하는 데 사용됩니다.

이것은 또한 여기에 묻습니다 : 문맥 민감성 대 모호성 .

상황에 맞는 문법은 다음과 같습니다.

<a> ::= <b> | <c>
<b> ::= "x"
<c> ::= "x"

입력 "x"를 구문 분석하려면 일부 컨텍스트가 필요하거나 모호함을 느끼거나 "경고 : E8271-입력이 모호합니다. 115 행"을 출력해야합니다. 그러나 그것은 상황에 맞는 문법이 아닙니다.


프로덕션의 왼쪽에 여러 개의 심볼이 있으면이 문제가 어떻게 해결됩니까? 이 답변이 질문에 대한 답변이라고 생각하지 않습니다.
user541686

1
내 대답은 첫 번째 문장에 대한 답변입니다. "C ++이 상황에 맞는 언어라는 주장을 자주 듣습니다." 이러한 주장이 비공식적으로 "문맥에 민감한"이라는 표현을 사용한다면 아무런 문제가 없습니다. C ++이 공식적으로 상황에 맞는 것이라고 생각하지 않습니다.
Omri Barel

C ++ 공식적으로 상황에 맞는 것으로 생각 하지만, 내가 겪고있는 문제는 상황에 맞는 문법이 CFG보다 C ++을 구문 분석하는 데 더 많은 성공을 거두는 방법을 이해하지 못한다는 것입니다.
user541686

6

알골과 유사한 언어는 문맥에 영향을받지 않습니다. 문맥에 따라 식별자가 유형에 따라 표시 될 수있는 표현식과 명령문을 제한하는 규칙이 있으며 선언과 사용 사이에 발생할 수있는 명령문의 수에는 제한이 없기 때문입니다.

일반적인 해결책은 실제로 유효한 프로그램의 상위 세트를 허용하고 컨텍스트에 민감한 부분 을 규칙에 첨부 된 임시 "시맨틱"코드에 넣는 컨텍스트없는 구문 분석기를 작성하는 것 입니다.

C ++은 Turing-complete 템플릿 시스템 덕분에이를 뛰어 넘습니다. 스택 오버플로 질문 794015를 참조하십시오 .




5

a b(c);두 개의 유효한 구문 분석 선언과 변수 가 있으므로 상황에 따라 다릅니다. "If cis a type" 이라고 말하면 바로 문맥입니다. C ++이 그 유형에 어떻게 민감한 지 정확하게 설명했습니다. "무엇입니까 c?" 라는 문맥이 없다면 이것을 명확하게 파싱 할 수 없었습니다.

여기서 컨텍스트는 토큰 선택으로 표현됩니다. 구문 분석기는 유형의 이름을 지정하면 식별자를 유형 이름 토큰으로 읽습니다. 이것은 가장 간단한 해결 방법이며 상황에 따라 달라지는 복잡한 작업을 피합니다 (이 경우).

편집 : 물론 상황 민감도에 대한 더 많은 문제가 있으며, 나는 당신이 보여준 것에 중점을 두었습니다. 템플릿은 특히 불쾌합니다.


1
또한 a<b<c>>d? (귀하의 예를 실제로에서 고전 C 는 것입니다, 단지 문맥 자유가되기 위해서는 장애물.)
Kerrek SB

그것은 렉싱 문제에 더 가깝습니다. 그러나 확실히 같은 범주에 있습니다.
강아지

2
질문자는 C 보다 컨텍스트에 민감한 지 묻지 않고 컨텍스트에 민감하다는 것을 보여줍니다.
강아지

그래서 ...을 하다 C ++ 더 문맥에 맞는 C보다 더?
Kerrek SB

2
@DeadMG 나는 당신이 질문에 대답하고 있다고 생각하지 않습니다 (나도 둘 중 하나라고 생각하지 않습니다). 생산의 왼쪽에 터미널이이 문제를 어떻게 해결합니까?
user541686

5

C ++ 표준의 제작물은 상황에 맞게 작성되지만, 우리 모두가 알고 있듯이 실제로 언어를 정확하게 정의하지는 않습니다. 대부분의 사람들이 현재의 언어로 애매 모호하다고 생각하는 것 중 일부는 상황에 맞는 문법으로 명확하게 해결할 수 있습니다.

가장 확실한 예를 들어, 가장 Vexing 구문 분석을 고려하십시오 int f(X);. 경우 X의 값,이 정의이다 f으로 초기화 될 변수로 X. X유형 인 경우 유형 f의 단일 매개 변수를 사용하는 함수로 정의 합니다.X .

문법적인 관점에서 보면 다음과 같이 볼 수 있습니다.

A variable_decl ::= <type> <identifier> '(' initializer ')' ';'

B function_decl ::= <type> <identifier> '(' param_decl ')' ';'

A ::= [declaration of X as value]
B ::= [declaration of X as type]

물론, 완전히 정확하려면 다른 유형의 선언을 중재 할 가능성을 설명하기 위해 추가 "물건"을 추가해야합니다 (즉, A와 B는 둘 다 "X의 선언을 포함하여 선언 ..."이어야 함) 또는 그 순서에 맞는 것).

이것은 여전히 ​​전형적인 CSG와는 다릅니다 (또는 적어도 그것들을 기억하는 것). 이는 구성되고있는 기호 테이블에 따라 달라집니다.이 부분은 X앞의 문장 유형뿐만 아니라 올바른 기호 / 식별자에 대한 올바른 문장 유형입니다.

따라서, 나는 확실하게 찾고자 노력해야하지만, 즉각적인 추측은 적어도 이것이 일반적으로 사용되는 것처럼 이것이 실제로 CSG로서 자격이 없다는 것입니다.


(컨텍스트가없는) 프로덕션은 가장 자유로운 구문 분석을 충분히 정의하므로 컨텍스트가없는 구문 분석 엔진으로 구문 분석 할 수 있습니다. 이는 구문 분석이 완료 될 때까지 여러 해석 중 어떤 해석이 유효한지 결정하는 문제를 지연 시키지만, 파서와 이름 해석기의 엔지니어링은 기존 C ++ 파서 에서처럼 엉키지 않고 모듈화되기 때문에 더 쉽게 만들 수 있습니다. 대부분의 애 태우게하는 구문 분석에 대한 AST 참조 stackoverflow.com/questions/17388771/...
아이라 박스터

5

문맥이없는 문법의 가장 간단한 경우는 템플릿과 관련된 표현식을 구문 분석하는 것입니다.

a<b<c>()

이것은 다음 중 하나로 구문 분석 할 수 있습니다

template
   |
   a < expr > ()
        |
        <
      /   \
     b     c

또는

 expr
   |
   <
 /   \
a   template
     |
     b < expr > ()
          |
          c

두 개의 AST는 'a'선언을 검사하여 명확하게 설명 할 수 있습니다. 'a'가 템플릿 인 경우 이전 AST, 그렇지 않은 경우에는 AST입니다.


나는 C ++ 11이 후자의 해석을 지시한다고 생각하며, 전자에 옵트 인하 기 위해 parens를 추가해야합니다.
Joseph Garvin

1
@JosephGarvin, 아니오. C ++에서는 <가능하면 대괄호 여야합니다 (예 : 템플릿 이름을 지정하는 식별자를 따릅니다). C ++ 11 은 그 사용이 그럴듯한 경우 >첫 번째 문자를 >>대괄호로 해석 해야한다는 요구 사항을 추가했습니다 . 이것은 템플릿이있는 a<b>c>곳 의 구문 분석에 영향을 a주지만에 영향을 미치지 않습니다 a<b<c>.
rici

@ aaron : 어떻게 a();( expr.call또는 어느 것보다) 간단 expr.type.conv합니까?
rici

@rici : 죄송합니다. 비대칭인지 몰랐습니다.
Joseph Garvin

5
모호성 또는 상황 민감도 를 설명하고 있습니까?
corazza

4

C ++ 템플릿은 Turing Powerful 인 것으로 나타났습니다. 공식적인 참고 자료는 아니지만 다음과 같은 점을 고려해야합니다.

http://cpptruths.blogspot.com/2005/11/c-templates-are-turing-complete.html

나는 추측을 할 것이다. (60 년대의 ALGOL이 CFG에 의해 다시 표현 될 수 없다는 것을 보여주는 민속적이고 간결한 CACM 증거만큼 오래되었다) C ++은 CFG에 의해서만 정확하게 구문 분석 될 수 없다고 말한다. CFG는 트리 패스 또는 축소 이벤트 중 다양한 TP 메커니즘과 함께 사용되며 이는 또 다른 이야기입니다. 일반적으로 Halting Problem로 인해 정확 / 잘못된 것으로 표시 될 수 없지만 그럼에도 불구하고 정확하지 않은 C ++ 프로그램이 있습니다.

{PS- Meta-S의 저자로서 (위의 여러 사람들에 의해 언급 된)-가장 확실하게 Thothic은 기능이 없으며 소프트웨어를 무료로 사용할 수 없다고 말할 수 있습니다. 아마도이 버전의 응답을 삭제하거나 -3으로 투표하지 않도록이 버전의 응답을 사용했습니다.}


3

C ++에는 컨텍스트가 없습니다. 얼마 전에 컴파일러 강의에서 배웠습니다. "검색어 또는 의미론"섹션에서 C 및 C ++에 컨텍스트가없는 이유를 설명하는 빠른 검색에서이 링크를 제공했습니다.

Wikipedia Talk : 문맥없는 문법

감사합니다, 오
바네스


2

분명히, 질문을 그대로 사용하면 식별자가있는 거의 모든 언어가 상황에 따라 다릅니다.

식별자가 형식 이름 (클래스 이름, typedef에 의해 도입 된 이름, typename 템플릿 매개 변수)인지, 템플릿 이름 또는 식별자의 일부를 올바르게 사용할 수있는 다른 이름인지 알아야합니다. 예를 들어 :

x = (name)(expression);

name유형 이름 인 경우 캐스트 이고name 함수 이름 인 입니다. 또 다른 경우는 변수 정의와 함수 선언을 구별 할 수없는 소위 "가장 vexing 구문 분석"입니다 (함수 선언이라고하는 규칙이 있습니다).

그 어려움의 필요성 도입 typenametemplate의존 이름을. 나머지 C ++은 내가 아는 한 문맥에 민감하지 않습니다 (즉, 문맥에 맞는 문법을 작성할 수 있습니다).


2

Meta-S "는 Quinn Tyler Jackson의 상황에 맞는 구문 분석 엔진입니다. 사용하지는 않았지만 인상적인 이야기를 들려줍니다. comp.compilers에서 자신의 의견을 확인하고 rnaparse.com/MetaS%20defined.htm을 참조하십시오. – Ira Baxter 7 월 25 일 10:42

올바른 링크는 수수께끼를 파싱합니다

Meta-S는 Thothic이라는 기능이없는 회사의 자산이었습니다. Meta-S의 무료 사본을 관심있는 사람에게 보낼 수 있으며 rna 파싱 연구에 사용했습니다. 예제 폴더에 포함 된 "pseudoknot grammar"는 비 생물 정보학, 성숙 프로그래머가 작성했으며 기본적으로 작동하지 않습니다. 저의 문법은 다른 접근법을 취하고 잘 작동합니다.


이것은 실제로 흥미로운 발견입니다.
Dervin Thunk

0

여기서 중요한 문제는 "문맥이없는"과 "문맥에 민감한"이라는 용어가 컴퓨터 과학에서 조금 직관적이지 않다는 것입니다. C ++의 경우 컨텍스트 감도는 모호성과 비슷하지만 일반적인 경우에는 반드시 그런 것은 아닙니다.

C / ++에서 if 문은 함수 본문 내에서만 허용됩니다. 상황에 맞는 것 같아요? 음 ... 아니. 문맥이없는 문법은 실제로 코드 줄을 뽑아서 유효한지 결정할 수있는 속성이 필요하지 않습니다. 실제로 컨텍스트가없는 것은 아닙니다. 그것은 실제로 그 소리와 관련이있는 것을 막연하게 암시하는 레이블 일뿐입니다.

이제 함수 본문 내의 명령문이 경우와 같이 직접적인 문법 조상 외부에 정의 된 내용 (예 : 식별자가 유형 또는 변수를 설명하는지 여부)에 따라 다르게 구문 분석되는 a * b;경우 실제로 상황에 따라 다릅니다 . 여기에는 실제 모호성이 없습니다. a유형이 포인터이면 포인터 선언으로 해석되고 그렇지 않으면 곱셈입니다.

상황에 맞는 것이 반드시 "파싱하기 어렵다"는 것은 아닙니다. 악명 높은 a * b;"모호성"은 typedef이전에 발생한 기호 테이블을 사용하여 해결할 수 있기 때문에 C는 실제로 그렇게 어렵지 않습니다 . C ++과 같은 경우를 해결하기 위해 튜링 완료로 입증 된 임의의 템플릿 인스턴스화가 필요하지 않습니다. C ++과 동일한 컨텍스트 감도를 가지고 있지만 유한 한 시간 내에 컴파일되지 않는 C 프로그램을 작성할 수는 없습니다.

파이썬 (및 기타 공백에 민감한 언어들)은 또한 상황에 따라 다릅니다. 렉서에서 상태가 들여 쓰기 및 들여 쓰기 토큰을 생성해야하기 때문에 일반적인 LL-1 문법보다 구문 분석하기가 더 어렵지는 않습니다. 실제로 파서 생성기를 사용하는데, 이는 파이썬이 정보가없는 구문 오류 메시지를 갖는 이유의 일부입니다. 여기서는 a * b;파이썬 에서 문제 와 같은 "모호성"이 없다는 점에 주목하는 것이 중요합니다 (첫 번째 단락에서 언급 한대로) "모호한"문법이없는 상황에 맞는 언어의 구체적인 예를 제공합니다.


-4

이 답변은 C ++에 컨텍스트가 없음을 말합니다 ... 응답자가 아닌 구문 분석 할 수 없다는 의미가 있으며 특정 상수가 아닌 경우 잘못된 C ++ 프로그램을 생성하는 어려운 코드 예제를 제공합니다. 소수.

다른 사람들이 관찰 한 것처럼, 언어 가 상황 에 맞는지 / 없는지에 대한 질문은 특정 문법에 대한 동일한 질문과 다릅니다.

구문 분석 가능성에 대한 질문을 설정하기 위해 C ++에 컨텍스트가없는 문법이 있다는 사실을 실증적 증거로 제시합니다. 실제로는 기존 GLR로 구문 분석하여 소스 텍스트의 컨텍스트가없는 구문 분석을위한 AST를 생성하는 데 사용할 수 있습니다. 문법에 의해 구동되는 파서 기반 도구입니다.

그렇습니다. "너무 많은 것을 받아들이면"성공합니다. 허용되는 모든 것이 유효한 C ++ 프로그램이 아니기 때문에 추가 검사 (유형 검사)가 뒤 따릅니다. 그리고 예, 타입 체커는 계산 문제에 부딪 칠 수 있습니다. 실제로 도구에는이 문제가 없습니다. 사람들이 그런 프로그램을 작성했다면 아무도 컴파일하지 않을 것입니다. (표준은 실제로 템플릿을 펼칠 수있는 계산량을 제한한다고 생각합니다. 실제로 계산은 실제로 유한하지만 아마도 상당히 큽니다).

의미 하는 바, 소스 프로그램이 유효한 C ++ 소스 프로그램 세트의 멤버인지 판별하면 문제가 훨씬 더 어렵다는 데 동의합니다. 하지만 파싱 하지 않습니다 문제가되는 .

이 도구는 구문 분석 된 프로그램의 유형 검사에서 구문 분석을 분리하여이 문제를 해결합니다. (문맥이없는 상황에서 여러 가지 해석이있는 경우 모호성을 기록합니다. 몇 가지 가능한 구문 분석을 사용하여 구문 분석 트리에 노드를 . 유형 검사는 어느 것이 올바른지를 결정하고 유효하지 않은 하위 트리를 제거합니다. 아래 예제에서 (부분) 구문 분석 트리를 볼 수 있습니다. 전체 트리가 너무 커서 SO 답변에 맞지 않습니다. 값 234797 또는 234799가 사용되는지 여부에 상관없이 구문 분석 트리가 나타납니다.

원래 값 234799로 AST에서 도구 이름 / 유형 분석기를 실행하면 성공합니다. 값이 234797 인 경우 이름 분석기는 "typen is a type."이라는 오류 메시지와 함께 실패합니다 (예상대로). 따라서 해당 버전은 유효한 C ++ 프로그램이 아닙니다.

967 tree nodes in tree.
15 ambiguity nodes in tree.
(translation_unit@Cpp~GCC5=2#6b11a20^0 Line 1 Column 1 File C:/temp/prime_with_templates.cpp
 (declaration_seq@Cpp~GCC5=1021#6b06640^1#6b11a20:1 {10} Line 1 Column 1 File C:/temp/prime_with_templates.cpp
  (pp_declaration_seq@Cpp~GCC5=1022#6b049a0^1#6b06640:1 Line 1 Column 1 File C:/temp/prime_with_templates.cpp
   (declaration@Cpp~GCC5=1036#6b04980^1#6b049a0:1 Line 1 Column 1 File C:/temp/prime_with_templates.cpp
   |(template_declaration@Cpp~GCC5=2079#6b04960^1#6b04980:1 Line 1 Column 1 File C:/temp/prime_with_templates.cpp
   | (template_parameter_list@Cpp~GCC5=2082#6afbde0^1#6b04960:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |  (template_parameter@Cpp~GCC5=2085#6afbd80^1#6afbde0:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   (parameter_declaration@Cpp~GCC5=1611#6afbd40^1#6afbd80:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   |(basic_decl_specifier_seq@Cpp~GCC5=1070#6afb880^1#6afbd40:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   | (decl_specifier@Cpp~GCC5=1073#6afb840^1#6afb880:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   |  (trailing_type_specifier@Cpp~GCC5=1118#6afb7e0^1#6afb840:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   (simple_type_specifier@Cpp~GCC5=1138#6afb7a0^1#6afb7e0:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |  )trailing_type_specifier#6afb7e0
   |   | )decl_specifier#6afb840
   |   |)basic_decl_specifier_seq#6afb880
   |   |(ptr_declarator@Cpp~GCC5=1417#6afbc40^1#6afbd40:2 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   | (noptr_declarator@Cpp~GCC5=1421#6afbba0^1#6afbc40:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   |  (declarator_id@Cpp~GCC5=1487#6afbb80^1#6afbba0:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   (id_expression@Cpp~GCC5=317#6afbaa0^1#6afbb80:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |(unqualified_id@Cpp~GCC5=319#6afb9c0^1#6afbaa0:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   | (IDENTIFIER@Cpp~GCC5=3368#6afb780^1#6afb9c0:1[`V'] Line 1 Column 15 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   |)unqualified_id#6afb9c0
   |   |   )id_expression#6afbaa0
   |   |  )declarator_id#6afbb80
   |   | )noptr_declarator#6afbba0
   |   |)ptr_declarator#6afbc40
   |   )parameter_declaration#6afbd40
   |  )template_parameter#6afbd80
   | )template_parameter_list#6afbde0
   | (declaration@Cpp~GCC5=1033#6b04940^1#6b04960:2 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |  (block_declaration@Cpp~GCC5=1050#6b04920^1#6b04940:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   (simple_declaration@Cpp~GCC5=1060#6b04900^1#6b04920:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |(basic_decl_specifier_seq@Cpp~GCC5=1070#6b048e0^1#6b04900:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   | (decl_specifier@Cpp~GCC5=1073#6b048c0^1#6b048e0:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |  (type_specifier@Cpp~GCC5=1110#6b048a0^1#6b048c0:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |   (class_specifier@Cpp~GCC5=1761#6b04880^1#6b048a0:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |   |(class_head@Cpp~GCC5=1763#6afb980^1#6b04880:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |   | (class_key@Cpp~GCC5=1791#6afbca0^1#6afb980:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp)class_key
   |   |   | (IDENTIFIER@Cpp~GCC5=3368#6afbcc0^1#6afb980:2[`answer'] Line 1 Column 25 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   | (optional_base_clause@Cpp~GCC5=1872#6afba60^1#6afb980:3 Line 1 Column 32 File C:/temp/prime_with_templates.cpp)optional_base_clause
   |   |   |)class_head#6afb980
   |   |   |(member_specification@Cpp~GCC5=1794#6b042e0^1#6b04880:2 {2} Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   | (member_declaration_or_access_specifier@Cpp~GCC5=1806#6b04060^1#6b042e0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |  (member_declaration@Cpp~GCC5=1822#6b04040^1#6b04060:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   (function_definition@Cpp~GCC5=1632#6b04020^1#6b04040:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |(function_head@Cpp~GCC5=1673#6afbec0^1#6b04020:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   | (ptr_declarator@Cpp~GCC5=1417#6afbfe0^1#6afbec0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |  (noptr_declarator@Cpp~GCC5=1422#6afbf80^1#6afbfe0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   (noptr_declarator@Cpp~GCC5=1421#6afbf60^1#6afbf80:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |(declarator_id@Cpp~GCC5=1487#6afbea0^1#6afbf60:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   | (id_expression@Cpp~GCC5=317#6afbb40^1#6afbea0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |  (unqualified_id@Cpp~GCC5=319#6afbc80^1#6afbb40:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   (IDENTIFIER@Cpp~GCC5=3368#6afbc20^1#6afbc80:1[`answer'] Line 1 Column 34 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   |   |   |  )unqualified_id#6afbc80
   |   |   |   |   | )id_expression#6afbb40
   |   |   |   |   |)declarator_id#6afbea0
   |   |   |   |   )noptr_declarator#6afbf60
   |   |   |   |   (parameter_declaration_clause@Cpp~GCC5=1559#6afbd00^1#6afbf80:2 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |(pp_parameter_declaration_list@Cpp~GCC5=1570#6afb940^1#6afbd00:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   | (pp_parameter_declaration_seq@Cpp~GCC5=1574#6afb800^1#6afb940:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |  (parameter_declaration@Cpp~GCC5=1610#6afb9a0^1#6afb800:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   (basic_decl_specifier_seq@Cpp~GCC5=1070#6afbf40^1#6afb9a0:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |(decl_specifier@Cpp~GCC5=1073#6afbfa0^1#6afbf40:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   | (trailing_type_specifier@Cpp~GCC5=1118#6afbfc0^1#6afbfa0:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |  (simple_type_specifier@Cpp~GCC5=1140#6afb860^1#6afbfc0:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |   |   |   |   | )trailing_type_specifier#6afbfc0
   |   |   |   |   |   |)decl_specifier#6afbfa0
   |   |   |   |   |   )basic_decl_specifier_seq#6afbf40
   |   |   |   |   |  )parameter_declaration#6afb9a0
   |   |   |   |   | )pp_parameter_declaration_seq#6afb800
   |   |   |   |   |)pp_parameter_declaration_list#6afb940
   |   |   |   |   )parameter_declaration_clause#6afbd00
   |   |   |   |   (function_qualifiers@Cpp~GCC5=1438#6afbce0^1#6afbf80:3 Line 1 Column 46 File C:/temp/prime_with_templates.cpp)function_qualifiers
   |   |   |   |  )noptr_declarator#6afbf80
   |   |   |   | )ptr_declarator#6afbfe0
   |   |   |   |)function_head#6afbec0
   |   |   |   |(function_body@Cpp~GCC5=1680#6b04000^1#6b04020:2 Line 1 Column 46 File C:/temp/prime_with_templates.cpp
   |   |   |   | (compound_statement@Cpp~GCC5=888#6afbee0^1#6b04000:1 Line 1 Column 46 File C:/temp/prime_with_templates.cpp)compound_statement
   |   |   |   |)function_body#6b04000
   |   |   |   )function_definition#6b04020
   |   |   |  )member_declaration#6b04040
   |   |   | )member_declaration_or_access_specifier#6b04060
   |   |   | (member_declaration_or_access_specifier@Cpp~GCC5=1806#6b042c0^1#6b042e0:2 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |  (member_declaration@Cpp~GCC5=1822#6b04820^1#6b042c0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   (function_definition@Cpp~GCC5=1632#6b04280^1#6b04820:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   |(function_head@Cpp~GCC5=1674#6b04220^1#6b04280:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   | (basic_decl_specifier_seq@Cpp~GCC5=1070#6b040e0^1#6b04220:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   |  (decl_specifier@Cpp~GCC5=1073#6b040c0^1#6b040e0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   |   (trailing_type_specifier@Cpp~GCC5=1118#6b040a0^1#6b040c0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |(simple_type_specifier@Cpp~GCC5=1138#6b04080^1#6b040a0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |   |   |   )trailing_type_specifier#6b040a0
   |   |   |   |  )decl_specifier#6b040c0
   |   |   |   | )basic_decl_specifier_seq#6b040e0
   |   |   |   | (ptr_declarator@Cpp~GCC5=1417#6b04200^1#6b04220:2 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |  (noptr_declarator@Cpp~GCC5=1422#6b041e0^1#6b04200:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   (noptr_declarator@Cpp~GCC5=1421#6b041a0^1#6b041e0:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |(declarator_id@Cpp~GCC5=1487#6b04180^1#6b041a0:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   | (id_expression@Cpp~GCC5=317#6b04160^1#6b04180:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |  (unqualified_id@Cpp~GCC5=320#6b04140^1#6b04160:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   (operator_function_id@Cpp~GCC5=2027#6b04120^1#6b04140:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |(operator@Cpp~GCC5=2070#6b04100^1#6b04120:1 Line 1 Column 62 File C:/temp/prime_with_templates.cpp)operator
   |   |   |   |   |   )operator_function_id#6b04120
   |   |   |   |   |  )unqualified_id#6b04140
   |   |   |   |   | )id_expression#6b04160
   |   |   |   |   |)declarator_id#6b04180
   |   |   |   |   )noptr_declarator#6b041a0
   |   |   |   |   (parameter_declaration_clause@Cpp~GCC5=1558#6afba40^1#6b041e0:2 Line 1 Column 65 File C:/temp/prime_with_templates.cpp)parameter_declaration_clause
   |   |   |   |   (function_qualifiers@Cpp~GCC5=1438#6b041c0^1#6b041e0:3 Line 1 Column 66 File C:/temp/prime_with_templates.cpp)function_qualifiers
   |   |   |   |  )noptr_declarator#6b041e0
   |   |   |   | )ptr_declarator#6b04200
   |   |   |   |)function_head#6b04220
   |   |   |   |(function_body@Cpp~GCC5=1680#6b04300^1#6b04280:2 Line 1 Column 66 File C:/temp/prime_with_templates.cpp
   |   |   |   | (compound_statement@Cpp~GCC5=889#6b04760^1#6b04300:1 Line 1 Column 66 File C:/temp/prime_with_templates.cpp
   |   |   |   |  (pp_statement_seq@Cpp~GCC5=894#6b04780^1#6b04760:1 Line 1 Column 67 File C:/temp/prime_with_templates.cpp
   |   |   |   |   (statement@Cpp~GCC5=857#6b04440^1#6b04780:1 Line 1 Column 67 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |(jump_statement@Cpp~GCC5=1011#6afba80^1#6b04440:1 Line 1 Column 67 File C:/temp/prime_with_templates.cpp
   |   |   |   |   | (pm_expression@Cpp~GCC5=551#6b04380^1#6afba80:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |  (cast_expression@Cpp~GCC5=543#6b04360^1#6b04380:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   (unary_expression@Cpp~GCC5=465#6b04340^1#6b04360:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |(primary_expression@Cpp~GCC5=307#6b04320^1#6b04340:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   | (id_expression@Cpp~GCC5=317#6b042a0^1#6b04320:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |  (unqualified_id@Cpp~GCC5=319#6b04260^1#6b042a0:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |   (IDENTIFIER@Cpp~GCC5=3368#6b04240^1#6b04260:1[`V'] Line 1 Column 74 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   |   |   |   |  )unqualified_id#6b04260
   |   |   |   |   |   | )id_expression#6b042a0
   |   |   |   |   |   |)primary_expression#6b04320
   |   |   |   |   |   )unary_expression#6b04340
   |   |   |   |   |  )cast_expression#6b04360
   |   |   |   |   | )pm_expression#6b04380
   |   |   |   |   |)jump_statement#6afba80
   |   |   |   |   )statement#6b04440
   |   |   |   |  )pp_statement_seq#6b04780
   |   |   |   | )compound_statement#6b04760
   |   |   |   |)function_body#6b04300
   |   |   |   )function_definition#6b04280
   |   |   |  )member_declaration#6b04820
   |   |   | )member_declaration_or_access_specifier#6b042c0
   |   |   |)member_specification#6b042e0
   |   |   )class_specifier#6b04880
   |   |  )type_specifier#6b048a0
   |   | )decl_specifier#6b048c0
   |   |)basic_decl_specifier_seq#6b048e0
   |   )simple_declaration#6b04900
   |  )block_declaration#6b04920
   | )declaration#6b04940
   |)template_declaration#6b04960
   )declaration#6b04980
  )pp_declaration_seq#6b049a0
  (pp_declaration_seq@Cpp~GCC5=1022#6b06620^1#6b06640:2 Line 3 Column 1 File C:/temp/prime_with_templates.cpp
   (declaration@Cpp~GCC5=1036#6b06600^1#6b06620:1 Line 3 Column 1 File C:/temp/prime_with_templates.cpp
   |(template_declaration@Cpp~GCC5=2079#6b065e0^1#6b06600:1 Line 3 Column 1 File C:/temp/prime_with_templates.cpp
   | (template_parameter_list@Cpp~GCC5=2083#6b05460^1#6b065e0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |  (template_parameter_list@Cpp~GCC5=2083#6b05140^1#6b05460:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   (template_parameter_list@Cpp~GCC5=2083#6b04ee0^1#6b05140:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |(template_parameter_list@Cpp~GCC5=2082#6b04cc0^1#6b04ee0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   | (template_parameter@Cpp~GCC5=2085#6b04ca0^1#6b04cc0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |  (parameter_declaration@Cpp~GCC5=1611#6b04c80^1#6b04ca0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   (basic_decl_specifier_seq@Cpp~GCC5=1070#6b04a40^1#6b04c80:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   |(decl_specifier@Cpp~GCC5=1073#6b04a20^1#6b04a40:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   | (trailing_type_specifier@Cpp~GCC5=1118#6b04a00^1#6b04a20:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   |  (simple_type_specifier@Cpp~GCC5=1138#6b049e0^1#6b04a00:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |   | )trailing_type_specifier#6b04a00
   |   |   |)decl_specifier#6b04a20
   |   |   )basic_decl_specifier_seq#6b04a40
   |   |   (ptr_declarator@Cpp~GCC5=1417#6b04c40^1#6b04c80:2 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |(noptr_declarator@Cpp~GCC5=1421#6b04be0^1#6b04c40:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   | (declarator_id@Cpp~GCC5=1487#6b04bc0^1#6b04be0:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |  (id_expression@Cpp~GCC5=317#6b04b60^1#6b04bc0:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |   (unqualified_id@Cpp~GCC5=319#6b04ac0^1#6b04b60:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |   |(IDENTIFIER@Cpp~GCC5=3368#6b049c0^1#6b04ac0:1[`no'] Line 3 Column 15 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   |   )unqualified_id#6b04ac0
   |   |   |  )id_expression#6b04b60
   |   |   | )declarator_id#6b04bc0
   |   |   |)noptr_declarator#6b04be0
   |   |   )ptr_declarator#6b04c40
   |   |  )parameter_declaration#6b04c80
   |   | )template_parameter#6b04ca0
   |   |)template_parameter_list#6b04cc0
   |   |(template_parameter@Cpp~GCC5=2085#6b04ec0^1#6b04ee0:2 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   | (parameter_declaration@Cpp~GCC5=1611#6b04ea0^1#6b04ec0:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   |  (basic_decl_specifier_seq@Cpp~GCC5=1070#6b04b40^1#6b04ea0:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   |   (decl_specifier@Cpp~GCC5=1073#6b04ba0^1#6b04b40:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   |   |(trailing_type_specifier@Cpp~GCC5=1118#6b04c60^1#6b04ba0:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   |   | (simple_type_specifier@Cpp~GCC5=1138#6b04580^1#6b04c60:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |   |)trailing_type_specifier#6b04c60
   |   |   )decl_specifier#6b04ba0
   |   |  )basic_decl_specifier_seq#6b04b40
   |   |  (ptr_declarator@Cpp~GCC5=1417#6b04e60^1#6b04ea0:2 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   (noptr_declarator@Cpp~GCC5=1421#6b04e40^1#6b04e60:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   |(declarator_id@Cpp~GCC5=1487#6b04de0^1#6b04e40:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   | (id_expression@Cpp~GCC5=317#6b04d80^1#6b04de0:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   |  (unqualified_id@Cpp~GCC5=319#6b04ce0^1#6b04d80:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   |   (IDENTIFIER@Cpp~GCC5=3368#6b04560^1#6b04ce0:1[`yes'] Line 3 Column 24 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   |  )unqualified_id#6b04ce0
   |   |   | )id_expression#6b04d80
   |   |   |)declarator_id#6b04de0
   |   |   )noptr_declarator#6b04e40
   |   |  )ptr_declarator#6b04e60
   |   | )parameter_declaration#6b04ea0
   |   |)template_parameter#6b04ec0
   |   )template_parameter_list#6b04ee0
   |   (template_parameter@Cpp~GCC5=2085#6b05120^1#6b05140:2 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   |(parameter_declaration@Cpp~GCC5=1611#6b05100^1#6b05120:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   | (basic_decl_specifier_seq@Cpp~GCC5=1070#6b04d20^1#6b05100:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   |  (decl_specifier@Cpp~GCC5=1073#6b04dc0^1#6b04d20:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   |   (trailing_type_specifier@Cpp~GCC5=1118#6b04e80^1#6b04dc0:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   |   |(simple_type_specifier@Cpp~GCC5=1140#6b046e0^1#6b04e80:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |   )trailing_type_specifier#6b04e80
   |   |  )decl_specifier#6b04dc0
   |   | )basic_decl_specifier_seq#6b04d20
   |   | (ptr_declarator@Cpp~GCC5=1417#6b05080^1#6b05100:2 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |  (noptr_declarator@Cpp~GCC5=1421#6b05020^1#6b05080:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |   (declarator_id@Cpp~GCC5=1487#6b05000^1#6b05020:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |   |(id_expression@Cpp~GCC5=317#6b04fa0^1#6b05000:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |   | (unqualified_id@Cpp~GCC5=319#6b04f00^1#6b04fa0:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |   |  (IDENTIFIER@Cpp~GCC5=3368#6b046c0^1#6b04f00:1[`f'] Line 3 Column 33 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   | )unqualified_id#6b04f00
   |   |   |)id_expression#6b04fa0
   |   |   )declarator_id#6b05000
   |   |  )noptr_declarator#6b05020
   |   | )ptr_declarator#6b05080
   |   |)parameter_declaration#6b05100
   |   )template_parameter#6b05120
   |  )template_parameter_list#6b05140
   |  (template_parameter@Cpp~GCC5=2085#6b05440^1#6b05460:2 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   (parameter_declaration@Cpp~GCC5=1611#6b05420^1#6b05440:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   |(basic_decl_specifier_seq@Cpp~GCC5=1070#6b05160^1#6b05420:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   | (decl_specifier@Cpp~GCC5=1073#6b04fe0^1#6b05160:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   |  (trailing_type_specifier@Cpp~GCC5=1118#6b050e0^1#6b04fe0:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   |   (simple_type_specifier@Cpp~GCC5=1140#6b050c0^1#6b050e0:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |  )trailing_type_specifier#6b050e0
   |   | )decl_specifier#6b04fe0
   |   |)basic_decl_specifier_seq#6b05160
   |   |(ptr_declarator@Cpp~GCC5=1417#6b053e0^1#6b05420:2 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   | (noptr_declarator@Cpp~GCC5=1421#6b053c0^1#6b053e0:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   |  (declarator_id@Cpp~GCC5=1487#6b05360^1#6b053c0:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   |   (id_expression@Cpp~GCC5=317#6b05280^1#6b05360:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   |   |(unqualified_id@Cpp~GCC5=319#6b051a0^1#6b05280:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   |   | (IDENTIFIER@Cpp~GCC5=3368#6b046a0^1#6b051a0:1[`p'] Line 3 Column 40 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   |)unqualified_id#6b051a0
   |   |   )id_expression#6b05280
   |   |  )declarator_id#6b05360
   |   | )noptr_declarator#6b053c0
   |   |)ptr_declarator#6b053e0
   |   )parameter_declaration#6b05420
   |  )template_parameter#6b05440
   | )template_parameter_list#6b05460

변수 선언인지 곱셈인지 판별하는 것은 유형 검사 기능이 아닙니다. 또한 나는 그 자체 프로모션에 대한 당신의 대답을 다시 닦아내야했습니다 ... 다시.
강아지

@ 강아지 : 당신이 좋아하는 것을 말할 수 있지만, 그것이 도구의 작동 방식입니다. 도구 이름을 삭제하면 사람들이 도구 이름을 묻게 할 것입니다.
Ira Baxter

도구가 어떻게 작동하는지에 대한 질문이 없기 때문에 도구가 작동하는 방식과 관련이 없습니다. 또한 실제로 일어날 때까지 안전하게 기다릴 수 있다고 생각합니다.
강아지
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.