C ++是无上下文还是上下文敏感?

时间:2013-01-29 18:05:57

标签: c++ syntax grammar context-free-grammar context-sensitive-grammar

我经常听到C ++是一种上下文敏感语言的说法。请看以下示例:

a b(c);

这是变量定义还是函数声明?这取决于符号c的含义。如果c变量,则a b(c);定义名为b的{​​{1}}类型的变量。它使用a直接初始化。但如果c类型,那么c会声明一个名为a b(c);的函数,该函数需要b并返回c

如果你查找无上下文语言的定义,它基本上会告诉你所有语法规则必须有左侧,只包含一个非终端符号。另一方面,上下文敏感语法允许在左侧使用任意字符串的终端和非终端符号。

浏览“The C ++ Programming Language”的附录A,我找不到单个语法规则,除了左侧的单个非终端符号之外还有其他任何东西。这意味着C ++是无上下文的。 (当然,每种无上下文的语言也都是上下文敏感的,因为无上下文的语言构成了上下文敏感语言的一个子集,但这不是重点。)

那么,C ++是无上下文还是上下文敏感?

19 个答案:

答案 0 :(得分:112)

首先,您正确地观察到C ++标准末尾的语法中没有上下文敏感规则,因此语法 无上下文。

然而,该语法并没有精确地描述C ++语言,因为它产生非C ++程序,如

int m() { m++; }

typedef static int int;

定义为“一组结构良好的C ++程序”的C ++语言不是无上下文的(可以证明只需要声明要求的变量就可以了)。理论上,你可以在模板中编写图灵完备程序,并根据结果使程序格式不正确,它甚至不是上下文敏感的。

现在,(无知)人(通常不是语言理论家,但是解析器设计者)通常在以下某些含义中使用“不具有上下文”

  • 暧昧
  • 无法使用Bison解析
  • 不是LL(k),LR(k),LALR(k)或他们选择的任何解析器定义的语言类

标准背面的语法不满足这些类别(即它不明确,而不是LL(k)......)因此C ++语法对它们来说“不具有上下文”。从某种意义上说,他们是对的,很难生成一个可行的C ++解析器。

请注意,此处使用的属性仅与上下文无关语言微弱关联 - 模糊性与上下文敏感性无关(事实上,上下文相关规则通常有助于消除歧义的制作),另外两个仅仅是无上下文语言的子集。解析无上下文语言不是一个线性过程(尽管解析确定性语言)。

答案 1 :(得分:59)

是。以下表达式具有不同的操作顺序,具体取决于类型已解析的上下文

编辑:当实际操作顺序不同时,使用“常规”编译器在装饰之前解析未修饰的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 );

答案 2 :(得分:23)

要回答您的问题,您需要区分两个不同的问题。

  1. 几乎所有编程语言的语法都是无上下文的。通常,它是作为扩展的Backus-Naur形式或无上下文的gramar给出的。

  2. 但是,即使程序符合编程语言定义的无上下文gramar,它也不一定是有效的程序。程序必须满足许多非上下文无关的特性才能成为有效的程序。例如,最简单的这种属性是变量的范围。

  3. 总而言之,C ++是否无上下文取决于你问的问题。

答案 3 :(得分:11)

你可能想看看Bjarne Stroustrup的The Design & Evolution of C++。在其中,他描述了他试图使用yacc(或类似)来解析早期版本的C ++,并希望他使用递归下降的问题。

答案 4 :(得分:10)

使用GLR解析器解析C ++。这意味着在解析源代码时,解析器可能遇到歧义,但它应该继续并决定使用以后的语法规则。

看看,

Why C++ cannot be parsed with a LR(1) parser?


请记住,无上下文语法不能描述 ALL 编程语言语法的规则。例如,属性语法用于检查表达式类型的有效性。

int x;
x = 9 + 1.0;

无法使用无上下文语法描述以下规则: 作业的右侧应与左手侧的类型相同。

答案 5 :(得分:10)

是的C ++是上下文敏感的,非常依赖于上下文。您无法通过使用无上下文解析器解析文件来构建语法树,因为在某些情况下,您需要知道先前知识中的符号来决定(即在解析时构建符号表)。

第一个例子:

A*B;

这是乘法表达式吗?

OR

这是B变量的声明是A类型的指针吗?

如果A是变量,那么它是一个表达式,如果A是类型,它就是一个指针声明。

第二个例子:

A B(bar);

这是一个函数原型,它采用bar类型的参数吗?

OR

这是B类型的变量A,并且调用A的构造函数bar常量作为初始值设定项吗?

您需要再次知道bar是变量还是符号表中的类型。

第三个例子:

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

构建符号表时就是这种情况,而解析没有帮助,因为x和y的声明位于函数定义之后。所以你需要首先扫描类定义,然后在第二遍中查看方法定义,告诉x * y是一个表达式,而不是指针声明或其他。

答案 6 :(得分:8)

我感觉在“上下文敏感”的正式定义与“上下文敏感”的非正式使用之间存在一些混淆。前者具有明确的含义。后者用于说“你需要上下文来解析输入”。

这里也有人问: Context-sensitivity vs Ambiguity

这是一个无上下文的语法:

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

这是不明确的,所以为了解析输入“x”你需要一些上下文(或者带有模糊性,或者发出“警告:E8271 - 输入在第115行中是模糊的”)。但它肯定不是一个上下文敏感的语法。

答案 7 :(得分:5)

没有类似Algol的语言是无上下文的,因为它们具有限制表达式和语句可以根据其类型出现的规则,并且因为声明和使用之间可能发生的语句数量没有限制。

通常的解决方案是编写一个无上下文的解析器,它实际上接受有效程序的超集,并将上下文相关部分放在附加到规则的 ad hoc “语义”代码中。

由于其图灵完整的模板系统,C ++远远超出了这个范围。请参阅Stack Overflow Question 794015

答案 8 :(得分:5)

最简单的非上下文语法包括解析涉及模板的表达式。

a<b<c>()

这可以解析为

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

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

这两个AST只能通过检查'a'的声明来消除歧义 - 如果'a'是模板,则为前AST,如果不是,则为后者。

答案 9 :(得分:4)

它是上下文相关的,因为a b(c);有两个有效的parses-声明和变量。如果你说“如果c是一个类型”,那就是那个上下文,你已经准确地描述了C ++对它的敏感程度。如果你没有“什么是c?”的背景你不能毫不含糊地解析这个。

这里,上下文在标记的选择中表示 - 如果标识符命名类型,则解析器将标识符读取为类型名称标记。这是最简单的解决方案,并且避免了上下文敏感的大部分复杂性(在这种情况下)。

编辑:当然,有更多的情境敏感问题,我只关注你所展示的问题。模板对此特别讨厌。

答案 10 :(得分:4)

真:)

学家斯坦利沃福德。 Computer systems。第341-346页。

答案 11 :(得分:4)

C ++标准中的作品是无上下文的,但我们都知道并没有真正定义语言。大多数人认为当前语言中含糊不清的一些内容(我相信)可以通过上下文敏感语法明确地解决。

对于最明显的例子,让我们考虑最令人烦恼的解析: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,至少通常使用该术语。

答案 12 :(得分:3)

C ++模板已被证明是图灵强大的。虽然不是一个正式的参考,但在这方面,这里是一个值得关注的地方:

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

我会冒险猜测(就像一个民俗和简洁的CACM证明,表明60年代的ALGOL无法被CFG重新制定)并且说C ++因此不能仅通过CFG正确解析。 CFG,结合树木通过或减少事件期间的各种TP机制 - 这是另一个故事。在一般意义上,由于停止问题,存在一些C ++程序无法显示正确/不正确但仍然是正确/不正确的。

{PS-作为Meta-S的作者(上面有几个人提到) - 我可以肯定地说,Thothic既不会失效,也不会免费提供软件。也许我已经措辞了这个版本的回复,这样我就不会被删除或投票到-3。}

答案 13 :(得分:3)

答案 14 :(得分:2)

C ++不是上下文。不久前我在编译器讲座中学到了它。快速搜索给出了这个链接,其中“语法或语义”部分解释了为什么C和C ++不是无上下文的:

Wikipedia Talk: Context-Free grammar

的问候,
Ovanes

答案 15 :(得分:1)

显然,如果你逐字逐句地提出问题,几乎所有带标识符的语言都是上下文敏感的。

需要知道标识符是类型名称(类名,typedef引入的名称,typename模板参数),模板名称还是其他一些名称才能正确使用标识符。例如:

x = (name)(expression);
如果name是类型名称,则

是强制转换,如果name是函数名,则为函数调用。另一种情况是所谓的“最令人烦恼的解析”,它不可能区分变量定义和函数声明(有一条规则说它是一个函数声明)。

这种困难引入了typenametemplate与依赖名称的需求。据我所知,C ++的其余部分对上下文不敏感(即可以为它编写无上下文语法)。

答案 16 :(得分:1)

  

Meta-S“是Quinn Tyler Jackson的一个上下文敏感的解析引擎。我没有使用它,但他讲述了一个令人印象深刻的故事。请查看他在comp.compilers中的评论,并参阅rnaparse.com/MetaS% 20defined.htm - Ira Baxter 7月25日10:42

正确的链接是parsing enigines

Meta-S是一家名为Thothic的已停业公司的财产。我可以向任何感兴趣的人发送免费的Meta-S副本,我已经在rna解析研究中使用过它。请注意,示例文件夹中包含的“pseudoknot语法”是由非生物信息学,不成熟的程序员编写的,基本上不起作用。我的语法采用不同的方法,并且工作得很好。

答案 17 :(得分:0)

这里的一个大问题是,在计算机科学中,术语“无上下文”和“上下文敏感”有点不直观。对于C ++,上下文敏感性看上去很像模棱两可,但是在通常情况下并不一定是如此。

在C / ++中,仅在函数体内允许使用if语句。这似乎使它与上下文相关,对吗?好吧,不。上下文无关的语法实际上不需要该属性,您可以在其中提取一些代码行并确定其是否有效。这实际上不是上下文无关的意思。它实际上只是一个标签,含糊地暗示着与它听起来像的某种联系。

现在,如果像a * b;情况那样,根据直接语法祖先外部定义的内容(例如,标识符是描述类型还是变量)对函数体内的语句进行不同的解析,则实际上,上下文相关。这里没有实际的歧义;如果a是类型,则将其解析为指针的声明,否则将是乘法。

对上下文敏感并不一定意味着“难以解析”。实际上,C并不难,因为臭名昭著的a * b;的“歧义性”可以通过包含先前遇到的typedef的符号表来解决。它不需要任何模板实例化(已被证明是Turing Complete)就可以像C ++那样解决这种情况。即使C语言具有与C ++相同的上下文敏感性,实际上也不可能编写不会在有限时间内编译的C程序。

Python(以及其他对空格敏感的语言)也依赖于上下文,因为它需要词法分析器中的状态来生成缩进和缩进标记,但这并不比典型的LL-1语法更难解析。实际上,它使用了一个解析器生成器,这就是为什么Python包含这种无用的语法错误消息的一部分。在这里还需要注意的是,Python中没有像a * b;问题那样的“模棱两可”,它是上下文敏感语言的一个很好的具体示例,没有“模棱两可”的语法(如第一段所述)。 / p>

答案 18 :(得分:-4)

This answer says C++ is not context-free...有一个暗示(不是由回答者)它无法解析,并且答案提供了一个困难的代码示例,如果某个常量不是素数,则会产生无效的C ++程序。< / p>

正如其他人所观察到的,关于语言是否是上下文敏感/自由的问题与关于特定语法的相同问题不同。

为了设置关于可解析性的问题,我提供了经验证据,证明C ++有无上下文的语法,可以使用 为源文本的无上下文解析生成AST 事实上,用一个由显式语法驱动的现有基于GLR解析器的工具解析它。

是的,它成功地“接受了太多”;并非它接受的一切都是有效的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