2010-08-29 62 views
8

我正在使用新的编程语言,但是我一直对每个人都使用yaxx/lex来解析代码这一事实感到困惑,但我不是。yacc/lex还是手工编码?

我的编译器(已经工作)在C++/STL中被手动编写,我不能说它很复杂或花费太多时间。它既有某种词法分析器也有解析器,但它们不是自动生成的。

早些时候,我用同样的方式编写了一个C编译器(不是完整的spec) - 它能够在1遍中编译程序,所有这些反向引用都可以解析&预处理 - yacc/lex绝对不可能。

我只是不能说服自己放弃所有这些,并开始潜入yaxx/lex--这可能需要相当大的努力来实现,并可能会引入一些语法限制。

当没有使用yacc/lex时,是否有我想念的东西?我做了一件坏事吗?

回答

3

的Yacc是不灵活的,在某些方面:

  • 好的错误处理硬(基本上,它的算法只定义正确解析正确的字符串,否则,所有的赌注都关闭,这是原因之一该GCC移至手写解析器)
  • 上下文依赖是很难表达,而用手写的递归下降解析器可以将参数简单地添加到功能

此外,我注意到该lex/yacc目标代码是错误的比手写递归下降解析器更大(源代码往往是相反的方式)。

我还没有使用ANTLR,所以我不能说这是否更好在这些点。

1

也许你错过了ANTLR,这对于可以用递归下降解析策略定义的语言来说是很好的。

使用Yacc/Lex可能有一些优点,但它不是强制使用它们。使用Yacc/Lex也有一些缺点,但优点通常超过了缺点。尤其是,维护Yacc驱动的语法通常比手工编写的语法更容易,并且您从Yacc提供的自动化中受益。

但是,从头开始编写自己的解析器并不是一件坏事。这可能会使未来难以维持,但也可能使它更容易。

6

使用任何类型的词法分析器/分析器生成器的主要优点是,如果您的语言发展,它会给您更多的灵活性。在一个手工编码的词法分析器/解析器中(尤其是如果你在一次传递中混合了许多功能!),对语言的改变相当快,而使用解析器生成器进行更改,重新运行发电机,并继续与您的生活。总是手工编写所有内容肯定没有固有的技术限制,但我认为自动化无聊位的可演化性和可维护性是值得的!

+2

良好的模块化设计(例如,词法分析器和词法分析器应该完全分离)可以减少这个问题。仍然重要。 – delnan 2010-08-29 11:23:40

3

使用生成器的另一个巨大优势是它们保证能够精确处理并且只处理您在语法中指定的语言。你不能说任何手写代码。 LR/LALR变体也保证是O(N),这也是你不能断言的任何手工编码,至少在构建证明时不需要很多努力。

我已经写了两个都住在一起,我再也不会手动编码了。我只做了那个,因为当时我没有在平台上使用yacc

+0

那么,我不需要一个数学证明来知道我的代码是快速的 - 通常很明显它在O(N)或O(N * LogN)中的某处。 – BarsMonster 2010-08-29 02:23:05

+2

我没有说'快'的任何内容。我在谈论算法的复杂性,你需要一个证明。 – EJP 2010-08-29 02:57:46

+0

那么,当我编写代码时,我总是知道它很复杂。如果工具为我编写代码 - 那么我肯定会需要一个证明。 – BarsMonster 2010-08-29 03:26:41

0

这当然取决于你的语言语法的复杂性。一个简单的语法意味着有一个简单的实现,你可以自己做。

看看也许是最糟糕的可能的例子:C++ :)(除了自然语言之外,是否有人知道另一种语言,这些语言更难以正确解析?)即使使用Antlr这样的工具,也很难做对,尽管它是可以管理的。因此,在另一方面,即使很困难,似乎一些最好的C++解析器,例如GCC和LLVM也大都是手写的。

如果您不需要太多的灵活性,并且您的语言不是太简单,那么您将通过使用Antlr确保一些工作/时间安全。

+0

我的语言的复杂性只比C++少一点。 – BarsMonster 2010-08-29 02:14:49

+1

经典的Fortran很难解析:DO10I = 12.43'“和DO循环”DO10I = 12,43'“的分配甚至不能准确地分解成单词,直到你到达逗号vs句号。 (第一个涉及一个浮点变量'DO10I',第二个涉及一个整数变量'I'和一个标签'10':'DO 10 I = 12,43')。这往往会让它变得相当困难! – 2010-08-29 09:07:11