gpt4 book ai didi

javascript - 在保持左结合性的同时避免左递归解析 Lambda 微积分

转载 作者:行者123 更新时间:2023-11-30 06:23:12 29 4
gpt4 key购买 nike

我正在尝试利用 JavaScript 和 PEG.JS 将 lambda 演算项解析为 AST。语法相当简单:

/*****************************************************************
t ::=
x variable
λx.t abstraction
t t application
*****************************************************************/

我从中编码出了 PEG:

TERM "term"
= ABSTRACTION
/ APPLICATION
/ VARIABLE

APPLICATION "application"
/*****************************************************************
application ::= t t
*****************************************************************/
= APPLICATION_W_PARENS
/ APPLICATION_WO_PARENS

ABSTRACTION "abstraction"
/*****************************************************************
abstraction ::= λx.t
*****************************************************************/
= ABSTRACTION_W_PARENS
/ ABSTRACTION_WO_PARENS

VARIABLE "variable"
/*****************************************************************
variable ::= x
*****************************************************************/
= x:CHARACTER
{
return Variable(location(), x)
}

//////////////////////////////////////////////////////////////////////
// Application
//////////////////////////////////////////////////////////////////////

ABSTRACTION_OR_VARIABLE
//////////////////////////////////////////////////////////////////
// "Left recursive grammar" workaround "term term" enters a loop
// assuming the left side cannot match Application
// remediates the left recursion issue
//////////////////////////////////////////////////////////////////
= ABSTRACTION / VARIABLE

APPLICATION_W_PARENS
/*****************************************************************
'(' -> Abstraction | Variable -> Term -> ')'
*****************************************************************/
= L_PARENS lhs:ABSTRACTION_OR_VARIABLE rhs:TERM R_PARENS
{
return Application(location(), lhs, rhs, true)
}

APPLICATION_WO_PARENS
/*****************************************************************
Abstraction | Variable -> Term
*****************************************************************/
= lhs:ABSTRACTION_OR_VARIABLE rhs:TERM
{
return Application(location(), lhs, rhs, false)
}

//////////////////////////////////////////////////////////////////////
// Abstraction
//////////////////////////////////////////////////////////////////////

ABSTRACTION_W_PARENS "abstraction"
/*****************************************************************
'(' -> 'λ' -> Variable -> '.' -> TERM -> ')'
*****************************************************************/
= L_PARENS LAMBDA x:CHARACTER DOT term:TERM R_PARENS
{
return Abstraction(location(), x, term, true)
}

ABSTRACTION_WO_PARENS
/*****************************************************************
'λ' -> Variable -> '.' -> Term
*****************************************************************/
= LAMBDA x:CHARACTER DOT term:TERM
{
return Abstraction(location(), x, term, false)
}

//////////////////////////////////////////////////////////////////////
// Atoms
//////////////////////////////////////////////////////////////////////

LAMBDA "lambda"
= 'λ'

L_PARENS "lParens"
= '('

R_PARENS "rParens"
= ')'

DOT "dot"
= [\.]

CHARACTER "character"
= [A-Za-z]
{
return text().trim() ;
}

这在简单的输入上编译和运行良好。当我开始通过示例来测试实现时,我发现了一些问题。给定术语

λl.λm.λn.lmn

它解析成

{
"expr": "λl.λm.λn.lmn",
"ast": " Abstraction( l, Abstraction( m, Abstraction( n, Application( Variable( l ), Application( Variable( m ), Variable( n ) ) ) ) ) )"
}

问题出在左应用 m 应应用于 l,然后 n 应用于该结果。从 AST 的打印输出中可以看出,n 应用于 m,结果应用于 l,这是不正确的。

如果我更改现有规则以防止左递归问题,其中应用程序假定左侧只是一个变量或抽象以包含应用程序的可能性 - 那么就会出现递归问题。

我介绍了 parens 的概念 - 但我停止将它们整合进去。我真的不希望它们出现在语法中。

  1. 我们可以在 PEG.JS 中解决这个问题吗?
  2. 或者我应该重写应用程序对象的构造(hack)吗?
  3. 或者是否有更好的方法来解析它 - 例如滚动自定义解析器?

最佳答案

有缺陷的方法:我试过的一种方法是强制匹配两个以上的变量 |连续抽象并向左应用它们

APP_2
= lhs:ABSTRACTION_OR_VARIABLE rhs:ABSTRACTION_OR_VARIABLE
{
return Application(location(), lhs, rhs, false, "APP2")
}

APP_3
= lhs:APP_2 rhs:TERM
{
return Application(location(), lhs, rhs, false, "APP3")
}

APPLICATION_WO_PARENS
= APP_3
/ APP_2

当应用程序包含三个术语时,这看起来很有效。当有四个时,我们得到一棵 2 层的平衡树,而我们想要一棵三层的不平衡树……所以这是前一个 PEG 的错误输出(输入为 lmno):

{
"expr": "lmno",
"ast": "Application::APP3(
Application::APP2( Variable(l), Variable(m) ),
Application::APP2( Variable(n), Variable(o) )
)"
}

因此我可以构建任意数量的 APP_2 ... APP_99 规则并强制执行左侧应用程序。哪个可行 - 直到我超过 99(或其他)申请数量。解决方案将是一个真正的黑客和脆弱的。


工作 Hack 方法:想要一起破解一些东西,我改变了匹配一组术语作为应用程序的方法:

APP_ARR
= terms:ABSTRACTION_OR_VARIABLE*
{
return reduceTerms(location(), terms)
}

APPLICATION_WO_PARENS
= APP_ARR

这种方法需要我编写一些代码来构建我试图避免的结构 (reduceTerms)。这是代码:

const reduceTerms = function(info, terms){
const initialLhs = terms.shift()
const initialRhs = terms.shift()
const initialApp = Application(info, initialLhs, initialRhs, false, 'reduceTerms')

const appAll = terms.reduce(
(lhs, rhs) => Application(info, lhs, rhs, false, 'reduceTerms'),
initialApp
)

return appAll ;
}

请忽略 bool 值和'reduceTerms' 字符串。 bool 值用于指示此应用程序是否包含在括号内(将删除括号概念,直到我在本书后面遇到它)。字符串是关于我如何/在何处构造此应用程序 Node 实例的标签(以调试解析器如何应用规则)。

reduceTerms 函数是将数组简单地缩减到应用程序树中,应用左侧应用程序中的术语。初始对象是 terms 数组中左侧两项的应用程序。 reducing 函数会将初始对象作为 lhs 并将下一项作为 rhs,这正是您想要的。这是工作输出:

{
"expr": "lmno",
"ast": "Application::reduceTerms(
Application::reduceTerms(
Application::reduceTerms( Variable(l), Variable(m) ),
Variable(n) ),
Variable(o) )"
}

这里的一个问题是我需要做一些额外的工作来让 info 对象准确地反射(reflect)匹配。在此版本中,info 对象包含匹配所有术语的范围。虽然这并不重要,但最好能将所有这些联系起来。


所以我仍在寻找一种解决方案,它可以在 PEG 内部执行此操作,而无需在数组上进行匹配并缩减为树。


移除左递归的进展:使用已发布的翻译方法

A -> A α | β

A -> β A'
A' -> α A' | ε

在 PEG 中我有

TERM_OR_VARIABLE
= L_PARENS TERM R_PARENS
/ VARIABLE

APP
= lhs:TERM_OR_VARIABLE rhs:APP_
{
return Application(location(), lhs, rhs, false, "APP")
}

APP_
= lhs:TERM_OR_VARIABLE rhs:APP_
{
return Application(location(), lhs, rhs, false, "APP_")
}
/ lhs:TERM_OR_VARIABLE END
{
return lhs
}
/ END

END
= !.

APPLICATION_WO_PARENS
= APP

我现在能够解析应用程序 lmno 但 AST 是从右到左的应用程序

Application::APP(  
Variable(l),
Application::APP_(
Variable(m),
Application::APP_(
Variable(n),
Variable(o)
)
)
)

关于javascript - 在保持左结合性的同时避免左递归解析 Lambda 微积分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51910361/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com