Parsing 高阶函数的无歧义文法
我的语法是这样的:Parsing 高阶函数的无歧义文法,parsing,grammar,language-design,higher-order-functions,Parsing,Grammar,Language Design,Higher Order Functions,我的语法是这样的: <type> ::= <base_type> <optional_array_size> <optional_array_size> ::= "[" <INTEGER_LITERAL> "]" | "" <base_type> ::= <integer_type> | <real_type> | <function_type> <function_type&g
<type> ::= <base_type> <optional_array_size>
<optional_array_size> ::= "[" <INTEGER_LITERAL> "]" | ""
<base_type> ::= <integer_type> | <real_type> | <function_type>
<function_type> ::= "(" <params> ")" "->" <type>
<params> ::= <type> <params_tail> | ""
<params_tail> ::= "," <type> <params_tail> | ""
问题是
first(params)
包含”(“
,因为函数类型可以作为函数参数传递:((Integer)->Real,Real)->Integer
。在我修改语法之前,此语法是有效的,但现在不再有效。如何修改语法以获得所需内容?这绝对是一个挑战
为该语言编写LR语法要容易得多,尽管这仍然是一个挑战。首先,有必要消除其中的歧义
<type> ::= <base_type> <optional_array_size>
<base_type> ::= <function_type>
<function_type> ::= "(" <params> ")" "->" <type>
不幸的是,该语法是LR(2),而不是LR(1)
( Integer ) [ 42 ]
( Integer ) -> Integer
^
|
+----------------- Lookahead
在先行点,解析器仍然不知道它是在查看(冗余的)括号类型还是函数类型中的参数列表。在看到以下符号(除了上面的两个选项外,可能是输入的结尾)之前,它不会知道。在这两种情况下,它都需要将整数
减少到
,然后再减少到
。但是,在第一种情况下,它可以只移动右括号,而在第二种情况下,它需要继续减少,先减少到
,然后减少到
。这是一个移位-减少冲突。当然,它可以通过l轻松解决多看一个将来的标记,但需要看到两个将来的标记,这就是语法LR(2)的原因
幸运的是,LR(k)语法总是可以简化为LR(1)语法。(顺便说一句,LL(k)语法不是这样的。)它只是变得有点混乱,因为有必要引入一点冗余。我们这样做是通过避免减少
直到我们知道我们有一个参数列表,这意味着我们需要接受()“”“
而不提交到一个或另一个解析。这会导致以下情况,其中在
中添加了明显冗余的规则,并且
被修改为接受0或至少两个参数:
<type> ::= <atomic_type> <optional_array_size>
| <function_type>
<atomic_type> ::= <integer_type>
| <real_type>
| "(" <type> ")"
<function_type> ::= "(" <opt_params> ")" "->" <type>
| "(" <type> ")" "->" <type>
<opt_params> ::= ""
| <params2>
<params2> ::= <type> "," <type>
| <params2> "," <type>
:=
|
::=
|
| "(" ")"
::= "(" ")" "->"
| "(" ")" "->"
::= ""
|
::= ","
| ","
现在,我个人就到此为止。这里有很多LR解析器生成器,上面的语法是LALR(1),并且仍然相当容易阅读。但是,可以将其转换为LL(1)语法,需要做大量的工作。(我使用语法转换工具来做一些转换。)
直接删除左递归,然后左因子语法:
# Not LL(1)
<type> ::= <atomic_type> <opt_size>
| <function_type>
<opt_size> ::= ""
| "[" integer "]"
<atomic_type> ::= <integer_type>
| <real_type>
| "(" <type> ")"
<function_type> ::= "(" <fop>
<fop> ::= <opt_params> ")" to <type>
| <type> ")" to <type>
<opt_params> ::= ""
| <params2>
<params2> ::= <type> "," <type> <params_tail>
<params_tail> ::= "," <type> <params_tail>
| ""
#非LL(1)
::=
|
::= ""
|“[“整数”]”
::=
|
| "(" ")"
::= "("
::=”)至
|“)至
::= ""
|
::= ","
::= ","
| ""
但这还不够,因为
和
都可以以开头(“
。在参数列表的产品之间也存在类似的问题。为了解决这些问题,我们需要另一种技术:将非终端扩展到同一个非终端中,以便将冲突保留到同一个非终端中。与本例一样,这通常以一些重复为代价
通过扩展
、
和
,我们得到:
<type> ::= <integer_type> <opt_size>
| <real_type> <opt_size>
| "(" <type> ")" <opt_size>
| "(" ")" "->" <type>
| "(" <type> ")" "->" <type>
| "(" <type> "," <type> <params2> ")" "->" <type>
<opt_size> ::= ""
| "[" INTEGER_LITERAL "]"
<params2> ::= ""
| "," <type> <params2>
:=
|
| "(" ")"
| "(" ")" "->"
| "(" ")" "->"
| "(" "," ")" "->"
::= ""
|“[“整型文字”]”
::= ""
| ","
然后我们就可以留下生产要素
<type> ::= <integer_type> <opt_size>
| <real_type> <opt_size>
| "(" <fop>
<fop> ::= <type> <ftype>
| ")" "->" <type>
<ftype> ::= ") <fcp>
| "," <type> <params2> ")" "->" <type>
<fcp> ::= <opt_size>
| "->" <type>
<opt_size> ::= ""
| "[" INTEGER_LITERAL "]"
<params2> ::= ""
| "," <type> <params2>
:=
|
| "("
::=
| ")" "->"
::= ")
| "," ")" "->"
::=
| "->"
::= ""
|“[“整型文字”]”
::= ""
| ","
这就是LL(1)。我将把它作为一个练习,将所有适当的操作重新附加到这些产品上。这绝对是一个挑战 为该语言编写LR语法要容易得多,尽管这仍然是一个挑战。首先,有必要消除其中的歧义
<type> ::= <base_type> <optional_array_size>
<base_type> ::= <function_type>
<function_type> ::= "(" <params> ")" "->" <type>
不幸的是,该语法是LR(2),而不是LR(1)
( Integer ) [ 42 ]
( Integer ) -> Integer
^
|
+----------------- Lookahead
在先行点,解析器仍然不知道它是在查看(冗余的)括号类型还是函数类型中的参数列表。在看到以下符号(除了上面的两个选项外,可能是输入的结尾)之前,它不会知道。在这两种情况下,它都需要将整数
减少到
,然后再减少到
。但是,在第一种情况下,它可以只移动右括号,而在第二种情况下,它需要继续减少,先减少到
,然后减少到
。这是一个移位-减少冲突。当然,它可以通过l轻松解决多看一个将来的标记,但需要看到两个将来的标记,这就是语法LR(2)的原因
幸运的是,LR(k)语法总是可以简化为LR(1)语法。(顺便说一句,LL(k)语法不是这样的。)它只是变得有点混乱,因为有必要引入一点冗余。我们这样做是通过避免减少
直到我们知道我们有一个参数列表,这意味着我们需要接受”(“”)“
而不提交一个或另一个分析。这导致了以下情况,其中向
添加了明显冗余的规则,并且
被修改为接受0或至少两个参数:
<type> ::= <atomic_type> <optional_array_size>
| <function_type>
<atomic_type> ::= <integer_type>
| <real_type>
| "(" <type> ")"
<function_type> ::= "(" <opt_params> ")" "->" <type>
| "(" <type> ")" "->" <type>
<opt_params> ::= ""
| <params2>
<params2> ::= <type> "," <type>
| <params2> "," <type>
:=
|
::=
|
| "(" ")"
::= "(" ")" "->"
| "(" ")" "->"
::= ""
|
::= ","
| ","