2

我目前正在编写我自己的语言(无耻插件),它以灵活性为中心。我试图通过扩展/插件之类的东西使语言语法的几乎任何部分都可以交换。写完整篇的时候,我一直在思考。我想知道这种灵活性如何影响语言。

我知道 Lisp 由于其广泛的宏系统而经常被称为最可扩展的语言之一。我确实理解宏的概念,但我还没有找到一种允许某人改变解析方式的语言。据我所知,几乎每一种语言都有一个非常具体的语法,由一些冗长的规范定义。

我的问题是灵活的语法如何影响语言的直观性和可用性?我知道基本的“当语法改变时人们可能会感到困惑”和“语义分析会很困难”。这些是我已经开始补偿的事情。我正在寻找关于使用灵活语法的利弊的更具概念性的答案。

语言设计的话题对我来说仍然很陌生,所以如果我问一个明显或其他愚蠢的问题,我很抱歉!

编辑: 我只是想澄清我问的问题。就语言理论而言,语言语法的灵活性究竟在哪里?我真的不需要具有灵活性的示例或项目/语言,我想了解它如何影响语言的可读性、功能和其他类似的东西。

4

4 回答 4

1

感谢SK-logic的回答为我指明了 Alan Blackwell 的方向。我给他发了一封电子邮件,询问他对此事的立场,他的回答非常精彩。这里是:

因此,回答您的 StackOverflow 问题的人说灵活的语法可能对 DSL 有用,这当然是正确的。实际上,过去常常使用 C 预处理器来创建替代语法(在初始编译阶段会变成常规语法)。许多早期的 esolang 都是这样构建的。

在实践中,我认为我们不得不说许多 DSL 都是作为常规编程语言中的库实现的,并且库设计远比语法重要。视觉语言的多样性可能有更多的目的,但是为任意图形语法制作可定制的通用编译器真的很难——比改变文本语法特性要糟糕得多。

您的设计可能会实现一些有趣的事情,所以我不会阻止实验。但是,我认为自定义语法不那么普遍的原因之一。这与著名的程序员编辑器EMACS有关。在 EMACS 中,一切都是可定制的——所有键绑定和所有编辑器功能。玩起来很有趣,而且在过去,我们中的许多人都制作了自己的个性化版本,只有我们知道如何操作。但事实证明,每个人的编辑工作方式完全不同,这确实很麻烦。你永远不能俯身对另一个人的会话提出建议,团队总是必须知道谁登录了才能知道编辑器是否会工作。事实证明,这些年来,我们都刚刚开始使用默认分布和键绑定,

在这个时间点上,这已经足够我寻找的解释了。如果有人觉得他们有更好的解释或要补充的东西,请随时与我联系。

于 2019-05-08T16:23:50.707 回答
1

Common Lisp 允许改变它的解析方式——参见阅读器宏。Racket 允许修改其解析器,请参阅球拍语言。

当然,如果您使用正确的解析技术(例如,PEG),您可以拥有灵活的、动态可扩展的解析以及强大的宏。看看这里的一个例子——主要是 C 语法,但可以用语法和语义宏进行扩展。

至于优先级,PEG 与 Pratt 配合得非常好。

为了回答您更新的问题 - 无论如何,关于编程语言可读性的研究很少。您可能想看看 Blackwell 博士小组在做什么但还远未得出结论。

所以我只能分享我的轶事——灵活的语法语言有利于 eDSL 的构建,而且,在我看来,eDSL 是消除代码中不必要的复杂性、使代码实际上可长期维护的唯一方法。我相信不灵活的语言是这个行业犯下的最大错误之一,必须不惜一切代价尽快纠正。

于 2019-04-26T11:37:42.217 回答
1
于 2019-04-17T11:32:49.997 回答
1

灵活性允许您操纵语言的语法。例如,Lisp 宏可以让您编写程序,在编译时编写程序并操作您的语法以生成有效的 Lisp 表达式。例如循环宏:

(loop for x from 1 to 5
      do(format t "~A~%" x))

1
2
3
4
5
NIL

我们可以看到代码是如何用 macroexpand-1 翻译的:

(pprint(macroexpand-1 '(loop for x from 1 to 5
                 do (format t "~a~%" x))))

然后我们可以看到对该宏的调用是如何翻译的:

  (LET ((X 1))
(DECLARE (TYPE (AND REAL NUMBER) X))
(TAGBODY
 SB-LOOP::NEXT-LOOP
  (WHEN (> X '5) (GO SB-LOOP::END-LOOP))
  (FORMAT T "~a~%" X)
  (SB-LOOP::LOOP-DESETQ X (1+ X))
  (GO SB-LOOP::NEXT-LOOP)
 SB-LOOP::END-LOOP)))

语言灵活性只允许您在一种语言中创建自己的嵌入式语言,并根据使用的字符减少程序的长度。所以理论上,这会使语言变得非常不可读,因为我们可以操纵语法。例如,我们可以创建转换为有效代码的无效代码:

(defmacro backwards (expr)
   (reverse expr))
BACKWARDS
CL-USER> (backwards ("hello world" nil format))
"hello world"
CL-USER> 

显然,上面的代码可能会变得复杂,因为:

 ("hello world" nil format)

不是有效的 Lisp 表达式。

于 2019-05-07T23:29:39.877 回答