在学习一些项目源代码时,看到了大量的#line定义,小人不才,语法搜搜是大概懂了,可问个为什么,却难道了自己。
#line是C语言预处理器,语法格式为:
#line number “filename”
如 #line 123 “file.c”
意思就是改变__LINE__和__FILE__宏内容。
当在程序中使用这两个宏的时候,就会因为#line的定义而改变,例子很简单,我就不列举了,不明白的朋友可以自己试试,加入#line后,打印这两个宏的内容。
这两个宏是永久被改变的,会影响当前的c文件一直到文件末尾。
回到原来的项目源代码中,源代码部分片段:
#line 357 "..\gram\sprt.y"
{
yyval.node = alloc_tree_cell(LNB, yyvsp[-3].str);
yyval.node->type = NODE_ARRAY_EL;
yyval.node->link[0] = yyvsp[-1].node;
;
break;}
case 72:
#line 366 "..\gram\sprt.y"
{ yyval.node = alloc_expr_cell(LNB, EXPR_INCR, NULL, yyvsp[0].node); ;
break;}
case 73:
#line 367 "..\gram\sprt.y"
{yyval.node = alloc_expr_cell(LNB, EXPR_DECR, NULL, yyvsp[0].node); ;
break;}
源程序中,有大量这种代码,和#line,在没查资料前,我一直以为#line是链接到外部文件的一种用法,后来才发现,这种做法仅仅是为了满足调试需要,并且,发布产品时,完全可以全部删除。
在继续阅读并搜罗资料后才得知,这是一组叫做语法解析器生成的代码,OK,看到这里,我就明白了很多了。
首先,#line是改变__LINE__和__FILE__宏的,这两个宏通常用来调试定位问题。
在平常项目开发中,可能用到的不多,甚至是根本不需要,因为我尝试了很多种方法,如宏,函数,动态库等方式,来探讨#line的意义所在,都没能找到原因,后来知晓了分析器后,才得知。
首先介绍两个程序,一个是Flex,一个是Bison。
Flex是词法分析器,它可以根据用户的输入,依据一定的规则(Flex语法)将输入拆分成各个有效片段。
Bison是语法分析器,它可以根据用户的输入,依据一定的规则(Bison语法)将输入的一组文本分析成语法树,并解释执行。
业界人士,通常用Flex和Bison共同来开发语法解释器,例如Nessus的攻击脚本,Unity3D的Action脚本等。
大致了解了Flex和Bison后,进行了一些实践,#line在这里面就显得有为重要了,它可以帮助你处理编译链接时的错误定位,因为你可能写了一个语法哪怕是%{ }%,都会生成上千行的代码。
什么时候使用#line,我思考后总结了一下:
其一,当你给用户提供一些脚本支持,语法解释等工具集时,需要这种#line来帮助用户定位问题。
其二,当你给用户提供一系列API或SDK时,当用户在使用API时,可能需要#line来帮助用户定位问题。
其三,#line不仅仅能改变__LINE__,__FILE__宏,它可以在用户对代码进行编译链接时,显示到错误列表中。
虽然在实际的开发中,基本不用到,但是相对了解下,说不定哪一天需要用Flex和Bison开发属于自己的脚本语言。
小提示:这是语法分析器,如果有兴趣开发语言的朋友们,关于语法高亮,可以使用 Scintilla,它也是开源项目,可以自定义语法高亮,智能提示,Notepad++就是用它做的,关于它的用法以后有机会给大家介绍。