【问题标题】:Implement method calling without parentheses实现不带括号的方法调用
【发布时间】:2016-05-17 00:58:02
【问题描述】:

我当前的项目(实际上只是一种玩具语言)是一种功能性脚本语言。而且我想允许方法调用而不需要括号进行分组。

sum 1 2 3

这就是问题所在,老实说,我不确定这是否常见。但在我的语言中,方法可以定义执行标识符的参数。

def (a) plus (b)
    a + b
end

最终会是什么

1 plus 2

但是如果我对这些参数使用变量/函数呢? 例如,我怎么知道“加号”是我正在调用的方法,而不是下面的“getnum”

getnum plus 2

此外,我怎么知道 getnum 是 plus 的参数而不是相反的参数? (仅仅是通过检查参数签名吗?) 编辑:我只是重复了自己。哎呀。

最后,词法分析器应该为这种事情做一些特别的事情吗?如果是这样,IT 怎么知道应该调用哪个“方法令牌”?还是词法分析器只是将诸如“Identifiertoken”和“literaltoken”之类的东西抽出来,并留给运行时来确定它是一个方法调用?

【问题讨论】:

  • 更糟糕的是,如果 getnumplusboth 函数怎么办?一般来说,听起来你的语法会模棱两可。
  • 我的意思是,如果你有def f (x)def (x) g,那么f g 应该解决什么问题?
  • 我猜嵌套函数调用必须使用括号(或其他一些分组字符集),除非它可以根据 getnum 不带参数的事实来确定。
  • 我猜你必须建立运算符优先级来定义哪个运算符先行。与1 + 2 * 3 在数学中的工作方式相同,没有括号。
  • 这不是词法分析问题。这是一个解析问题。词法分析器不知道要调用哪个标识符“methodtoken”。它只是抽出诸如“Identifiertoken”和“literaltoken”之类的东西。解析器必须判断它是否是一个方法调用。

标签: parsing functional-programming language-design lexical-analysis


【解决方案1】:

您的问题是解析问题。但是,更大的问题是您的语言不是syntax-directed。这意味着您的语言的语法与其语义不匹配。例如,考虑以下用您的语言编写的程序:

f g

这可以通过以下两种方式之一进行解析,f 应用于gg 应用于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

这与plus-or-minus(true)(1, 2) 相同。


另一种选择是像在 Lisp 中那样引用数据。这种语法噪音要小得多:

  1. 普通函数应用,sum 1 2 3
  2. 中缀函数应用,1 plus 2
  3. 带引号的标识符,f 'g 表示f 应用于g'f g 表示g 应用于f
  4. 引用函数应用程序,'getnum' plus 2 其中 'getnum' 被隐式引用。
  5. 高阶函数应用,1 (true plus-or-minus) 2

希望对您有所帮助。

【讨论】:

  • 所以基本上句号/引号指定我们打电话给谁?
  • ...当需要时(比如在嵌套函数调用中)我们可以回退到使用括号吗?
  • 另外,很抱歉可能看起来一无所知。语言设计是我感兴趣的众多计算机科学/软件领域之一,所以即使我还没有上大学,我想我会玩弄它;)。不要告诉我我没有经验/没有受过教育,因为这是我的时间,我可以浪费它,但我认为合适:p。
  • 是的,句号标记函数,引号标记数据。您总是可以退回到嵌套函数调用的括号/引号。
  • 我不会阻止您学习计算机科学或编译器。事实上,你在这么小的年纪就开始学习编程语言真是太好了。如果你真的热衷于学习编译器,那么你应该阅读dragon book
【解决方案2】:

您正在寻找的是operator precendenceoperator associativity。在无括号方法调用的情况下,空格是函数应用运算符。

Mixfix expressions 使这有点复杂,但毕竟你只需要为你的语言制定一些规则并禁止一些模棱两可的表达。在您的示例中,您将 plus 声明为中缀运算符,并赋予所有中缀运算符高于前缀运算符的优先级。

这是解析器的工作,而不是分词器或词法分析器。

【讨论】:

  • 那么我的词法分析器将被允许继续并在这样的地方解析标识符/文字标记?到目前为止,这就是我当前的实现方式。但后来我停了下来,想知道我将如何解决像这样的“方法(方法 2(123),某个变量)”这样的方法调用(只是假装括号和逗号是空格)。我能想到的唯一方法是花时间检查参数/参数计数的有效性。这是唯一的方法吗?我也觉得我完全错过了我可以使用的逻辑快捷方式。
  • @RoyalPotato Lexers 不解析。三个不同的人告诉你这是一个解析问题,而不是词法分析问题。
  • @RoyalPotato:你的词法分析器不需要知道它是否是一个方法调用。
  • @EJP 是的,当我说“解析”时,我指的是将字符流解析为标记(即,词法分析器中包含的操作)。很抱歉造成任何混乱。
  • Here's 另一篇关于在 Agda 中解析 mixfix 运算符的论文,我认为是由 Agda 的实现者编写的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-29
  • 2011-09-28
  • 1970-01-01
相关资源
最近更新 更多