C++模板>>编译问题举例分析

发布时间:2021-11-30 16:48:29 作者:iii
来源:亿速云 阅读:113

本篇内容主要讲解“C++模板>>编译问题举例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++模板>>编译问题举例分析”吧!

在编译理论中,通常将编译过程抽象为5个主要阶段:词法分析(Lexical  Analysis),语法分析(Parsing),语义分析(Semantic  Analysis),优化(Optimization),代码生成(Code  Generation)。这5个阶段类似Unix管道模型,上一个阶段的输出作为下一个阶段的输入。其中,词法分析是根据输入源代码文本流,分割出词,识 别类别,产生词法元素(Token)流,如:

int a = 10;

经过词法分析会得到[(Type, "int"), (Identifier, "a"), (AssignOperator, "="),  (IntLiteral,  10)],在后续的语法分析阶段,就会根据这些词法元素匹配相应的语法规则。在我学习编译原理时,教科书中对于词法分析的介绍主要是基于正则表达式的,言 下之意就是普通语言的词法规则是可以通过正则表达式描述的。比如,C语言的变量名规则是“包含字母、数字或下划线,并且以字母或下划线开头”,这就可以用 正则表达式[a-zA-Z][a-zA-Z0-9]*表达。但是,在实践中我发现不管是主流语言,还是自己设计的DSL都大量存在不能简单通过正则表达式进行词法分析的例子。来看C++98的模版例子:

map<int, vector<int>>

上面这段代码会被C++98编译器中报语法错误,原因在于它把“>>”识别成了位右移运算符而不是两个模版右括号,在C++98中必须在两个括号中间加空格,写成

map<int, vector<int> >

除此了C++模版,据我所知,经典的FORTRAN语言的语法规则更是大量存在词法歧义。

我认为从本质上讲,这类问题的根源在于词法分析的依据只是简单的词法规则,并不具备所有的语法信息,而词法歧义必须提升一层在语法规则中消除。所 以,在我自己设计一些DSL的时候干脆就把词法分析和语法分析合二为一了,相当于让语法分析在字符层次上去进行,而不是经典的词法元素层次上,这就是所谓 的Scannerless Parsing。采用这种方法的例子并不少见,TeX, Wiki, Makefile和Perl 6等语言的语法分析器都属此类。

Scannerless  Parsing方法弥补了词法规则无法消歧的问题,但是同时也破坏了词法和语法分析简单清晰的管道结构,总体上增加了实现和理解的复杂度。另外,像C++ 这样大型的语言,如果开始是有词法分析的,稍微碰到一个歧义就整个转成Scannerless  Parsing未免也显得太夸张了。这个问题困扰了我很久,直到最近才找到了一个满意的解决方案。还是以上面”>>”为例,我们知道现在 C++11已经允许不加空格了,那么C++11编译器是如何处理这个词法歧义的呢?答案是:词法分析阶段既然分析不好”>>”,干脆就不分析 了,直接把”>”  “>”交给语法分析器来分析,其他没有词法歧义的照旧。当我知道这个方案的时候不由得感叹:妙!理论上,词法分析是可以什么也不做的,全部把字符一 一交给语法分析器也没有问题,所以,干脆让词法分析只做有把握的部分,解决不了的交给语法分析器,这样就既保留了管道结构,又解决了词法歧义。

下面我们再来看看C++11规范关于这个问题的定义:

 

14.2 Names of template specializations [temp.names] ###

After name lookup (3.4) finds that a name is a template-name or that  an operator-function-id or a literal-operator-id refers to a set of  overloaded functions any member of which is a function template if this  is followed by a <, the < is always taken as the delimiter of a  template-argument-list and never as the less-than operator. When parsing  a template-argument-list, the first non-nested > is taken as the  ending delimiter rather than a greater-than operator. Similarly, the  first non-nested >> is treated as two consecutive but distinct  > tokens, the first of which is taken as the end of the  template-argument-list and completes the template-id. [ Note: The second  > token produced by this replacement rule may terminate an enclosing  template-id construct or it may be part of a different construct (e.g. a  cast).&mdash;end note ]

可见,在C++11中,词法分析器是把”>>”直接当成两个”>”传给了语法分析器,然后在语法分析中如果匹配了template- argument-lis语法,***个”>”符号会被直接认为是模版结束符,而不是大于,也不是位移符号。根据这个定义,我构造了一个例子:

template<int N> class Foo { };   Foo<3>>1> foo;

这个例子在C++98中是能正确编译的,”>>”被解释成了位移运算,但是它反而不能在C++11中编译了,因为根据规范***个”>”被解释成了模版参数结束符。如果要在C++11中编译,需要显式地加上括号:

Foo<(3>>1)> foo;

到此,相信大家对“C++模板>>编译问题举例分析”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

推荐阅读:
  1. Linux 重定向符:> ,>>, <
  2. C++编程->预编译指令小结

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

c++

上一篇:informix onbar恢复报错后onbar程序直接退出该怎么办

下一篇:C/C++ Qt TreeWidget单层树形组件怎么应用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》