用LL语法标记抽象终端

时间:2019-02-18 11:06:21

标签: parsing lexer bnf ll recursive-descent

我目前正在为XML风格编写基本的解析器。作为练习,我将实现一个LL表驱动的解析器。

这是我的BNF语法示例:

%token name data string

%% /* LL(1) */

doc          :  elem

elem         :  "<" open_tag

open_tag     :  name attr close_tag

close_tag    :  ">" elem_or_data "</" name ">"
             |  "/>"
             ;

elem_or_data :  "<" open_tag elem_or_data
             |  data elem_or_data
             |  /* epsilon */
             ;

attr         :   name ":" string attr
             |  /* epsilon */
             ;

此语法正确吗?

每个终端文字都在引号之间。抽象终端由%token指定。

我正在编写一个手写词法器,以将我的输入转换成令牌列表。我将如何标记抽象终端?

1 个答案:

答案 0 :(得分:0)

经典方法是为每个可能的终端编写一个正则表达式(或其他识别器)。

您所说的“抽象”终端,实际上是非常具体的终端,其关联的模式可以识别多个可能的输入字符串。实际识别的字符串(或该字符串的某些计算函数)应作为令牌的语义值传递给解析器。

名义上,在输入字符串的每个点上,令牌生成器将运行所有识别器,并选择匹配时间最长的识别器。 (这是所谓的“最大嚼数”规则。)通常可以对其进行优化,特别是在所有模式都是正则表达式的情况下。例如,(F)lex将为您进行优化。

您的情况的复杂之处在于,语言的标记化取决于上下文。特别是,当目标是elem_or_data时,唯一可能的标记是<</和“数据”。但是,在标签内部,“数据”是不可能的,“名称”和“字符串”标签是可能的(以及其他)。

属性的值也可能具有与键相同的词法形式(即名称)。在XML本身中,属性值必须是带引号的字符串,并且使用未带引号的字符串将被标记为错误,但是肯定有“类似于XML”的语言(例如HTML)可以在其中插入不带空格的属性值未引用。

由于词法分析取决于上下文,因此必须将词法分析器传递(或访问)定义词法上下文的其他信息。通常将其表示为单个枚举值,可以根据返回的最后几个标记或基于当前解析器堆栈的FIRST集来计算。