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

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

a b(c);

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

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

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

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

Ответ 1

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

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

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

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

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

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

Но в любом случае, как и строка 21 (т.е. auto b = foo<IsPrime<234799>>::typen<1>();) в приведенной ниже программе, выражения не являются двусмысленными; они просто разбираются по-разному в зависимости от контекста. В простейшем выражении проблемы синтаксическая категория определенных идентификаторов зависит от того, как они были объявлены (например, типы и функции), что означает, что формальный язык должен был бы признать тот факт, что две строки произвольной длины в одна и та же программа идентична (декларация и использование). Это может быть смоделировано грамматикой "копия", которая является грамматикой, которая распознает две последовательные точные копии одного и того же слова. Легко доказать с помощью леммы https://math.stackexchange.com/questions/163830/context-sensitive-grammar-for-the-copy-language.

Если попытаться написать контекстно-зависимую (или неограниченную) грамматику для синтаксического анализа С++, она вполне может заполнить вселенную scribblings. Написание машины Тьюринга для синтаксического анализа С++ было бы столь же невозможным. Даже писать программу на С++ сложно, и насколько я знаю, никто не был доказан правильно. Вот почему стандарт не пытается предоставить полную формальную грамматику и почему он предпочитает писать некоторые правила синтаксического анализа на техническом английском языке.

То, что выглядит как формальная грамматика в стандарте С++, не является полным формальным определением синтаксиса языка С++. Это даже не полное формальное определение языка после предварительной обработки, которое может быть легче формализовать. (Это не было бы языком, однако: язык С++, определенный стандартом, включает препроцессор, а работа препроцессора описана алгоритмически, поскольку было бы чрезвычайно сложно описать в любом грамматическом формализме. Именно в этом разделе стандарта, где описывается лексическое разложение, включая правила, в которых его необходимо применять более одного раза.)

Различные грамматики (два перекрывающихся грамматики для лексического анализа, один из которых выполняется перед препроцессией, а другой, если необходимо, впоследствии, плюс синтаксическая грамматика) собраны в Приложении А с этой важной запиской (выделено мной)

Это резюме синтаксиса С++ предназначено для помощи в понимании. Это не точная формулировка языка. В частности, описанная здесь грамматика принимает надмножество допустимых конструкций С++. Правила различения (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β &rightarrow; αγβ

где A является нетерминальным, а α, β - это, возможно, пустые последовательности символов грамматики, а γ - непустая последовательность. (Символы грамматики могут быть либо терминалами, либо терминалами).

Это можно прочитать как A &rightarrow; γ только в контексте [α, β]. В грамматике без контекста (тип 2) α и β должны быть пустыми.

Оказывается, вы также можете ограничить грамматики "монотонным" ограничением, где каждое произведение должно иметь вид:

α &rightarrow; β где |α| ≥ |β| > 0   (|α| означает "длина α" )

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

Ответ 2

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

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

int m() { m++; }

или

typedef static int int;

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

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

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

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

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

Ответ 3

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

Изменить: когда действительный порядок работы меняется, это делает невероятно трудным использование "обычного" компилятора, который анализирует неконсолидированный АСТ, прежде чем украшать его (распространять информацию о типе). Другие упомянутые контекстно-зависимые вещи "довольно легки" по сравнению с этим (не то, что оценка шаблона совсем невелика).

#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 );

Ответ 4

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

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

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

В заключение, зависит ли С++ от контекста, зависит от вопроса, который вы задаете.

Ответ 6

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

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

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 - выражение, а не объявление указателя или что-то еще.

Ответ 7

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

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

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


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

int x;
x = 9 + 1.0;

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

Ответ 8

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

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

Здесь контекстно-свободная грамматика:

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

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

Ответ 9

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

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

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

Ответ 11

Он контекстно-зависим, так как a b(c); имеет два действительных выражения и переменную parses. Когда вы говорите: "Если c - это тип", этот контекст, прямо там, и вы точно описали, как С++ чувствителен к нему. Если у вас не было этого контекста "Что такое c?" вы не могли бы разобрать это однозначно.

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

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

Ответ 12

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

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

Ответ 13

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

a<b<c>()

Это может анализироваться как

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

Или

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

Два АСТ могут быть устранены только путем изучения объявления "а" - бывшего АСТ, если "а" - это шаблон, или последний, если нет.

Ответ 15

С++ шаблоны были показаны как Turing Мощный. Хотя это не формальная ссылка, здесь место, чтобы посмотреть в этом отношении:

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

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

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

Ответ 16

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

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

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

Ответ 17

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

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

x = (name)(expression);

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

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

Ответ 18

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

Правильная ссылка синтаксический анализ

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

Ответ 19

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

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

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

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

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

Ответ 20

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

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

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

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

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

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

Запуск имени инструмента/типа распознавателя по AST с исходным значением 234799 успешно завершен. При значении 234797 распознаватель имен не работает (как и ожидалось) с сообщением об ошибке, "typen не является типом". и, следовательно, эта версия не является допустимой программой на С++.

967 tree nodes in tree.
15 ambiguity nodes in tree.
([email protected]~GCC5=2#6b11a20^0 Line 1 Column 1 File C:/temp/prime_with_templates.cpp
 ([email protected]~GCC5=1021#6b06640^1#6b11a20:1 {10} Line 1 Column 1 File C:/temp/prime_with_templates.cpp
  ([email protected]~GCC5=1022#6b049a0^1#6b06640:1 Line 1 Column 1 File C:/temp/prime_with_templates.cpp
   ([email protected]~GCC5=1036#6b04980^1#6b049a0:1 Line 1 Column 1 File C:/temp/prime_with_templates.cpp
   |([email protected]~GCC5=2079#6b04960^1#6b04980:1 Line 1 Column 1 File C:/temp/prime_with_templates.cpp
   | ([email protected]~GCC5=2082#6afbde0^1#6b04960:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |  ([email protected]~GCC5=2085#6afbd80^1#6afbde0:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   ([email protected]~GCC5=1611#6afbd40^1#6afbd80:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   |([email protected]~GCC5=1070#6afb880^1#6afbd40:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   | ([email protected]~GCC5=1073#6afb840^1#6afb880:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   |  ([email protected]~GCC5=1118#6afb7e0^1#6afb840:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   ([email protected]~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
   |   |([email protected]~GCC5=1417#6afbc40^1#6afbd40:2 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   | ([email protected]~GCC5=1421#6afbba0^1#6afbc40:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   |  ([email protected]~GCC5=1487#6afbb80^1#6afbba0:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   ([email protected]~GCC5=317#6afbaa0^1#6afbb80:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |([email protected]~GCC5=319#6afb9c0^1#6afbaa0:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   | ([email protected]~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
   | ([email protected]~GCC5=1033#6b04940^1#6b04960:2 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |  ([email protected]~GCC5=1050#6b04920^1#6b04940:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   ([email protected]~GCC5=1060#6b04900^1#6b04920:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |([email protected]~GCC5=1070#6b048e0^1#6b04900:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   | ([email protected]~GCC5=1073#6b048c0^1#6b048e0:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |  ([email protected]~GCC5=1110#6b048a0^1#6b048c0:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |   ([email protected]~GCC5=1761#6b04880^1#6b048a0:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |   |([email protected]~GCC5=1763#6afb980^1#6b04880:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |   | ([email protected]~GCC5=1791#6afbca0^1#6afb980:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp)class_key
   |   |   | ([email protected]~GCC5=3368#6afbcc0^1#6afb980:2[`answer'] Line 1 Column 25 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   | ([email protected]~GCC5=1872#6afba60^1#6afb980:3 Line 1 Column 32 File C:/temp/prime_with_templates.cpp)optional_base_clause
   |   |   |)class_head#6afb980
   |   |   |([email protected]~GCC5=1794#6b042e0^1#6b04880:2 {2} Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   | ([email protected]~GCC5=1806#6b04060^1#6b042e0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |  ([email protected]~GCC5=1822#6b04040^1#6b04060:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   ([email protected]~GCC5=1632#6b04020^1#6b04040:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |([email protected]~GCC5=1673#6afbec0^1#6b04020:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   | ([email protected]~GCC5=1417#6afbfe0^1#6afbec0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |  ([email protected]~GCC5=1422#6afbf80^1#6afbfe0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   ([email protected]~GCC5=1421#6afbf60^1#6afbf80:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |([email protected]~GCC5=1487#6afbea0^1#6afbf60:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   | ([email protected]~GCC5=317#6afbb40^1#6afbea0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |  ([email protected]~GCC5=319#6afbc80^1#6afbb40:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   ([email protected]~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_de[email protected]~GCC5=1559#6afbd00^1#6afbf80:2 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |([email protected]~GCC5=1570#6afb940^1#6afbd00:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   | ([email protected]~GCC5=1574#6afb800^1#6afb940:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |  ([email protected]~GCC5=1610#6afb9a0^1#6afb800:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   ([email protected]~GCC5=1070#6afbf40^1#6afb9a0:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |([email protected]~GCC5=1073#6afbfa0^1#6afbf40:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   | ([email protected]~GCC5=1118#6afbfc0^1#6afbfa0:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |  ([email protected]~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
   |   |   |   |   ([email protected]~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
   |   |   |   |([email protected]~GCC5=1680#6b04000^1#6b04020:2 Line 1 Column 46 File C:/temp/prime_with_templates.cpp
   |   |   |   | ([email protected]~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
   |   |   | ([email protected]~GCC5=1806#6b042c0^1#6b042e0:2 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |  ([email protected]~GCC5=1822#6b04820^1#6b042c0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   ([email protected]~GCC5=1632#6b04280^1#6b04820:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   |([email protected]~GCC5=1674#6b04220^1#6b04280:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   | ([email protected]~GCC5=1070#6b040e0^1#6b04220:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   |  ([email protected]~GCC5=1073#6b040c0^1#6b040e0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   |   ([email protected]~GCC5=1118#6b040a0^1#6b040c0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |([email protected]~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
   |   |   |   | ([email protected]~GCC5=1417#6b04200^1#6b04220:2 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |  ([email protected]~GCC5=1422#6b041e0^1#6b04200:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   ([email protected]~GCC5=1421#6b041a0^1#6b041e0:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |([email protected]~GCC5=1487#6b04180^1#6b041a0:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   | ([email protected]~GCC5=317#6b04160^1#6b04180:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |  ([email protected]~GCC5=320#6b04140^1#6b04160:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   ([email protected]~GCC5=2027#6b04120^1#6b04140:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |([email protected]~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
   |   |   |   |   ([email protected]~GCC5=1558#6afba40^1#6b041e0:2 Line 1 Column 65 File C:/temp/prime_with_templates.cpp)parameter_declaration_clause
   |   |   |   |   ([email protected]~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
   |   |   |   |([email protected]~GCC5=1680#6b04300^1#6b04280:2 Line 1 Column 66 File C:/temp/prime_with_templates.cpp
   |   |   |   | ([email protected]~GCC5=889#6b04760^1#6b04300:1 Line 1 Column 66 File C:/temp/prime_with_templates.cpp
   |   |   |   |  ([email protected]~GCC5=894#6b04780^1#6b04760:1 Line 1 Column 67 File C:/temp/prime_with_templates.cpp
   |   |   |   |   ([email protected]~GCC5=857#6b04440^1#6b04780:1 Line 1 Column 67 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |([email protected]~GCC5=1011#6afba80^1#6b04440:1 Line 1 Column 67 File C:/temp/prime_with_templates.cpp
   |   |   |   |   | ([email protected]~GCC5=551#6b04380^1#6afba80:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |  ([email protected]~GCC5=543#6b04360^1#6b04380:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   ([email protected]~GCC5=465#6b04340^1#6b04360:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |([email protected]~GCC5=307#6b04320^1#6b04340:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   | ([email protected]~GCC5=317#6b042a0^1#6b04320:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |  ([email protected]~GCC5=319#6b04260^1#6b042a0:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |   ([email protected]~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
  ([email protected]~GCC5=1022#6b06620^1#6b06640:2 Line 3 Column 1 File C:/temp/prime_with_templates.cpp
   ([email protected]~GCC5=1036#6b06600^1#6b06620:1 Line 3 Column 1 File C:/temp/prime_with_templates.cpp
   |([email protected]~GCC5=2079#6b065e0^1#6b06600:1 Line 3 Column 1 File C:/temp/prime_with_templates.cpp
   | ([email protected]~GCC5=2083#6b05460^1#6b065e0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |  ([email protected]~GCC5=2083#6b05140^1#6b05460:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   ([email protected]~GCC5=2083#6b04ee0^1#6b05140:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |([email protected]~GCC5=2082#6b04cc0^1#6b04ee0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   | ([email protected]~GCC5=2085#6b04ca0^1#6b04cc0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |  ([email protected]~GCC5=1611#6b04c80^1#6b04ca0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   ([email protected]~GCC5=1070#6b04a40^1#6b04c80:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   |([email protected]~GCC5=1073#6b04a20^1#6b04a40:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   | ([email protected]~GCC5=1118#6b04a00^1#6b04a20:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   |  ([email protected]~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
   |   |   ([email protected]~GCC5=1417#6b04c40^1#6b04c80:2 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |([email protected]~GCC5=1421#6b04be0^1#6b04c40:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   | ([email protected]~GCC5=1487#6b04bc0^1#6b04be0:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |  ([email protected]~GCC5=317#6b04b60^1#6b04bc0:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |   ([email protected]~GCC5=319#6b04ac0^1#6b04b60:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |   |([email protected]~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
   |   |([email protected]~GCC5=2085#6b04ec0^1#6b04ee0:2 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   | ([email protected]~GCC5=1611#6b04ea0^1#6b04ec0:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   |  ([email protected]~GCC5=1070#6b04b40^1#6b04ea0:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   |   ([email protected]~GCC5=1073#6b04ba0^1#6b04b40:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   |   |([email protected]~GCC5=1118#6b04c60^1#6b04ba0:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   |   | ([email protected]~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
   |   |  ([email protected]~GCC5=1417#6b04e60^1#6b04ea0:2 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   ([email protected]~GCC5=1421#6b04e40^1#6b04e60:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   |([email protected]~GCC5=1487#6b04de0^1#6b04e40:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   | ([email protected]~GCC5=317#6b04d80^1#6b04de0:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   |  ([email protected]~GCC5=319#6b04ce0^1#6b04d80:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   |   ([email protected]~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
   |   ([email protected]~GCC5=2085#6b05120^1#6b05140:2 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   |([email protected]~GCC5=1611#6b05100^1#6b05120:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   | ([email protected]~GCC5=1070#6b04d20^1#6b05100:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   |  ([email protected]~GCC5=1073#6b04dc0^1#6b04d20:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   |   ([email protected]~GCC5=1118#6b04e80^1#6b04dc0:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   |   |([email protected]~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
   |   | ([email protected]~GCC5=1417#6b05080^1#6b05100:2 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |  ([email protected]~GCC5=1421#6b05020^1#6b05080:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |   ([email protected]~GCC5=1487#6b05000^1#6b05020:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |   |([email protected]~GCC5=317#6b04fa0^1#6b05000:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |   | ([email protected]~GCC5=319#6b04f00^1#6b04fa0:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |   |  ([email protected]~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
   |  ([email protected]~GCC5=2085#6b05440^1#6b05460:2 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   ([email protected]~GCC5=1611#6b05420^1#6b05440:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   |([email protected]~GCC5=1070#6b05160^1#6b05420:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   | ([email protected]~GCC5=1073#6b04fe0^1#6b05160:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   |  ([email protected]~GCC5=1118#6b050e0^1#6b04fe0:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   |   ([email protected]~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
   |   |([email protected]~GCC5=1417#6b053e0^1#6b05420:2 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   | ([email protected]~GCC5=1421#6b053c0^1#6b053e0:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   |  ([email protected]~GCC5=1487#6b05360^1#6b053c0:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   |   ([email protected]~GCC5=317#6b05280^1#6b05360:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   |   |([email protected]~GCC5=319#6b051a0^1#6b05280:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   |   | ([email protected]~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