我目前正在为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
指定。
我正在编写一个手写词法器,以将我的输入转换成令牌列表。我将如何标记抽象终端?
答案 0 :(得分:0)
经典方法是为每个可能的终端编写一个正则表达式(或其他识别器)。
您所说的“抽象”终端,实际上是非常具体的终端,其关联的模式可以识别多个可能的输入字符串。实际识别的字符串(或该字符串的某些计算函数)应作为令牌的语义值传递给解析器。
名义上,在输入字符串的每个点上,令牌生成器将运行所有识别器,并选择匹配时间最长的识别器。 (这是所谓的“最大嚼数”规则。)通常可以对其进行优化,特别是在所有模式都是正则表达式的情况下。例如,(F)lex将为您进行优化。
您的情况的复杂之处在于,语言的标记化取决于上下文。特别是,当目标是elem_or_data
时,唯一可能的标记是<
,</
和“数据”。但是,在标签内部,“数据”是不可能的,“名称”和“字符串”标签是可能的(以及其他)。
属性的值也可能具有与键相同的词法形式(即名称)。在XML本身中,属性值必须是带引号的字符串,并且使用未带引号的字符串将被标记为错误,但是肯定有“类似于XML”的语言(例如HTML)可以在其中插入不带空格的属性值未引用。
由于词法分析取决于上下文,因此必须将词法分析器传递(或访问)定义词法上下文的其他信息。通常将其表示为单个枚举值,可以根据返回的最后几个标记或基于当前解析器堆栈的FIRST集来计算。