Questions tagged «compilers»

有关以一种语言(源语言)读取代码并将其翻译为另一种语言(目标语言)的等效程序的程序的问题。

4
为什么左递归不好?
此问题是从理论计算机科学堆栈交换迁移而来的,因为可以在计算机科学堆栈交换上回答。 迁移 6年前。 在编译器设计中,为什么应在语法中消除左递归?我正在读这是因为它可能导致无限递归,但是对于正确的递归语法来说,它也不是真的吗?

3
解析任意上下文无关的语法,主要是简短的摘要
我想解析用户定义的域特定语言。这些语言通常接近数学符号(我不是在解析自然语言)。用户以BNF表示法定义其DSL,如下所示: expr ::= LiteralInteger | ( expr ) | expr + expr | expr * expr 像输入1 + ( 2 * 3 )必须接受,而像输入1 +必须予以拒绝为不正确,并输入像1 + 2 * 3必须被拒绝暧昧。 这里的中心难题是以一种用户友好的方式处理模棱两可的语法。限制语法的唯一性不是一种选择:这就是语言的方式-想法是作者宁愿在不必要时避免使用括号来避免歧义。只要表达式不是模棱两可的,我就需要解析它,如果不是,我就必须拒绝它。 我的解析器必须能够处理任何与上下文无关的语法,即使是模棱两可的语法,也必须接受所有明确的输入。我需要所有接受的输入的分析树。对于无效或模棱两可的输入,理想情况下,我希望得到良好的错误消息,但首先,我将尽我所能。 通常,我将在相对较短的输入上调用解析器,而偶尔会有较长的输入。因此,渐近更快的算法可能不是最佳选择。我想针对少于80个符号长的输入,大约20%和50个符号之间的19%以及很少的较长输入的1%的分布进行优化。无效输入的速度不是主要问题。此外,我希望大约每1000至100000个输入都可以修改DSL。我可以花几秒钟来预处理我的语法,而不是几分钟。 给定我的典型输入大小,我应该研究哪种解析算法?错误报告应该成为我选择的一个因素,还是应该专注于解析明确的输入并可能运行一个完全独立的,较慢的解析器以提供错误反馈? (在需要时(前一段时间)的项目中,我使用了CYK,实现起来并不难,并且可以很好地适应我的输入大小,但不会产生非常好的错误。)


2
在许多行业使用的编译器中,为什么单静态分配优先于连续传递样式?
根据Wikipedia页面上的静态单分配(SSA)页面,大型和知名项目(例如LLVM,GCC,MSVC,Mono,Dalvik,SpiderMonkey和V8 )使用SSA,而项目使用连续传递样式(CPS)在比较中有点不足。 我的想法是,主要实现功能语言的编译器和解释器更喜欢CPS-特别是,Haskell和Scheme由于对突变的限制或需要一流的连续支持而似乎对CPS风格有强烈的倾向(我想(Smalltalk也可能需要)。我遇到的使用CPS的主要文献似乎是那些主要在Scheme上工作或在某些方面与Scheme相关的文献。 除了采用的势头之外,SSA还用于工业中有什么特殊原因吗?SSA和CPS有密切关系;这意味着很容易用另一种方式陈述,但是对于CPS来说,信息表示可能不太紧凑或效率较低。

1
为什么要分开词法和解析?
可以使用状态机的一次传递来解析文档。两次通过,即有什么好处?有一个词法分析器将文本转换为令牌,并有一个解析器来测试这些令牌的生产规则?为什么没有一次将生产规则直接应用于文本的过程?

1
产品类型的类型推断
我正在为连接语言开发编译器,并希望添加类型推断支持。我了解Hindley–Milner,但是我一直在学习类型理论,所以我不确定如何适应它。以下系统是否合理,可以推断? 术语是文字,术语的组合,术语的引用或基元。 e::=x∣∣ee∣∣[e]∣∣…e::=x|ee|[e]|… e ::= x \:\big|\: e\:e \:\big|\: [e] \:\big|\: \dots 所有术语表示功能。对于两个函数和,,即,并置表示反向组合。文字表示尼拉德功能。e 2 e 1e1e1e_1e2e2e_2e1e2=e2∘e1e1e2=e2∘e1e_1\:e_2 = e_2 \circ e_1 除组合以外的其他术语具有基本的类型规则: x:ι[Lit]Γ⊢e:σΓ⊢[e]:∀α.α→σ×α[Quot],α not free in Γx:ι[Lit]Γ⊢e:σΓ⊢[e]:∀α.α→σ×α[Quot],α not free in Γ \dfrac{}{x : \iota}\text{[Lit]} \\ \dfrac{\Gamma\vdash e : \sigma}{\Gamma\vdash [e] : \forall\alpha.\:\alpha\to\sigma\times\alpha}\text{[Quot]}, \alpha \text{ not free in } \Gamma 值得注意的是缺少应用规则,因为连接语言缺少它。 类型可以是文字,类型变量,也可以是堆栈之间的函数,其中堆栈被定义为右嵌套元组。相对于“堆栈其余部分”,所有函数都是隐式多态的。 …


2
缺点的什么性质可以消除尾部递归模缺点?
我熟悉基本尾部递归消除的概念,其中可以将返回调用自身直接结果的函数重写为迭代循环。 foo(...): # ... return foo(...) 我还了解,在特殊情况下,如果将递归调用包装在对的调用中,则仍然可以重写该函数cons。 foo(...): # ... return (..., foo(...)) 的什么性质cons允许?除了cons可以包装递归尾部调用而又不破坏我们迭代重写的功能之外,还有哪些功能呢? GCC(但不是Clang)能够优化 “尾递归模乘 ”的示例,但是尚不清楚哪种机制可以发现它或如何进行转换。 pow(x, n): if n == 0: return 1 else if n == 1: return x else: return x * pow(x, n-1)


3
为什么对二进制数据使用词法分析器/解析器如此错误?
我经常使用lexer / parsers而不是解析器组合器,并且看到从未参加过解析类的人问起解析二进制数据的问题。通常,数据不仅是二进制的,而且是上下文相关的。这基本上导致只有一种令牌,即字节令牌。 有人可以解释为什么对于没有参加语法课程但有理论基础的CS学生来说,用词法分析器/语法分析器解析二进制数据如此错误并且足够清晰。

2
除去语法中的左递归,同时保持运算符的左关联
我对此练习有疑问: 令G为λ微积分的以下歧义语法: E → v | λv.E | EE | (E) 其中E是单个非终结符号,λv.E表示带有E中变量v的抽象,而EE表示应用。 定义LL(1)语法G',以使L(G')= L(G)并通过施加以下常用约定来解决G的歧义: 抽象是正确的关联; 申请保持关联; 应用程序具有比抽象更高的优先级。 显示G'的LL(1)解析表和解析字符串时获得的解析树λv1. λv2. v1v2v1。 我消除了歧义设置的优先级和关联,获得了以下语法: E -> EF | F F -> λv.G | G G -> (E) | v 这不是LL(1),因为生产E -> EF是递归的。但是,从该生产中消除左递归可以获得: E -> FE¹ E¹-> FE¹ | ɛ F -> λv.G | …

3
“森林砍伐”如何从程序中删除“树”?
我想了解森林砍伐如何消耗,并产生在同一时间列表(由折叠和展开功能- 看到代码审查这个很好的答案在这里),但是当我相比,随着对技术的维基百科条目也谈到了“删除程序中的树木。 我了解如何将程序解析为语法分析树(是吗?),但是对某种形式的程序进行简化(是吗?)时使用砍伐森林的含义是什么?我该如何对我的代码进行处理?


3
语法LL(1)怎么样?
这是《龙书》中的一个问题。这是语法: S→AaAb∣BbBaS→AaAb∣BbBaS \to AaAb \mid BbBa A→εA→εA \to \varepsilon B→εB→εB \to \varepsilon 问题问如何显示它是LL(1)而不是SLR(1)。 为了证明它是LL(1),我尝试构造它的解析表,但是在一个单元格中有多个生成,这是矛盾的。 请告诉我们LL(1)怎么样,如何证明它?

1
“ CPS”方法严重损害了SML / NJ的性能;所需的推理
在对学习F# 的评论中:使用其他编程语言的哪些书籍可以翻译为F#以学习功能概念?Makarius说: 请注意,“ CPS”方法对SML / NJ中的性能造成了很大的损害。它的物理评估模型违反了硬件中内置的太多假设。如果您采用Isabelle / HOL之类的SML大型符号应用程序,则带有CPS的SML / NJ大约会问世。比传统堆栈的Poly / ML慢100倍。 有人可以解释原因吗?(最好有一些示例)这里是否存在阻抗不匹配?

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.