实现不带括号的方法调用
Implement method calling without parentheses
我当前的项目(真的只是一种玩具语言)是一种函数式脚本语言。我想允许方法调用而不需要括号进行分组。
sum 1 2 3
问题来了,老实说,我不确定这是否常见。但是在我的语言中,方法可以定义继续标识符的参数。
def (a) plus (b)
a + b
end
最终会是
1 plus 2
但是如果我对这些参数使用 variables/functions 怎么办?
例如,我怎么知道 "plus" 是我正在调用的方法而不是下面的 "getnum"
getnum plus 2
此外,我怎么知道 getnum 是 plus 的参数而不是相反的参数? (是否只是通过检查参数签名?)
编辑:我只是重复了一遍。哎呀
最后,词法分析器是否应该为这种事情做些特别的事情?如果是这样,IT 如何知道调用哪个 "methodtoken"?还是词法分析器只是抽出 "Identifiertoken" 和 "literaltoken" 之类的东西,然后将其留给运行时来确定它是一个方法调用?
您要找的是operator precendence and operator associativity。在无括号方法调用的情况下,空白 space 是函数应用程序运算符。
Mixfix expressions 稍微复杂一点,但毕竟你只需要为你的语言制定一些规则并禁止一些模棱两可的表达。在您的示例中,您将 plus
声明为中缀运算符,并为所有中缀运算符赋予比前缀运算符更高的优先级。
这是解析器的工作,而不是分词器或词法分析器。
你的问题是解析问题。然而,更大的问题是你的语言不是syntax-directed。这意味着您的语言的语法与其语义不匹配。例如,用您的语言考虑以下程序:
f g
这可以通过以下两种方式之一进行解析,f
应用于 g
或 g
应用于 f
。然而,该语言的语法并没有明确表示将生成两个解析树中的哪一个。正如 EJP 正确提到的那样,"it is more than a parsing problem, it is a semantic-feedback problem".
那么,如何让你的语言语法制导呢?让我们从面向对象的语言中得到启发。例如:
1 plus 2
在像 JavaScript 这样的面向对象语言中,这可能被写成:
Number.prototype.plus = function (n) {
return this + n;
};
var sum = (1) .plus (2);
alert(sum);
比较两种语言的语法,我们发现唯一的主要区别是标识符前面的点 plus
。这就是我们使您的语言语法制导所需的全部。现在,您可以使用正常功能了:
.sum 1 2 3
但是,您也可以使用语法制导的中缀函数:
1 .plus 2
现在,以下表达式不再有歧义:
.f g
f .g
但是,您仍然需要括号来消除某些表达式的歧义:
(.getnum) .plus 2
这是因为在应用 plus
之前调用了 getnum
。意思是plus(getnum(), 2)
。另一方面,getnum .plus 2
表示 plus(getnum, 2)
,这将是一个错误,因为您不能将 plus
应用于函数。
将点视为您的语言的 "apply" 运算符。使用点甚至可以让您拥有更高阶的功能:
1 .(true .plus-or-minus) 2
这与 plus-or-minus(true)(1, 2)
相同。
另一种方法是像在 Lisp 中那样引用数据。这种语法噪音小得多:
- 正常函数应用,
sum 1 2 3
。
- 中缀函数应用,
1 plus 2
.
- 带引号的标识符,
f 'g
表示 f
应用于 g
,'f g
表示 g
应用于 f
。
- 引用函数应用程序,
'getnum' plus 2
其中 'getnum'
被隐式引用。
- 高阶函数应用,
1 (true plus-or-minus) 2
。
希望对您有所帮助。
我当前的项目(真的只是一种玩具语言)是一种函数式脚本语言。我想允许方法调用而不需要括号进行分组。
sum 1 2 3
问题来了,老实说,我不确定这是否常见。但是在我的语言中,方法可以定义继续标识符的参数。
def (a) plus (b)
a + b
end
最终会是
1 plus 2
但是如果我对这些参数使用 variables/functions 怎么办? 例如,我怎么知道 "plus" 是我正在调用的方法而不是下面的 "getnum"
getnum plus 2
此外,我怎么知道 getnum 是 plus 的参数而不是相反的参数? (是否只是通过检查参数签名?) 编辑:我只是重复了一遍。哎呀
最后,词法分析器是否应该为这种事情做些特别的事情?如果是这样,IT 如何知道调用哪个 "methodtoken"?还是词法分析器只是抽出 "Identifiertoken" 和 "literaltoken" 之类的东西,然后将其留给运行时来确定它是一个方法调用?
您要找的是operator precendence and operator associativity。在无括号方法调用的情况下,空白 space 是函数应用程序运算符。
Mixfix expressions 稍微复杂一点,但毕竟你只需要为你的语言制定一些规则并禁止一些模棱两可的表达。在您的示例中,您将 plus
声明为中缀运算符,并为所有中缀运算符赋予比前缀运算符更高的优先级。
这是解析器的工作,而不是分词器或词法分析器。
你的问题是解析问题。然而,更大的问题是你的语言不是syntax-directed。这意味着您的语言的语法与其语义不匹配。例如,用您的语言考虑以下程序:
f g
这可以通过以下两种方式之一进行解析,f
应用于 g
或 g
应用于 f
。然而,该语言的语法并没有明确表示将生成两个解析树中的哪一个。正如 EJP 正确提到的那样,"it is more than a parsing problem, it is a semantic-feedback problem".
那么,如何让你的语言语法制导呢?让我们从面向对象的语言中得到启发。例如:
1 plus 2
在像 JavaScript 这样的面向对象语言中,这可能被写成:
Number.prototype.plus = function (n) {
return this + n;
};
var sum = (1) .plus (2);
alert(sum);
比较两种语言的语法,我们发现唯一的主要区别是标识符前面的点 plus
。这就是我们使您的语言语法制导所需的全部。现在,您可以使用正常功能了:
.sum 1 2 3
但是,您也可以使用语法制导的中缀函数:
1 .plus 2
现在,以下表达式不再有歧义:
.f g
f .g
但是,您仍然需要括号来消除某些表达式的歧义:
(.getnum) .plus 2
这是因为在应用 plus
之前调用了 getnum
。意思是plus(getnum(), 2)
。另一方面,getnum .plus 2
表示 plus(getnum, 2)
,这将是一个错误,因为您不能将 plus
应用于函数。
将点视为您的语言的 "apply" 运算符。使用点甚至可以让您拥有更高阶的功能:
1 .(true .plus-or-minus) 2
这与 plus-or-minus(true)(1, 2)
相同。
另一种方法是像在 Lisp 中那样引用数据。这种语法噪音小得多:
- 正常函数应用,
sum 1 2 3
。 - 中缀函数应用,
1 plus 2
. - 带引号的标识符,
f 'g
表示f
应用于g
,'f g
表示g
应用于f
。 - 引用函数应用程序,
'getnum' plus 2
其中'getnum'
被隐式引用。 - 高阶函数应用,
1 (true plus-or-minus) 2
。
希望对您有所帮助。