Является ли C++ контекстно-зависимым или контекстно-зависимым?

Я часто слышу заявления о том, что C++ является контекстно-зависимым языком. Возьмите следующий пример:

a b(c);

Это определение переменной или объявление функции? Это зависит от значения символа c, Если c переменная, то a b(c); определяет переменную с именем b типа a, Это непосредственно инициализируется с c, Но если c это тип, то a b(c); объявляет функцию с именем b это занимает c и возвращает a,

Если вы посмотрите определение контекстно-свободных языков, оно в основном скажет вам, что все грамматические правила должны иметь левые части, которые состоят ровно из одного нетерминального символа. Контекстно-зависимые грамматики, с другой стороны, допускают произвольные строки терминальных и нетерминальных символов в левой части.

Просматривая Приложение A "Языка программирования C++", я не смог найти ни одного грамматического правила, в котором было бы что-то еще, кроме одного нетерминального символа в левой части. Это подразумевает, что C++ не зависит от контекста. (Конечно, каждый контекстно-свободный язык также является контекстно-зависимым в том смысле, что контекстно-свободные языки образуют подмножество контекстно-зависимых языков, но это не главное.)

Итак, является ли C++ контекстно-зависимым или контекстно-зависимым?

19 ответов

Решение

Ниже моя (текущая) любимая демонстрация того, почему синтаксический анализ C++ (вероятно) является завершением по Тьюрингу, поскольку он показывает программу, синтаксически правильную тогда и только тогда, когда данное целое число является простым.

Поэтому я утверждаю, что C++ не является ни контекстно-зависимым, ни контекстно-зависимым.

Если вы разрешаете произвольные последовательности символов на обеих сторонах любого производства, вы создаете грамматику типа 0 ("неограниченную") в иерархии Хомского, которая является более мощной, чем контекстно-зависимая грамматика; неограниченные грамматики полны по Тьюрингу. Контекстно-зависимая (Тип-1) грамматика допускает несколько символов контекста в левой части продукции, но тот же контекст должен появляться в правой части продукции (отсюда и название "контекстно-зависимая"). [1] Контекстно-зависимые грамматики эквивалентны линейно ограниченным машинам Тьюринга.

В примере программы простое вычисление может быть выполнено с помощью линейно ограниченной машины Тьюринга, поэтому она не вполне доказывает эквивалентность Тьюринга, но важная часть заключается в том, что синтаксическому анализатору необходимо выполнить вычисления для выполнения синтаксического анализа. Это могли быть любые вычисления, выражаемые как создание экземпляра шаблона, и есть все основания полагать, что создание экземпляра шаблона C++ является Turing-complete. См., Например, статью Тодда Л. Вельдхуйзена за 2003 год.

Несмотря на это, C++ может быть проанализирован компьютером, поэтому он может быть проанализирован машиной Тьюринга. Следовательно, неограниченная грамматика может распознать это. На самом деле написание такой грамматики было бы непрактичным, поэтому стандарт не пытается это сделать. (Увидеть ниже.)

Проблема с "неоднозначностью" некоторых выражений - это в основном красная сельдь. Начнем с того, что двусмысленность - это особенность определенной грамматики, а не языка. Даже если можно доказать, что в языке нет однозначных грамматик, если его можно распознать по контекстно-свободной грамматике, он не зависит от контекста. Точно так же, если он не может быть распознан контекстно-свободной грамматикой, но он может быть распознан контекстно-зависимой грамматикой, он является контекстно-зависимым. Неоднозначность не актуальна.

Но в любом случае, как строка 21 (т.е. auto b = foo<IsPrime<234799>>::typen<1>();в приведенных ниже программах выражения вовсе не являются двусмысленными; они просто разбираются по-разному в зависимости от контекста. В самом простом выражении проблемы синтаксическая категория определенных идентификаторов зависит от того, как они были объявлены (например, типы и функции), что означает, что формальному языку придется признать тот факт, что две строки произвольной длины в одна и та же программа идентична (декларация и использование). Это может быть смоделировано грамматикой "копирования", которая является грамматикой, которая распознает две последовательные точные копии одного и того же слова. С леммой прокачки легко доказать, что этот язык не является контекстно-свободным. Контекстно-зависимая грамматика для этого языка возможна, и в ответе на этот вопрос приведена грамматика типа 0: https://math.stackexchange.com/questions/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 в 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 (|α| означает "длина α")

Можно доказать, что набор языков, распознаваемых монотонными грамматиками, точно такой же, как набор языков, распознаваемых контекстно-зависимыми грамматиками, и часто бывает проще основывать доказательства на монотонных грамматиках. Следовательно, довольно часто можно увидеть, что "контекстно-зависимый" используется, как если бы он означал "монотонный".

Во-первых, вы правильно заметили, что в грамматике в конце стандарта C++ нет контекстно-зависимых правил, поэтому грамматика не зависит от контекста.

Однако эта грамматика не совсем точно описывает язык C++, потому что она производит программы не на C++, такие как

int m() { m++; }

или же

typedef static int int;

Язык C++, определенный как "набор правильно сформированных программ на C++", не является контекстно-свободным (можно показать, что это делает просто требовательные переменные, которые должны быть объявлены). Учитывая, что вы можете теоретически писать программы, полные по Тьюрингу, в шаблонах и делать программу плохо сформированной на основе их результатов, она даже не зависит от контекста.

Теперь (невежественные) люди (обычно не теоретики языка, а разработчики синтаксических анализаторов) обычно используют слова "не контекстно-зависимые" в некоторых из следующих значений

  • двусмысленный
  • нельзя разобрать с бизоном
  • не LL(k), LR(k), LALR(k) или любой другой языковой класс, определенный парсером, который они выбрали

Грамматика в конце стандарта не удовлетворяет этим категориям (т. Е. Она неоднозначна, а не LL(k)...), поэтому грамматика C++ для них "не контекстно-свободна". И в некотором смысле, они правы, чертовски сложно создать работающий синтаксический анализатор C++.

Обратите внимание, что используемые здесь свойства слабо связаны с контекстно-свободными языками - неоднозначность не имеет ничего общего с контекстно-зависимой (на самом деле контекстно-зависимые правила обычно помогают устранить неоднозначность в продуктах), две другие являются просто подмножествами контекста Языки И разбор контекстно-свободных языков не является линейным процессом (хотя разбор детерминированных есть).

Да. Следующее выражение имеет различный порядок операций в зависимости от типа разрешенного контекста:

Редактирование: Когда фактический порядок операций меняется, становится невероятно сложно использовать "обычный" компилятор, который анализирует недекорированный 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 );

Чтобы ответить на ваш вопрос, вам нужно выделить два разных вопроса.

  1. Простой синтаксис почти каждого языка программирования не зависит от контекста. Как правило, это дается в виде расширенной формы Бэкуса-Наура или грамматики без контекста.

  2. Однако даже если программа соответствует грамматике без контекста, определенной языком программирования, она не обязательно является допустимой программой. Существует много неконтекстных попертисов, которым должна соответствовать программа, чтобы быть действительной программой. Например, самым простым таким свойством является область видимости переменных.

Чтобы сделать вывод, является ли C++ контекстно-зависимым, зависит от того, какой вопрос вы задаете.

Возможно, вы захотите взглянуть на дизайн и эволюцию C++, Бьярн Страуструп. В нем он описывает свои проблемы, пытаясь использовать yacc (или аналогичный) для анализа ранней версии C++, и желая, чтобы он использовал вместо этого рекурсивный спуск.

Да, C++ является контекстно-зависимым, очень контекстно-зависимым. Вы не можете построить синтаксическое дерево, просто проанализировав файл с помощью анализатора без контекста, потому что в некоторых случаях вам нужно знать символ из предыдущих знаний, чтобы принять решение (т.е. построить таблицу символов при разборе).

Первый пример:

A*B;

Это выражение умножения?

ИЛИ ЖЕ

Это декларация B переменная, чтобы быть указателем типа A?

Если A - переменная, то это выражение, если A - тип, это объявление указателя.

Второй пример:

A B(bar);

Это прототип функции, принимающий аргумент bar тип?

ИЛИ ЖЕ

Это объявить переменную B типа A и вызывает конструктор А с bar константа как инициализатор?

Вам нужно снова знать, bar переменная или тип из таблицы символов.

Третий пример:

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

Это тот случай, когда построение таблицы символов во время синтаксического анализа не помогает, потому что объявление x и y идет после определения функции. Поэтому вам нужно сначала просмотреть определение класса и посмотреть определения методов во втором проходе, чтобы сказать, что x * y - это выражение, а не объявление указателя или что-то еще.

У меня есть ощущение, что существует некоторая путаница между формальным определением "контекстно-зависимым" и неформальным использованием "контекстно-зависимым". Первый имеет четко определенный смысл. Последний используется для того, чтобы сказать "вам нужен контекст для анализа входных данных".

Это также спрашивается здесь: Контекст-чувствительность против неоднозначности.

Вот контекстная грамматика:

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

Это неоднозначно, поэтому для анализа входных данных "х" вам нужен некоторый контекст (или жить с неоднозначностью, или выдать "Предупреждение: E8271 - Ввод строки неоднозначен в строке 115"). Но это, конечно, не контекстно-зависимая грамматика.

C++ анализируется с помощью анализатора GLR. Это означает, что во время синтаксического анализа исходного кода анализатор может столкнуться с неоднозначностью, но он должен продолжить и решить, какое грамматическое правило использовать позже.

смотри также,

Почему C++ не может быть проанализирован парсером LR(1)?


Помните, что контекстно-свободная грамматика не может описывать ВСЕ правила синтаксиса языка программирования. Например, грамматика атрибута используется для проверки правильности типа выражения.

int x;
x = 9 + 1.0;

Вы не можете описать следующее правило с помощью контекстно-свободной грамматики:правая сторона задания должна быть того же типа, что и левая сторона.

Ни один подобный Алголу язык не является контекстно-свободным, потому что у них есть правила, которые ограничивают выражения и операторы, в которых идентификаторы могут появляться в зависимости от их типа, и потому что нет никаких ограничений на количество операторов, которые могут произойти между объявлением и использованием.

Обычное решение заключается в написании синтаксического анализатора без контекста, который фактически принимает расширенный набор допустимых программ и помещает чувствительные к контексту части в специальный "семантический" код, присоединенный к правилам.

C++ выходит далеко за рамки этого благодаря своей системе шаблонов, полной Turing. См. Вопрос переполнения стека 794015.

Самый простой случай неконтекстной грамматики включает в себя синтаксический анализ выражений с использованием шаблонов.

a<b<c>()

Это можно разобрать как

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

Или же

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

Два значения AST можно устранить только путем проверки объявления "a" - первого AST, если "a" является шаблоном, или второго, если нет.

Продукция в стандарте C++ написана без контекста, но, как мы все знаем, на самом деле не определяет язык точно. Некоторые из того, что большинство людей воспринимают как двусмысленность в текущем языке, могут (я считаю) быть решены однозначно с помощью контекстно-зависимой грамматики.

Для наиболее очевидного примера, давайте рассмотрим самый Vexing Parse: 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, по крайней мере, так как этот термин обычно используется.

Это зависит от контекста, как a b(c); имеет два допустимых синтаксических анализа - объявление и переменную. Когда вы говорите "Если c это тип ", это контекст, прямо здесь, и вы точно описали, как C++ чувствителен к нему. Если у вас не было этого контекста" Что такое c"Вы не могли разобрать это однозначно.

Здесь контекст выражается в выборе токенов - синтаксический анализатор считывает идентификатор как токен имени типа, если он называет тип. Это простейшее решение, позволяющее избежать значительной сложности, связанной с контекстом (в данном случае).

Изменить: Есть, конечно, больше вопросов чувствительности к контексту, я просто сосредоточился на том, что вы показали. Шаблоны особенно противны для этого.

Правда:)

Дж. Стэнли Уорфорд. Компьютерные системы. Страницы 341-346.

Было показано, что шаблоны C++ являются мощными по Тьюрингу. Хотя это и не официальная ссылка, здесь есть место, чтобы взглянуть на это:

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

Я рискну предположить (столь же старый, как народное и краткое доказательство CACM, показывающее, что ALGOL в 60-х годах не может быть представлен CFG), и скажу, что C++ не может быть правильно проанализирован только CFG. CFGs, в сочетании с различными механизмами TP в проходе дерева или во время событий сокращения - это другая история. В общем смысле, из-за проблемы остановки, существует некоторая программа на C++, которая не может быть показана правильной / неправильной, но тем не менее правильной / неправильной.

{PS - Как автор Meta-S (упомянутый несколькими людьми выше) - я могу с уверенностью сказать, что Thothic не является более не существующей, и программное обеспечение не доступно бесплатно. Возможно, я сформулировал эту версию своего ответа так, чтобы меня не удаляли и не голосовали до -3.}

C++ не является контекстно-свободным. Я узнал это некоторое время назад в лекции компиляторов. Быстрый поиск дал эту ссылку, где раздел "Синтаксис или семантика" объясняет, почему C и C++ не являются контекстно-свободными:

Обсуждение Википедии: Грамматика без контекста

С Уважением,
Ованес

Очевидно, что если принять дословный вопрос, почти все языки с идентификаторами являются контекстно-зависимыми.

Нужно знать, является ли идентификатор именем типа (именем класса, именем, введенным typedef, параметром шаблона typename), именем шаблона или каким-либо другим именем, чтобы иметь возможность правильно использовать идентификатор. Например:

x = (name)(expression);

это бросок, если name это имя типа и вызов функции, если name это имя функции. Другой случай - это так называемый "самый неприятный анализ", когда невозможно различить определение переменной и объявление функции (есть правило, гласящее, что это объявление функции).

Эта трудность привела к необходимости typename а также template с зависимыми именами. Насколько я знаю, остальная часть C++ не является контекстно-зависимой (то есть для нее можно написать контекстно-свободную грамматику).

Meta-S"является контекстно-зависимым механизмом синтаксического анализа Куинн Тайлер Джексон. Я не использовал его, но он рассказывает впечатляющую историю. Посмотрите его комментарии в comp.compilers и посмотрите rnaparse.com/MetaS%20defined.htm - Ира Бакстер 25 июля в 10:42

Правильная ссылка на разбор enigines

Meta-S был собственностью несуществующей компании под названием Thothic. Я могу отправить бесплатную копию Meta-S всем, кто интересуется ею, и использовал ее в исследованиях по анализу РНА. Обратите внимание, что "грамматика псевдоузла", включенная в папки с примерами, была написана программистом, не занимающимся биоинформатикой, и в основном не работает. Мои грамматики используют другой подход и работают довольно хорошо.

Большой проблемой здесь является то, что термины "контекстно-свободный" и "контекстно-зависимый" в информатике немного не интуитивно понятны. Для C++ контекстная чувствительность во многом похожа на двусмысленность, но в общем случае это не обязательно так.

В C/++ оператор if разрешен только внутри тела функции. Казалось бы, это делает его контекстно-зависимым, не так ли? Ну нет. Грамматикам без контекста на самом деле не требуется свойство, в котором вы можете выделить какую-то строку кода и определить, действительно ли она действительна. На самом деле это не то, что означает контекстно-свободный. На самом деле это просто ярлык, который неопределенно подразумевает что-то вроде того, на что это похоже.

Теперь, если оператор в теле функции анализируется по-разному в зависимости от того, что определено за пределами непосредственных грамматических предков (например, описывает ли идентификатор тип или переменную), как в a * b;case, то он фактически зависит от контекста. Здесь нет никакой двусмысленности; он будет проанализирован как объявление указателя, еслиa является типом и умножением в противном случае.

Быть зависимым от контекста не обязательно означает "сложный для анализа". C на самом деле не так сложно, потому что печально известныйa * b; "двусмысленность" может быть разрешена с помощью таблицы символов, содержащей typedefвстречались ранее. Для разрешения этого случая не требуется никаких произвольных экземпляров шаблонов (которые, как было доказано, являются полными по Тьюрингу), как это иногда делает C++. На самом деле невозможно написать программу на C, которая не будет компилироваться за конечное время, даже если она имеет такую ​​же контекстную чувствительность, что и C++.

Python (и другие языки, чувствительные к пробелам) также зависят от контекста, так как он требует состояния в лексере для генерации токенов отступа и отступа, но это не усложняет синтаксический анализ, чем типичная грамматика LL-1. Фактически он использует генератор синтаксического анализа, что является одной из причин, по которой Python имеет такие неинформативные сообщения об ошибках синтаксиса. Также важно отметить, что здесь нет "двусмысленности", подобнойa * b; проблема в Python, дающая хороший конкретный пример контекстно-зависимого языка без "неоднозначной" грамматики (как упоминалось в первом абзаце).

В этом ответе говорится, что C++ не является контекстно-свободным... есть смысл (не отвечающий), что он не может быть проанализирован, и в ответе предлагается пример сложного кода, который создает неверную программу C++, если определенная константа не является простое число.

Как отмечали другие, вопрос о том, является ли язык контекстно-зависимым / свободным, отличается от того же вопроса о конкретной грамматике.

Чтобы поставить вопрос о синтаксическом разборе на отдых, я предлагаю эмпирическое доказательство того, что существуют неконтекстные грамматики для C++, которые можно использовать для создания AST для неконтекстного анализа исходного текста, фактически анализируя его с помощью существующего GLR. -parser-инструмент, основанный на явной грамматике.

Да, это удается, "принимая слишком много"; не все, что она принимает, является допустимой программой на C++, поэтому за ней следуют дополнительные проверки (проверки типов). И да, проверка типов может столкнуться с проблемами вычислимости. На практике инструменты не имеют этой проблемы; если бы люди писали такие программы, ни одна из них не скомпилировалась бы. (Я думаю, что стандарт на самом деле накладывает ограничение на количество вычислений, которые вы можете выполнить, разворачивая шаблон, так что на самом деле вычисления на самом деле конечны, но, вероятно, довольно большие).

Если вы имеете в виду, определите, входит ли исходная программа в набор допустимых исходных программ на C++, тогда я согласен, что проблема намного сложнее. Но проблема не в разборе.

Инструмент решает эту проблему, изолируя анализ от проверки типа анализируемой программы. (Если существует несколько интерпретаций в отсутствие контекста, он записывает узел неоднозначности в дереве разбора с несколькими возможными анализами; проверка типа решает, какая из них правильная, и удаляет недопустимые поддеревья). Вы можете увидеть (частичное) дерево разбора в примере ниже; все дерево слишком велико, чтобы уместиться в SO ответе. Обратите внимание, что вы получаете дерево разбора независимо от того, используется ли значение 234797 или 234799.

Запуск средства определения имени / типа инструмента по AST с исходным значением 234799 завершается успешно. При значении 234797 преобразователь имен завершается неудачно (как и ожидалось) с сообщением об ошибке "typen не является типом". и, следовательно, эта версия не является допустимой программой 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
Другие вопросы по тегам