反对解析克苏鲁方式的论点是什么?


24

我的任务是为一种可能对公司非常重要的工具实现领域特定的语言。该语言很简单,但并非无关紧要,它已经允许嵌套循环,字符串连接等,并且实际上可以确定,随着项目的进行,还会添加其他构造。

我从经验中知道,除非语法很琐碎,否则手工编写词法分析器/解析器是一个耗时且容易出错的过程。因此,我有两个选择:解析器生成器y yacc或组合器库(如Parsec)。前者也很好,但是我出于各种原因选择了后者,并以功能语言实现了该解决方案。

结果在我看来非常壮观,代码非常简洁,优雅,可读/流利。我承认,如果您从未使用Java / c#以外的任何程序进行编程,它可能看起来有些怪异,但是对于未使用Java / c#编写的任何内容,这都是正确的。

但是在某个时候,我确实遭到了同事的攻击。快速浏览一下我的屏幕后,他宣布代码令人难以理解,并且我不应该重新发明解析方法,而应该像所有人一样使用堆栈和String.Split。他大声喧noise,我无法说服他,部分是因为我感到惊讶,没有明确的解释,部分是因为他的观点是不变的(没有双关语)。我什至提出要给他解释语言,但无济于事。

我很肯定讨论将再次出现在管理层面前,因此我正在准备一些扎实的论据。

这些是我想到避免基于String.Split的解决方案的前几个原因:

  • 您需要大量的if来处理特殊情况,而事情很快就会失控
  • 大量的硬编码数组索引使维护工作陷入困境
  • 很难处理像函数调用那样的方法参数(例如add((add a,b),c)
  • 如果出现语法错误,很难提供有意义的错误消息(极有可能发生)
  • 我全都是为了简单,清楚和避免不必要的智能加密,但我也认为,精简代码库的每个部分以使汉堡包都可以理解它是一个错误。我听到的是相同的论点,即不使用接口,不采用关注点分离,在周围粘贴粘贴代码等。毕竟,在软件项目上需要最低的技术能力和学习意愿。(我不会使用这个论点,因为它可能听起来令人反感,发动战争不会帮助任何人)

您最喜欢反对解析克苏鲁方式的论点是什么?*

*当然,如果您能说服我说他是对的,我也会很高兴


9
在我看来,您的同事正在自愿为您做DSL项目!
GrandmasterB

23
“我不应该重新解析,而应该像每个人一样使用堆栈和String.Split。”-该死,那个家伙应该为无知不会伤害而感到高兴……
Michael Borgwardt

4
建议您的同事不要重温讨论,除非他阅读了整本《龙书》并通过了测试。否则,他无权讨论任何与解析相关的内容。
SK-logic

4
抱歉,谁在重塑解析?
rwong

2
我认为,下一次我看到有人形象地使用“字面”一词时,我的头会立即爆炸。

Answers:


33

两种方法之间的关键区别在于,他认为唯一正确的方法是命令性的,而您的方法是声明性的。

  • 您的方法明确声明了规则,即语法规则(几乎)直接编码在您的代码中,并且解析器库自动将原始输入转换为已解析的输出,同时照顾到状态和其他难以处理的内容。您的代码编写在一层抽象中,这与问题域一致:解析。假设parsec的正确性是合理的,这意味着这里唯一的错误余地是您的语法定义是错误的。但是,您又有了完全合格的规则对象,可以轻松地对其进行隔离测试。同样值得注意的是,成熟的解析器库附带一项重要功能:错误报告。解析出错时,体面的错误恢复并非易事。作为证明,我调用了PHP的parse error, unexpected T_PAAMAYIM_NEKUDOTAYIM:D

  • 他的方法处理字符串,显式维护状态,并将原始输入手动提升为已解析的输入。您必须自己编写所有内容,包括错误报告。当出现问题时,您将完全迷路。

具有讽刺意味的是,用您的方法编写的解析器的正确性相对容易得到证明。就他而言,这几乎是不可能的。

构造软件设计的方法有两种:一种方法是使它变得如此简单,以至于显然没有缺陷,另一种方法是使它变得如此复杂以至于没有明显的缺陷。第一种方法要困难得多。

汽车Hoare

你的方法比较简单的一个。它所要做的只是让他扩大视野。无论您的视野有多广,他的方法的结果总是令人费解。
老实说,在我看来,这家伙只是个愚昧无知的人,患有勃氏综合症,如果他不了解你,就足以妄自欺欺地认为你是错的,并且对你大吼大叫。

但最终,问题是:谁将不得不维护它?如果是您,那么这就是您的电话,无论别人怎么说。如果将要成为他,那么只有两种可能性:找到一种使他理解解析器库或为他编写命令式解析器的方法。我建议您从解析器结构中生成它:D


很好地解释了两种方法之间的区别。
smarmy53,2011年

6
您显然已经链接到“ TVTropes程序员”。再见下午...
2011年

10

解析表达式语法(例如Packrat解析器方法)或解析器组合器不会重新构造解析。这些是函数式编程领域中公认的技术,并且在正确的方法中,与其他方法相比,它们更具可读性。几年前,我在C#中看到了一个令人信服的PEG演示,这实际上使它成为我使用相对简单的语法的首选工具。

如果您有使用解析器组合器或PEG的优雅解决方案,那么它应该相对容易出售:它相当可扩展,一旦克服了对函数式编程的恐惧,通常就相对容易阅读,并且有时比典型的解析器生成器更容易阅读工具提供的内容,尽管这在很大程度上取决于语法和您使用任一工具集的经验水平。为此编写测试也很容易。当然,在最坏的情况下(或Packrat会消耗大量内存),有些语法歧义会导致非常糟糕的解析性能,但平均情况是相当不错的,并且与LRLR相比,使用PEG更好地处理了某些语法歧义,因为我记得。

使用Split和stack可以使用比PEG更简单的语法,或者可以支持某些语法,但是很可能随着时间的流逝,您将严重地重新发明递归下降,或者您将获得一系列不稳定的行为,协助提交,但代价是极度非结构化的代码。如果您仅具有简单的标记化规则,则可能还不错,但是随着您添加复杂性,它可能是最难以维护的解决方案。我会代替解析器生成器。

就我个人而言,当我需要构建DSL时,我的初衷是使用Boo(.Net)或Groovy(JVM)之类的东西,因为通过构建宏和简单的调整,我可以获得现有编程语言的所有优势以及令人难以置信的可定制性到编译器管道,而无需实现我从零开始(循环,变量,对象模型等)时最终要做的乏味工作。如果我在一家从事Ruby或Lisp开发的商店中,我只会使用在那里有意义的成语(元编程等)。

但是我怀疑您真正的问题是关于文化还是自我。如果使用过Antlr或Flex / Bison,您确定您的同事不会同样感到震惊吗?我怀疑为您的解决方案“争论”可能是一场失败的战斗;您可能需要花费更多的时间来做更软的方法,该方法使用共识构建技术而不是向您的本地管理机构求助。进行配对编程,并演示在不牺牲可维护性的情况下对语法进行调整的速度,并做一个皮包来解释该技术,其历史等等,可能会超过10个要点和一些“不道德的问与答”对抗会议。


9

我并不精通解析算法之类的东西,但是我认为布丁的证据就是吃东西。因此,如果其他所有方法均失败,则可以让他以自己的方式实现解析器。然后

  • 比较两种解决方案的投入时间,
  • 通过全面的验收测试来运行两个解决方案,以查看哪个错误更少,并且
  • 让独立的法官将所生成的代码的大小和清晰度与您的代码进行比较。

为了使测试真正公平,您可能希望两个解决方案都实现相同的API,并使用一个通用的测试平台(或你们俩都知道的单元测试框架)。你们两个都可以编写任何数量和种类的功能测试用例,并确保他自己的解决方案能够通过所有这些测试用例。当然,理想情况下,你们两个都不应该在截止日期之前访问对方的实施。然后,决定性的测试将是使用另一个开发人员开发的测试套件对两个解决方案进行交叉测试。


这是一个好主意!使用公共单元测试框架也很容易。
smarmy53,2011年

1
+1是让同事进行拆分的版本... OP是创建它的任务,因此他是最有可能需要支持它的人-而不是同事。只要在他的其他工作之上向他建议,就足以使他摆脱困境。
Izkata 2012年

7

您以好像有技术问题的方式问过这个问题,但是您可能已经知道,这里没有技术问题。您的方法远胜于在角色级别上破解某些东西。

真正的问题是您的(可能是经验更丰富的)同事没有安全感,并且受到您知识的威胁。 你不会用技术性的观点来说服他 ; 那只会使他更具防御性。相反,您将必须找到某种方法来减轻他的恐惧。我不能提供很多建议,但是您可以尝试高度赞赏他对遗留代码的了解。

最后,如果您的经理同意他的各种技术论点并放弃了您的解决方案,那么我认为您将不得不寻找其他职位。显然,在一个更复杂的组织中,您将变得更有价值,更有价值。


没错,我已经知道我的方法很出色,但是我没有给出一个很好的,令人信服的解释-这就是我想要的技术信息。商定问题的“人机交互”方面与技术方面同样重要(如果不是更多的话)。
smarmy53

4

我会很简短:

解析克苏鲁方式很难。这是最简单,最有说服力的说法。

它可以解决简单语言的问题。例如普通语言。不过,它可能不会比正则表达式简单。

它也可以解决一些更复杂的语言的问题。

但是,我想看到一种Cthulhu解析器,可解析任何具有嵌套的语言,或者仅仅是“显着状态”的数学表达式或您的示例(嵌套函数调用)。

想象一下,如果有人试图为这种(非平凡的上下文无关)语言解析器会发生什么。如果他足够聪明,可以编写正确的解析器,我敢打赌,在编码过程中,他将“发现”先进行标记化,然后以某种形式“递归”下降解析。

之后,事情很简单:“嗨,看,您已经编写了一个称为递归下降解析器的东西!您知道它可以从简单的语法描述中自动生成,就像正则表达式吗?


长话短说:
唯一可以阻止某人使用文明方法的是他们的无知。


1

也许开发良好的DSL语义也很重要(语法很重要,但语义也很重要)。如果您不熟悉这些问题,我建议您阅读一些书籍,例如《编程语言实用语言》(M.Scott撰写)和Christian Queinnec。小的Lisp。剑桥大学出版社,1996年。

在DSL会议上阅读最新论文,例如DSL2011也应该有所帮助。

设计和实现领域特定语言是困难的(而且大多数困难不是解析!)。

我不太理解你解析克苏鲁的意思 ; 我想您只是想以某种奇怪的方式进行解析。


好的链接。至于克苏鲁,对不起,我忘了链接。它是对经典的codinghorror文章的引用:codinghorror.com/blog/2009/11/parsing-html-the-cthulhu-way.html。我更新了原始帖子。
smarmy53
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.