什么是开始编写编程语言的好资源,这不是上下文无关的?

时间:2008-09-16 00:28:17

标签: python compiler-construction programming-languages interpreter

我正在寻找一种有趣的编程语言,但是我所看到的大多数资源都是用于编写无上下文的语言,但我希望编写一种像python一样的语言,使用缩进,这对我的理解意味着它不能没有上下文。

12 个答案:

答案 0 :(得分:19)

简单地说,无上下文语法是一种不需要符号表以正确解析代码的语法。一个上下文敏感的语法。

D编程语言是无上下文语法的一个例子。 C ++是一个上下文敏感的。 (例如,T * x声明x是指向T的指针,还是将T乘以x?我们只能通过在符号表中查找T来判断它是类型还是变量。)

空白与它无关。

D使用无上下文语法,以便大大简化解析它,以便简单的工具可以解析它(例如语法高亮编辑器)。

答案 1 :(得分:6)

你可能想要阅读这篇关于解析Python Python: Myths about Indentation的写得很好的文章。

虽然我没有尝试使用类似yacc的东西来编写无上下文解析器,但我认为使用条件词法分析器可以返回缩进更改标记,如url中所述。

顺便说一下,这是来自python.org的官方python语法:http://www.python.org/doc/current/ref/grammar.txt

答案 2 :(得分:5)

我首先要通过阅读有关该主题的一些文献来熟悉这个问题。 Aho等人的经典 Compilers 一书。人。数学和复合科学可能很重要,但杰克克伦肖的Let's Build a Compiler文章是一个更加容易接受的文本。这是Crenshaw先生在80年代后期写的一系列文章,它是有史以来编写的最不受欢迎的文本。方法很简单,重点:克伦肖先生表示“ A ”方法有效。您可以轻松地浏览几个晚上的内容,并更好地了解编译器的内容。一些警告是文本中的示例是用Turbo Pascal编写的,编译器会发出68K汇编程序。这些示例很容易移植到更新的编程语言,我推荐Python。但是,如果您想要按照示例进行操作,则至少需要Turbo Pascal 5.5a 68K assembler and emulator。该文本今天仍然具有相关性,使用这些旧技术非常有趣。我强烈推荐它作为任何人在编译器上的第一篇文章。好消息是像Python和Ruby这样的语言是开源的,你可以下载和研究C源代码,以便更好地理解它是如何完成的。

答案 3 :(得分:3)

“无上下文”是一个相对术语。大多数无上下文的解析器实际上解析了无上下文的语言的超集,然后检查生成的解析树以查看它是否有效。例如,根据C的无上下文语法,以下两个C程序是有效的,但在上下文检查期间很快就会失败:

int main()
{
    int i;
    i = 1;
    return 0;
}

int main()
{
    int i;
    i = "Hello, world";
    return 0;
}

没有上下文,i = "Hello, world";是完全有效的赋值,但在上下文中,您可以看到类型都是错误的。如果上下文是char* i;,那就没关系。因此,无上下文解析器将看到该赋值没有错。直到编译器开始检查类型(依赖于上下文)它才会捕获错误。

可以使用键盘生成的任何内容都可以解析为无上下文;至少你可以检查所有使用的字符是否有效(只包含可显示的Unicode字符的所有字符串的集合是无上下文语法)。唯一的限制是你的语法有多么有用,以及你需要对生成的解析树进行多少上下文相关的检查。

像Python这样的依赖于空格的语言使得无上下文的语法变得不那么有用,因此需要在以后进行更多的上下文敏感检查(其中大部分是在Python中通过动态类型在运行时完成的)。但是在需要进行上下文相关检查之前,仍然有很多无上下文解析器可以做。

答案 4 :(得分:2)

我不知道任何教程/指南,但您可以尝试查看tinypy的源代码,它是一种非常小的类似python语言的实现。

答案 5 :(得分:2)

在语言中使用缩进并不一定意味着语言的语法不能无上下文。即缩进将决定语句存在于哪个范围内。无论在哪个范围内定义语句,语句仍然是一个语句(范围通常可以由编译器/解释器的不同部分处理,通常在语义分析期间)。

那说一个好的资源就是antlr工具(http://www.antlr.org)。该工具的作者还编写了一本关于使用antlr(http://www.pragprog.com/titles/tpantlr/the-definitive-antlr-reference)创建语言解析器的书。有很好的文档和很多示例语法。

答案 6 :(得分:2)

如果你真的打算对语言设计和实现进行打击,你可能想要将以下内容添加到你的书架中:

  • 编程语言语用学,Scott等人
  • 编程语言中的设计概念,Turbak等人
  • 现代编译器设计,Grune等。 (我亵渎地更喜欢Aho等人的“龙书”)

Gentler介绍如:

  • Crenshaw的教程(由@'Jonas Gorauskas'在这里建议)
  • Parr的最终ANTLR参考
  • Martin Fowler最近关于DSL的工作

您还应该考虑您的实施语言。这是其中不同语言极大不同的领域之一。您应该考虑LISP,F#/ OCaml和Gilad Bracha的新语言Newspeak等语言。

答案 7 :(得分:1)

我建议您手动编写解析器,在这种情况下,使用重要的空格不应该出现任何实际问题。

使用解析器生成器的主要问题是难以在解析器中获得良好的错误恢复。如果您计划为您的语言实现IDE,那么良好的错误恢复对于使Intellisence这样的东西工作非常重要。 Intellisence总是在不完整的句法结构上运行,解析器在确定用户尝试输入的构造时越好,你可以提供更好的智能体验。

如果你编写一个手写的自上而下的解析器,你可以在任何你想要的地方实现你想要的规则。这使得提供错误恢复变得容易。它还将使您实现重要的空白变得微不足道。您可以简单地将当前缩进级别存储在解析器类中的变量中,并且当您在列位置小于当前缩进级别的新行上遇到令牌时,可以停止解析块。此外,你可能会在语法上遇到含糊之处。广泛使用的大多数“生产”语言具有语法歧义。一个很好的例子是C#中的泛型(在表达式上下文中“<”周围存在歧义,它可以是“小于”运算符,也可以是“通用参数列表”的开头)。在一个手写的解析器中,解决这种模糊性是微不足道的。您可以在需要的地方添加一些非确定性,而对其余解析器的影响相对较小,

此外,因为您自己设计语言,所以您应该假设它的设计会快速发展(对于某些使用标准委员会的语言,如C ++,情况并非如此)。对自动生成的解析器进行更改以处理歧义或演变语言可能需要您对语法进行重大的重构,这可能既刺激又耗时。对手写解析器的更改,特别是对于自上而下的解析器,通常是非常本地化的。

我想说解析器生成器只是一个很好的选择:

  1. 您永远不会计划编写IDE,
  2. 该语言具有 真正的 简单语法或
  3. 你需要一个解析器非常快,而且用户体验不好

答案 8 :(得分:1)

你读过Aho,Sethi,Ullman:“编译器:原理,技术和工具”吗?这是一本经典的语言参考书。

/阿伦

答案 9 :(得分:1)

如果您以前从未编写过解析器,请从简单的开始。解析器令人惊讶地微妙,如果你从未研究过编程语言的结构,你可能会遇到各种各样的麻烦。

阅读Aho,Sethi和Ullman(它被称为“龙书”)是一个很好的计划。与其他贡献者相反,我说你应该首先使用更简单的解析器生成器,比如Yacc和Bison,并且只有当你被烧毁因为你不能用这个工具做某事时你应该继续尝试用LL创建一些东西(* )解析器像Antlr。

答案 10 :(得分:0)

仅仅因为语言使用显着的缩进并不意味着它本身就是上下文敏感的。作为一个例子,Haskell使用了显着的缩进,并且(据我所知)它的语法是无上下文的。

需要上下文敏感语法的源代码示例可能是Ruby的这个片段:

my_essay = << END_STR
This is within the string
END_STR

<< self
  def other_method
    ...
  end
end

另一个例子是Scala的XML模式:

def doSomething() = {
  val xml = <code>def val <tag/> class</code>
  xml
}

作为一般规则,上下文相关语言在任何精确意义上都难以想象,因此不太常见。即使Ruby和Scala也不会真正计数,因为它们的上下文敏感功能只包含该语言的次要子集。如果我是你,我会制定我的语法作为灵感的指示,然后担心以后解析方法。我想你会发现,无论你想出什么,都会自然而然地没有背景,或者非常接近它。

最后要注意的是,如果确实需要上下文相关的解析工具,您可以尝试一些不那么严格的正式技术。解析器组合器用于Scala的解析。他们有一些恼人的限制(没有lexing),但他们并不是一个坏工具。像ANTLR这样的LL(*)工具似乎也更擅长表达这种“临时”解析逃逸。不要试图将Yacc或Bison与上下文敏感的语法一起使用,他们要严格地表达这些概念。

答案 11 :(得分:0)

上下文相关语言?这个是非缩进的:Protium(http://www.protiumble.com