彩票走势图

NLP|自然语言处理-语法解析指南:算法和技术(第3部分)

原创|使用教程|编辑:郑恭琳|2017-12-29 16:39:21.000|阅读 1376 次

概述:让我们继续在大蓝景的背景下讨论算法中的语法,从解析器、解析树、抽象语法树等开始。

# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>

相关链接:

请务必首先查看第1部分第2部分

大蓝景

语法

解析器

在解析的语境中,解析器既可以引用执行整个过程的软件,也可以引用解析器来分析词法分析器产生的tokens。这只是解析器处理整个解析过程中最重要和最困难部分的事实的结果。最重要的是,我们指的是用户最关心的事情,而且会真正看到的。实际上,正如我们所说的,词法分析器是帮助解析器工作的助手。

无论如何,解析器的输出是代码的有组织的结构——通常是一棵树。树可以是分析树或抽象语法树。它们都是树,但是它们代表实际编写的代码和解析器定义的中间元素的密切程度不同。两者之间的界限有时可能会模糊。我们将在后面的段落中看到他们的分歧。

选择树的形式是因为在不同的细节层次上处理代码是一种简单而自然的方式。例如,C#中的一个类有一个正文,这个正文由一个语句组成,block语句是一对大括号中的语句列表,依此类推……

句法与语义的正确性

解析器是编译器或解释器的基本组成部分,当然也可以是各种其他软件的一部分。例如,在本文中,我们分析了C#文件以生成图表。

解析器只能检查一段代码的语法正确性,但是编译器可以在检查同一段代码的语义有效性的过程中使用它的输出。

我们来看一个在语法上正确的代码,但是在语义上是不正确的。

int x = 10
int sum = x + y

该问题是一个变量(y)永远不会被定义,因此,如果执行,程序将会失败。然而,解析器没有办法知道这一点,因为它没有跟踪变量——它只是看代码的结构。

编译器通常会首先遍历分析树,并保留所有已定义变量的列表。然后,它再次遍历分析树,并检查所使用的变量是否都被正确定义。但在这个例子中,他们不是,它只会抛出一个错误。这是分析树也可以用来检查编译器的语义的一种方法。

无扫描解析器

无扫描解析器,或者更少见的是无词法解析器,是执行token化(即tokens中字符序列的转换)和适当解析的解析器。从理论上讲,有一个单独的词法分析器和解析器是可取的,因为它允许更清晰地分离目标和创建更多的模块化分析器。

无语法解析器对于语法分析器和解析器之间的明确区分是困难的或不必要的语言来说是更好的设计。一个例子是标记语言的解析器,其中特殊的标记被插入到文本的海洋中。它还可以方便地处理传统的文字阅读困难的语言,如C语言。这是因为无扫描解析器可以更轻松地处理复杂的符号。

解析真正的编程语言的问题

理论上讲,当代解析是为了处理真正的编程语言而设计的。在实践中,一些真正的编程语言面临着挑战。使用正常的解析生成器工具解析它们可能会更困难。

上下文相关的部分

分析工具传统上被设计为处理上下文无关的语言,但是有时候,这些语言是上下文敏感的。这可能是为了简化程序员的生活,或者仅仅是因为糟糕的设计。我记得读过一个程序员的故事,认为它可以在一个星期内为C语言生成一个解析器,但是后来发现了这么多的角落案例,一年之后,他仍然在为它工作。

上下文敏感元素的一个典型例子是软关键字,即可以在某些地方被认为是关键字的字符串,否则可以被用作标识符。

空白

空白在某些语言中起着重要的作用。最著名的例子是Python,其中语句的缩进指示它是否是某个代码块的一部分。

在大多数地方,空格是不相关的——即使在Python中,单词或关键字之间的空格也不重要。真正的问题是用于识别代码块的缩进。处理这个问题最简单的方法是检查行开头的缩进,并在合适的标记中进行转换,即当缩进从前一行改变时创建一个token。

在实践中,词法分析器中的自定义函数在缩进增大或减小时产生INDENT和DEDENT符号。这些tokens在类似C的语言中起着花括号的作用——它们表示代码块的开始和结束。

这种方法使得上下文敏感而不是上下文无关。这使解析变得复杂,你通常不想这样做,但是你必须这样做。

多个语法

另一个常见问题是处理语言实际上可能包含几个不同的语法的事实。换句话说,相同的源文件可能包含遵循不同语法的代码段。在解析的上下文中,相同的源文件包含不同的语言。最著名的例子可能是C或C ++预处理器,它实际上是一个相当复杂的语言,可以神奇地出现在任何随机的C代码中。

一个更容易处理的情况是注释,这是目前在许多当代编程语言。除此之外,它们可以用于在代码到达编译器之前对其进行处理。他们可以命令注释处理器以某种方式转换代码;例如,在执行注释之前执行特定的功能。他们更容易管理,因为他们只能出现在特定的地方。

空悬else

空悬else是链接到if-then-else语句的常见问题。由于else子句是可选的,所以一系列的if语句可能是不明确的,例如:

if one
   then if two
       then two
else ???

目前还不清楚其他人是否属于第一或第二。

公平地说,这在很大程度上是一个语言设计的问题。大多数解决方案并没有真正复杂的解析这么多,例如,当它包含else子句时,需要使用endif或要求使用块来限定if语句。

但是,也有一些语言没有提供解决方案。也就是说,它们被模糊地设计——例如,你猜对了,C。传统的方法是将else与最近的if语句相关联,这使得解析上下文敏感。

解析树和抽象语法树

有两个术语是相关的,有时它们可以互换使用:解析树和抽象语法树(AST)。从技术上讲,解析树也可以被称为具体语法树(CST),因为它应该更具体地反映输入的实际语法,至少与AST相比。

从概念上讲,它们非常相似。他们都是树型;有一个根节点代表整个源代码。根具有包含代表越来越小的代码的子树的子节点,直到单个tokens(终端)出现在树中。

不同之处在于抽象层面。一个解析树可能包含程序中出现的所有tokens,也可能包含一组中间规则。相反,AST是分析树的抛光版本,其中只保留了与理解代码有关的信息。我们将在下一节看到一个中间规则的例子。

有些信息可能在AST和分析树中都不存在。例如,评论和分组符号(即括号)通常不被表示。像注释这样的东西对程序来说是多余的,分组符号是由树的结构隐式定义的。

从分析树到抽象语法树

解析树是代码更接近具体的语法。它显示了解析器实现的许多细节。例如,通常,每个规则对应于节点的特定类型。解析树通常由用户在AST中转换,可能需要解析器生成器的帮助。通用帮助允许您在语法中注释某些规则,以便从生成的树中排除相应的节点。如果只有一个分支,那么另一个就是折叠某些节点的选项。

这是有道理的,因为解析树更容易为解析器生成,因为它是解析过程的直接表示。但是,通过程序的步骤,AST更简单,更容易处理。它们通常包括您可能想要在树上执行的所有操作:代码验证、解释、编译等。

我们来看一个简单的例子来展示一个分析树和一个AST的区别。我们先来看一个例子语法。

在这个语法中,我们可以使用符号加(+)或字符串加运算符来定义求和(sum)。想象一下,你必须解析下面的代码。这些可能是由此产生的分析树和抽象语法树。

一个分析树和抽象语法树

在AST中,特定操作员的指示消失,剩下的就是要执行的操作。特定的运算符是中间规则的一个例子。

树的图形表示

解析器的输出是一棵树,但树也可以用图形方式表示。这是为了让开发者更容易理解。一些解析生成器工具可以用DOT语言输出文件,DOT语言是用来描述图形的一种语言(树是一种特殊的图形)。然后这个文件被送到一个程序,该程序可以从这个文本描述(即)开始创建一个图形表示。

让我们看看基于前面的总和示例的DOT文本。

digraph sum {
     sum -> 10;
     sum -> 21;
}

适当的工具可以创建以下图形表示。

由graphviz创建的树的示例图像

请继续关注第4部分

本文原作者:Gabriele Tomassetti
翻译:Elyn

推荐阅读:
展望2018年:基于AI人工智能的移动应用程序开发将如何发展
开发一个聊天机器人(Chatbot)应用程序需要花费多少钱?
PS: 更多、相关视频、培训、公开课,请关注!
关于人工智能技术的最新资讯和相关开发工具推荐,请<>!

Apple加入百厂约惠

标签:算法人工智能解析器语法解析NLP自然语言处理

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn


为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP