C ++是上下文无关的还是上下文相关的?


405

我经常听到有人声称C ++是上下文相关的语言。请看以下示例:

a b(c);

这是变量定义还是函数声明?这取决于符号的含义c。如果c变量,则a b(c);定义一个名为btype 的变量a。直接用初始化c。但如果c类型,则a b(c);声明一个名为的函数b,该函数采用a c并返回a a

如果您查看无上下文语言的定义,它将基本上告诉您所有语法规则的左手边必须仅由一个非终结符组成。另一方面,上下文相关的语法允许在左侧使用任意字符串的终止符和非终止符。

浏览“ C ++编程语言”的附录A,我找不到一个单独的语法规则,该规则除左侧有一个非终结符外还没有其他内容。这意味着C ++是无上下文的。(当然,每种上下文无关的语言也是上下文敏感的,因为上下文无关的语言构成了上下文敏感语言的子集,但这并不是重点。)

那么,C ++是上下文无关的还是上下文相关的?


12
@CarlNorum请向我展示C ++的单个语法规则,该规则在其左侧不包含单个非终止符号,我将立即相信您。
fredoverflow 2013年

9
IIUC取决于您对上下文敏感程度的界线。我想我已经看到人们认为几乎所有静态类型的编程语言都是上下文相关的,这不是因为您不能使用CFG解析工具为其构建实用的编译器,而是因为此类实现会通过解析某些无效程序和仅在类型检查期间拒绝它们。因此,如果您认为类型错误的程序不是解析器应接受的语言(从CS的意义上说,即一组字符串),则比C ++更多的语言是上下文相关的。

6
@DeadMG:不,你错了。形式语言理论中根本没有“解析”或“语义学”,只有“语言”是一组字符串。
jpalecek

27
到目前为止,还没有任何答案可以解决您对“无上下文语法”的定义。在我看来,对这个问题的正确答案要么引用附录A中的产品,要么不符合您的定义,或者表明您的定义不正确或不足。坚守阵地!
Lightness Races in Orbit

8
看到D的语法真的没有上下文吗?。实际上,我认为这里的每个人都应该阅读该问题及其答案!
Lightness Races in Orbit

Answers:


341

以下是我(当前)最喜欢的演示,说明为什么解析C ++(可能)是图灵完备的,因为它显示了仅在给定整数为质数时在语法上正确的程序。

所以我断言C ++既不是上下文无关的,也不是上下文敏感的

如果在任何产生式的两侧都允许任意符号序列,则会在Chomsky层次结构中产生Type-0语法(“无限制”),它比上下文相关语法更强大;无限制的语法是图灵完备的。上下文相关(Type-1)语法允许在产品的左侧显示多个上下文符号,但是同一上下文必须出现在产品的右侧(因此,名称为“上下文相关”)。[1]上下文相关文法等效于线性图灵机

在示例程序中,素数计算可以由线性边界的Turing机器执行,因此它并不能完全证明Turing等价,但是重要的部分是解析器需要执行计算才能执行语法分析。可以将任何计算形式表示为模板实例化,并且有充分理由相信C ++模板实例化是图灵完备的。例如,参见Todd L. Veldhuizen在2003年发表的论文

无论如何,C ++可以由计算机解析,因此可以肯定地可以由Turing机器进行解析。因此,无限制的语法可以识别它。实际上编写这样的语法是不切实际的,这就是为什么标准不尝试这样做的原因。(见下文。)

某些表达方式“含糊不清”的问题主要是一个红色鲱鱼。首先,歧义是特定语法的特征,而不是语言。即使一种语言可以被证明没有明确的语法,即使可以被上下文无关的语法识别,它也是上下文无关的。同样,如果不能由上下文无关的语法识别它,但是可以由上下文敏感的语法识别,则它是上下文敏感的。歧义无关紧要。

但是无论如何,例如第21行(即该语言不是上下文无关的。该语言可以使用上下文相关的语法,并且在该问题的答案中提供了Type-0语法:https:// math .stackexchange.com / questions / 163830 / context-sensitive-grammar-for-the-copy-languageauto b = foo<IsPrime<234799>>::typen<1>();下面程序中的),这些表达式一点也不模糊。它们只是根据上下文进行不同的解析。在这个问题的最简单表达中,某些标识符的句法类别取决于如何声明它们(例如,类型和函数),这意味着形式语言将不得不认识到以下事实:相同的程序是相同的(声明和使用)。这可以通过“复制”语法来建模,该语法是识别同一单词的两个连续精确副本的语法。抽水引理很容易证明

如果要尝试编写一种上下文相关(或不受限制)的语法来解析C ++,则很有可能会在文本中添加一些文字。编写图灵机来解析C ++将同样是不可能的。即使编写C ++程序也很困难,据我所知,没有一个被证明是正确的。这就是为什么该标准不尝试提供完整的正式语法的原因,并且为什么它选择用技术英语编写一些解析规则。

在C ++标准中看起来像形式语法的东西不是C ++语言语法的完整形式定义。预处理后甚至还不是语言的完整正式定义,这可能更易于形式化。(不过,这不是语言。标准定义的C ++语言包括预处理器,并且预处理器的操作是通过算法描述的,因为在任何语法形式上都很难描述。描述词汇分解的标准,包括必须多次应用的规则。)

附录A中收集了各种语法(用于语法分析的两种重叠语法,一种发生在预处理之前,另一种发生在必要时,然后再加上“语法”语法),并带有此重要说明(强调)。

C ++语法的摘要旨在帮助理解。这不是该语言的确切陈述。特别是,此处描述的语法接受有效C ++结构超集。必须应用消歧规则(6.8、7.1、10.2)将表达式与声明区分开。此外,必须使用访问控制,歧义和类型规则来清除语法上有效但毫无意义的构造。

最后,这是承诺的程序。当且仅当N in IsPrime<N>为质数时,第21行在语法上正确。否则,typen是一个整数,而不是一个模板,因此typen<1>()被解析为(typen<1)>()语法上不正确的,因为()它不是语法上有效的表达式。

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

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

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

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

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

[1]从技术上讲,上下文敏感语法中的每个产品都必须具有以下形式:

αAβ → αγβ

其中A,是非终结符和αβ可能是语法符号的空序列,并且γ是非空序列。(语法符号可以是终端,也可以是非终端)。

A → γ只能在上下文中阅读[α, β]。无上下文(类型2)语法,α并且β必须为空。

事实证明,您还可以使用“单调”限制来限制语法,其中每个产品必须采用以下形式:

α → β其中|α| ≥ |β| > 0  (|α|表示“的长度α”)

可以证明单调语法可以识别的语言集与上下文敏感语法可以识别的语言集完全相同,并且通常情况下,更容易将证明基于单调语法。因此,看到“上下文敏感”似乎意味着“单调”是很常见的。


27
因此,它不仅对上下文敏感,而且可以依赖于您可以在模板中表达的任何上下文,这些模板是图灵完备的。
2013年

7
@ mehrdad,OP表示“上下文敏感的语言”,而不是上下文敏感的语法。歧义是语法的特征,而不是语言的特征。该语言确实是上下文相关的,但不是因为它的特定语法是模棱两可的。
rici

2
请注意,我的示例并不明确。这是有效程序的明确表达。如果您在第21行中更改该值,则它可能格式错误。但是在任何情况下都不是模棱两可的。
rici

5
我有一个疑问:如您所示,模板评估的结果可能会导致格式正确和格式错误的程序有所不同。模板评估已完成。因此,不能正确确定字符串是否为语言(C ++)是否需要图灵完整性?就像您说的那样,上下文相关的语言“只是”一种“线性有界自动机”,它不是图灵完整的AFAIK。还是您的论点是利用C ++标准对某些方面的限制,包括模板评估深度?

4
@AntonGolov:我原来的那个例子版本就是这样做的(你可以通过把实现它0的内部(),一个简单的一个),但我认为这是更有趣的方式,因为它证明了你需要的模板实例,即使认识到,如果字符串是语法正确的C ++程序。如果两个分支都编译,那么我将不得不更加努力地争辩这种差异是“语义”的论点。奇怪的是,尽管我经常面临定义“句法”的挑战,但是除了“我认为不是语法的东西”之外,没有人提供过“语义”的定义:)
rici

115

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

但是,该语法不能精确地描述C ++语言,因为它会产生非C ++程序,例如

int m() { m++; }

要么

typedef static int int;

定义为“格式良好的C ++程序集”的C ++语言不是上下文无关的(有可能表明,仅需要声明变量就可以做到这一点)。从理论上讲,您可以在模板中编写图灵完备的程序,并根据其结果使程序变形,因此它甚至与上下文无关。

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

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

标准后面的语法不满足这些类别(即,模棱两可,不是LL(k)...),因此C ++语法对它们而言“不是上下文无关的”。从某种意义上说,他们是对的,要产生一个有效的C ++解析器非常困难。

请注意,此处使用的属性仅与上下文无关的语言弱连接-歧义与上下文敏感度无关(实际上,上下文敏感的规则通常有助于消除生产歧义),其他两个仅仅是上下文的子集-免费语言。而且,解析上下文无关的语言不是线性过程(尽管解析确定性语言是)。


7
ambiguity doesn't have anything to do with context-sensitivity这也是我的直觉,所以我很高兴看到有人(a)同意,并且(b)在我无法解释的地方进行解释。我认为它取消了所有基于的论点的资格a b(c);,并部分满足了最初的问题,即前提是上下文模糊的语境是“经常听到的”主张,这是由于歧义而引起的……尤其是当语法实际上甚至在歧义中也不存在歧义时MVP。
Lightness Races in Orbit

6
@KonradRudolph:标准所说的是:“有一个实现定义的数量,它指定了递归实例化的总深度限制,可能涉及多个模板。实例化中无限递归的结果是不确定的。” (14.7.1p15)我的解释是,不需要理解每个有效的c ++程序的实现,也不意味着递归深度太大的程序是无效的。唯一具有无效递归深度的标记为无效的。
rici

3
@KonradRudolph:我认为这是“一般参考”。我读过的事实那篇相当复杂的文章,但对它的理解不足以说明这个小事实,这一事实足以证明这一点。这并不是说“计算机通常用电”或“位可以是真是假”之类的话。
Lightness Races in Orbit

3
如果这个事实确实广为人知,我认为找到一个参考这个参考要比争论是否应提供一个参考要容易得多。更不用说建设性的了。
塞缪尔·埃德温·沃德

5
据我所知,@ Konrad说“上下文敏感等同于图灵完成”时弄错了。(至少,如果他用“转向完成”来表示“递归可枚举”,那是他),此后一直无法识别此错误。这是此处涉及的适当集合包含关系的参考:en.wikipedia.org/wiki/Chomsky_hierarchy
pnkfelix 2013年

61

是。以下表达式根据类型解析的上下文具有不同的操作顺序

编辑:当实际的操作顺序发生变化时,将很难使用“常规”编译器来解析未经修饰的AST,然后再对其进行修饰(传播类型信息)。与此相比,提到的其他上下文相关的东西“相当容易”(并不是说模板评估一点都不容易)。

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

其次是:

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

通过记住范围内的类型定义,为什么不能像C那样解决该问题?
Blaisorblade 2012年

1
@Blaisorblade:使编译器“干净”的一种方法是将任务分成链中的独立步骤,例如从输入创建一个分析树,然后再执行一个进行类型分析的步骤。C ++迫使您要么1)将这些步骤合并为一个,要么2)根据两种/所有可能的解释来解析文档,并允许类型解析阶段将其范围缩小为正确的解释。
Sam Harwell 2012年

@ 280Z28:同意,但是C也是如此。我认为这个问题的好答案应该表明C ++为什么比C更差。此处链接的博士学位论文做到了:stackoverflow.com/a/243447/53974
Blaisorblade 2012年

26

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

  1. 几乎每种编程语言的语法都与上下文无关。通常,它以扩展的Backus-Naur形式或无上下文语法的形式给出。

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

总之,C ++是否不依赖上下文取决于您提出的问题。


5
有趣的是,为了获得编程语言的CFG,通常必须将“纯粹的语法”级别降低到低于预期的水平。以C为例。您可能会认为C中的简单变量声明的语法规则为VARDECL : TYPENAME IDENTIFIER,但您不能拥有该规则,因为您无法在CF级别将类型名与其他标识符区分开。另一个示例:在CF级别,您无法决定将其解析a*b为变量声明(b类型为的指针a)还是乘法。
LaC

2
@LaC:是的,谢谢你指出这一点!顺便说一下,我敢肯定,对于单纯的语法,还有一个更常用的技术术语。有没有人正确的术语?
2013年

4
@丹:您在说的是某种与上下文无关的语法给出的近似语言。当然,根据定义,这种近似是无密码文本的。这就是在讨论编程语言时经常使用“语法”的意义。
reinierpost

13

您可能想看一下Bjarne Stroustrup撰写的The Design&Evolution of C ++。在其中,他描述了尝试使用yacc(或类似方法)解析早期版本的C ++时遇到的问题,并希望他使用了递归下降。


哇谢谢。我想知道考虑使用比CFG更强大的功能来解析任何人工语言是否真的有意义。
Dervin Thunk

理解C ++为什么的好书。我建议使用Lippman的Inside the C ++ Object Model,以了解C ++的工作原理。尽管两者都有些过时,但它们仍然是不错的读物。
马特·普赖斯2009年

“ Meta-S”是Quinn Tyler Jackson的上下文相关的解析引擎。我没有用过,但是他讲了一个令人印象深刻的故事。在comp.compilers中查看他的评论,并查看rnaparse.com/MetaS%20defined.htm
Ira Baxter,2009年

@IraBaxter:您的x-ref今天是MIA,并且对该软件的扎实引用似乎难以捉摸(Google搜索无法提供“ site:rnaparse.com meta-s”或“ quinn jackson meta- s';虽然有些零碎,但例如meta-s.com会导致网站内容不完整。
乔纳森·莱夫勒

@乔纳森:已经有一段时间了,只是注意到您的投诉。邓诺(Dunno)为什么链接不好,我在写的时候就觉得很好。奎因曾经在comp.compilers中非常活跃。Google似乎越来越脆弱,这就是我所能找到的:groups.google.com/group/comp.compilers/browse_thread/thread/…IIRC ,他已将MetaS的权利签署给了夏威夷的一些公司以进行再营销。鉴于这在技术上是多么奇怪,恕我直言,这是在签署其死刑令。听起来很聪明。
艾拉·巴克斯特

12

是的,C ++是上下文相关的,非常上下文相关。您不能通过使用上下文无关的解析器来简单地解析文件来构建语法树,因为在某些情况下,您需要从先验知识中了解符号来进行决策(即在解析时构建符号表)。

第一个例子:

A*B;

这是一个乘法表达式吗?

要么

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

如果A是变量,则为表达式,如果A为类型,则为指针声明。

第二个例子:

A B(bar);

这是带有bar类型实参的函数原型吗?

要么

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

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

第三个例子:

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

这是在解析时建立符号表无济于事的情况,因为x和y的声明位于函数定义之后。因此,您需要首先浏览类定义,然后第二遍查看方法定义,以告诉x * y是一个表达式,而不是指针声明或其他内容。


1
A B();即使在函数定义中也是函数声明。寻找最烦人的解析...
AProgrammer 2012年

“您不能仅通过分析文件FALSE来构建语法树。看我的答案。
艾拉·巴克斯特

10

C ++使用GLR解析器进行解析。这意味着在解析源代码期间,解析器可能会遇到歧义,但应该继续并决定以后要使用哪种语法规则。

也看

为什么C ++无法使用LR(1)解析器进行解析?


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

int x;
x = 9 + 1.0;

不能使用上下文无关的语法描述以下规则: 分配的右侧应与左侧相同。


4
大多数C ++解析器不使用GLR解析技术。GCC没有。有的。请参阅语义设计s.com/Products/FrontEnds/CppFrontEnd.html。
Ira Baxter,2009年

10

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

这里也要问: 上下文敏感性vs歧义

这是上下文无关的语法:

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

它是模棱两可的,因此要解析输入“ x”,您需要一些上下文(或者承受歧义,或者发出“警告:E8271-输入在第115行中模棱两可”)。但这当然不是上下文相关的语法。


在产品的左侧具有多个符号如何解决此问题?我认为这个答案不能回答问题。
user541686

1
我的回答是对第一句话的回答:“我经常听到有人声称C ++是上下文相关的语言。” 如果这些声明非正式地使用“上下文相关”表达,那么就没有问题。我不认为C ++在形式上对上下文敏感。
Omri Barel 2013年

我认为C ++ 形式上上下文敏感的,但是我遇到的问题是我不了解上下文敏感的语法在解析C ++方面比在CFG方面会更成功。
user541686

6

没有哪种类似Algol的语言是上下文无关的,因为它们具有规则来限制可根据标识符的类型出现的表达式和语句,并且因为在声明和使用之间可以出现的语句数量没有限制。

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

由于其图灵完备的模板系统,C ++远远超出了此范围。请参阅堆栈溢出问题794015




5

它具有上下文敏感性,因为它a b(c);具有两个有效的解析器-声明和变量。当您说“ If cis a type”时,就在上下文中,并且您已经准确地描述了C ++对它的敏感程度。如果您没有“什么是c?”的您无法明确地对此进行解析。

在这里,上下文以令牌的选择表示-解析器读取一个标识符,如果它为类型命名,则作为类型名令牌。这是最简单的解决方案,并且避免了上下文相关的大部分复杂性(在这种情况下)。

编辑:当然,还有更多的上下文敏感性问题,我只关注您所展示的问题。模板对此尤其讨厌。


1
a<b<c>>d可以吧 (您的示例实际上是C的经典作品,它是唯一不受上下文限制的
示例

我认为这更多是一个词汇问题。但是肯定是同一类,是的。
2013年

2
发问者没有问它与C相比对上下文敏感,只是为了表明它与上下文有关。
小狗

所以.. C ++更上下文敏感的不是C?
Kerrek SB 2013年

2
@DeadMG我不认为您正在回答这个问题(我也不是)。产品左侧的端子如何解决此问题?
user541686

5

C ++标准中的产品是在没有上下文的情况下编写的,但是众所周知,实际上并没有精确定义该语言。大多数人认为当前语言中的歧义可以通过上下文相关的语法得到明确解决。

对于最明显的示例,让我们考虑“最令人烦恼的解析”:int f(X);。如果X为,则将其定义f为将使用初始化的变量X。如果X为type,则将其定义f为采用type的单个参数的函数X

从语法角度来看,我们可以这样看:

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

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

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

当然,要完全正确,我们需要添加一些额外的“填充”,以解决其他类型的声明介入的可能性(即,A和B都应该是“包括将X声明为...的声明”)。 ,或该订单上的某项)。

但是,这与典型的CSG还是有很大不同的(或者至少我记得它们)。这取决于所构建的符号表-具体识别X为类型或值的部分,不仅是此类型或值之前的某种类型的语句,还包括正确的符号/标识符的正确语句类型。

因此,我必须做些确定的事情,但是我的直接猜测是,这至少在正常使用的情况下并不能真正成为CSG。


(无上下文)产品定义了最复杂的解析,因此可以由上下文无关的解析引擎进行解析。这延迟了确定多个解释中哪个解释才有效的问题,直到解析完成之后为止,但这只是使解析器和名称解析器的工程更加容易,因为它们是模块化的,而不是像传统的C ++解析器那样复杂。见AST的最棘手的解析:stackoverflow.com/questions/17388771/...
艾拉巴克斯特

5

非上下文无关语法的最简单情况是解析包含模板的表达式。

a<b<c>()

这可以解析为

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

要么

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

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


我相信C ++ 11要求使用后一种解释,因此您必须添加括号以选择加入前一种。
约瑟夫·加文

1
@JosephGarvin,不。<如果可能的话,C ++要求必须放在方括号中(例如,它遵循一个命名为模板的标识符)。C ++ 11增加了一个要求,即如果合理使用>,则将第一个字符>>解释为右括号。这会影响对模板a<b>c>位置的解析,a但对无效a<b<c>
rici

@aaron:那比a();expr.callexpr.type.conv)简单吗?
rici

@rici:糟糕,我没有意识到这是不对称的。
约瑟夫·加文

5
您是在描述歧义,还是上下文敏感?
corazza 2014年

4

C ++模板已被证明具有强大的图灵能力。尽管不是正式参考,但这里是一个可以考虑的地方:

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

我会大胆猜测(就像一个民俗而简洁的CACM证明,表明CFG不能代表60年代的ALGOL),因此我只能说只有CFG才能正确解析C ++。CFG与树木通过或减少事件期间的各种TP机制结合使用-这是另一回事了。在一般意义上,由于停止问题,存在一些C ++程序,这些程序无法显示为正确/不正确,但是仍然正确/不正确。

{PS-作为Meta-S的作者(上面有几个人提到)-我可以肯定地说,Thothic既不存在,也没有免费提供的软件。也许我的措辞是这个版本的,这样我才不会被删除或被否决为-3。}


3

C ++不是上下文无关的。我前一段时间在编译器讲座中学到的。快速搜索给出了此链接,其中“语法或语义”部分说明了为什么C和C ++不是上下文无关的:

维基百科谈话:无上下文语法

问候,
Ovanes


2

显然,如果您逐字回答问题,几乎所有带有标识符的语言都是上下文相关的。

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

x = (name)(expression);

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

这种困难导致需要使用依赖名称typename并需要template使用依赖名称。就我所知,其余C ++对上下文不敏感(即可以为它编写上下文无关的语法)。


2

“ Meta-S”是奎因·泰勒·杰克逊(Quinn Tyler Jackson)的上下文相关的解析引擎。我没有使用过它,但是他讲的故事令人印象深刻。 –艾拉·巴克斯特7月25日10:42

正确的链接是解析引擎

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


这实际上是一个有趣的发现。
Dervin Thunk

0

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

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

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

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

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


-4

这个答案说C ++不是上下文无关的……暗示(不是应答者)它不能被解析,并且答案提供了一个困难的代码示例,如果某个常量不是一个常数,它将生成一个无效的C ++程序。质数。

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

为了解决有关可解析性的问题,我提供了经验证据,表明存在C ++的无上下文语法,实际上可以通过使用现有的GLR对其进行解析,从而可以使用AST来为源文本的无上下文解析生成AST。 -基于解析器的工具,由显式语法驱动。

是的,它通过“接受太多”而成功;并非它接受的所有内容都是有效的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

确定它是变量声明还是乘法不是类型检查功能。我也不得不擦洗你对这种自我宣传的回答……。
小狗

@Puppy:您可以说自己喜欢的东西,但这就是该工具的工作方式。删除工具名称可能只会使人们问什么是工具名称。
艾拉·巴克斯特

该工具的工作方式是否无关紧要,因为问题并不要求该工具可以工作。另外,我认为我们可以放心等待实际发生。
小狗
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.