我当前的项目(实际上只是一种玩具语言)是一种功能性脚本语言。我想允许方法调用,而不需要括号进行分组。
sum 1 2 3
这就是问题所在,说实话,我不确定这是否是常见的事情。但是在我的语言中,方法可以定义继续标识符的参数。
def (a) plus (b)
a + b
end
最终会成为
1 plus 2
但是如果我在这些参数中使用变量/函数呢? 例如,我怎么知道"加"是我打电话的方法而不是" getnum"在以下
getnum plus 2
此外,我怎么知道getnum是加号的参数而不是其他方式? (它只是通过检查参数签名吗?) 编辑:我只是重复自己。糟糕。
最后,一个词法分析者应该为这类事做些特别的事吗?如果是这样,IT将如何知道哪一个称为" methodtoken"?或者词法分析器只是抽出像#34; Identifiertoken" " literaltoken" out并将其留给运行时以确定它是一个方法调用?
答案 0 :(得分:3)
您的问题是解析问题。但是,更大的问题是您的语言不是syntax-directed。这意味着您的语言语法与其语义不匹配。例如,请考虑使用您的语言的以下程序:
f g
可以通过以下两种方式之一解析:f
应用于g
或g
应用于f
。但是,该语言的语法并不能说明将生成两个解析树中的哪一个。正如EJP正确提到的那样,“它不仅仅是一个解析问题,而是一个语义反馈问题”。
那么,如何使语言语法导向?让我们从面向对象的语言中获得启发。例如:
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
这是因为在getnum
应用plus
之前调用了plus(getnum(), 2)
。这意味着getnum .plus 2
。另一方面,plus(getnum, 2)
意味着plus
这将是一个错误,因为您无法将1 .(true .plus-or-minus) 2
应用于函数。
将点视为您语言的“apply”运算符。使用点甚至可以让您拥有更高阶的功能:
plus-or-minus(true)(1, 2)
这与sum 1 2 3
相同。
另一种方法是像在Lisp中那样引用数据。这种语法噪音要小得多:
1 plus 2
。f 'g
。f
表示g
适用于'f g
,g
表示f
适用于'getnum' plus 2
。'getnum'
隐含引用1 (true plus-or-minus) 2
。3D_vol(Start_x : Start_x + SizeX-1, Start_y : Start_y + SizeY-1, Start_z : Start_z + SizeZ-1);
。希望有所帮助。
答案 1 :(得分:1)
您要找的是operator precendence和operator associativity。在无括号方法调用的情况下,空格是函数应用程序操作符。
Mixfix expressions使这一点复杂化,但毕竟你只需要为你的语言制定一些规则并禁止使用一些含糊不清的表达。在您的示例中,您将plus
声明为中缀运算符,并为所有中缀运算符提供比前缀运算符更高的优先级。
这是解析器的工作,而不是tokenizer或lexer。