编程语言的语法是否取决于其实现?


12

虽然,我的问题可能完全无关紧要,但是我已经感觉到大多数编程语言与其官方实现之间存在一种模式。

诸如Python,Lua等之类的解释(字节解释?)语言通常具有极其宽松和容易的语法,并且通常没有类型,或者不需要开发人员在源代码中显式地编写变量类型。

诸如C,C ++,Pascal等的编译语言通常具有严格的语法,通常具有类型,并且通常需要更多的代码/开发时间

像Java / C#这样的官方实现采用JIT编译的语言通常是上述两种语言之间的独特折衷,同时兼具两者的某些最佳功能。

某些更现代的已编译编程语言(例如D和Vala,以及Java的GNU GJC实现)可能是该规则的例外,并且类似于Java和C#等JIT编译语言的语法和功能。

我的第一个问题是,这真的相关吗?或者这仅仅是大多数解释语言具有简单语法的巧合,而JIT编译语言具有适度的语法和功能等。

其次,如果这不是巧合,那为什么呢?举例来说,如果您正在对JIT进行编译,则某些功能只能用编程语言来实现吗?


@YannisRizos对不起,这不是报价。我只是想强调一下。我将对其进行编辑。
ApprenticeHacker

1
太酷了,尽管它不是引号,但它可能导致回答者认为它是一个引号,而不是试图反驳(或盲目同意)。。。回答。
yannis 2011年

@ R.MartinhoFernandes对不起,我没有意识到。我将再次编辑它。
ApprenticeHacker

4
对于用户定义的类型,Perl是动态类型的,关于区分数组,哈希,标量和子例程是静态类型的,并通过使用严格的,解释的和JIT编译的类型来强类型的(当然不是在同一时间)。为了使语言设计
更有

3
“宽松语法”与“严格语法”是什么意思?它们都是正式语言,没有一个会运行语法错误的源代码。
nikie 2011年

Answers:


17

语义和语法之间没有任何联系。像Scheme之类的Homoiconic编译语言都带有非常简单的语法。像Forth这样的低级编译元语言甚至比这更简单。一些非常严格类型的编译语言是基于琐碎的语法构建的(想想ML,Haskell)。OTOH,就许多语法规则而言,Python语法非常重要。

是的,键入与语法无关,它是语言的语义方面,除非它像C ++一样变态,否则在没有所有可用键入信息的情况下,您甚至无法解析。

一个普遍的趋势是,语言发展太久且不包含任何防止语法偏差的设计保护措施,迟早会演变成语法可憎的词。


+1让我查找“ homoiconic” ...并向PHP隐约点头
yannis

1
+1,语言发展太久且不包含任何设计保障,这是否也涉及Delphi / Object-Pascal?
ApprenticeHacker

1
@ThomasEding,你错了。即使使用无语法语言(例如Lisp或Forth),也可以在非常广泛的语法样式上实现相同的语义。相同的语法可以用于多种不同的语义-例如,C和Verilog表达式的语法几乎相同,但是语义却大不相同。
SK-logic

1
@ SK-logic-仅仅是因为它很复杂且图灵完成,并不意味着它至少不是程序语法的很大一部分。解析各种语言是图灵完成的,这并不能神奇地解析“与语法无关”的内容。语法与“作用域”无关,而与语言中语句结构的规则有关,而无需说明这些语句的含义。类型检查和类型推断不执行程序就对程序的语法树进行操作-它们确定程序结构的事情时不说任何有关...
Jack

1
@Jack,您正在尝试重新定义语法。没有实用的语言需要图灵完备的解析器,大多数仅与上下文无关。这就是语法应保留的地方。请不要在其他任何地方扩展这个(已经太过张扬)的概念。而且我已经提到过Curry-Howard同构-它全是关于语义的,远远超出了正确性规则。我认为,“ type checking” 这个词极度适得其反,不应该使用,这是非常误导的,它不能反映类型系统的性质。
SK-logic

6

通常这是一个巧合。

编程语言随着时间的推移而发展,并且编译器和解释器的技术也得到了改进。随着主流计算平台功能的增强,底层处理的效率(即编译时间,解释开销,执行时间等)也不再那么重要。

语言语法确实会产生影响-例如,Pascal经过精心设计,因此可以使用单遍编译器-即对源代码进行一次遍历,并且您具有可执行的机器代码。另一方面,Ada对此并不重视,而且众所周知,Ada编译器很难编写-大多数都需要多次通过。(我多年前使用的一个非常好的Ada编译器是8遍编译器。您可能会想到,它非常慢。)

如果您查看诸如Fortran(已编译)和BASIC(已解释或已编译)之类的旧语言,则它们具有非常严格的语法和语义规则。[在使用BASIC的情况下,那就不是Bills旧的BASIC,您需要在此之前返回原始版本。

另一方面,看一下诸如APL(很多有趣的东西)之类的其他东西,它具有动态类型。它通常也被解释,但是也可以被编译。

宽松的语法是一种困难的语法-如果这意味着您具有可选的东西或可以推断出的东西,那么这意味着该语言具有足够的丰富性,可以将其剔除。再说一次,BASIC早在多年前,当“ LET”语句变为可选语句时!

您现在看到的许多想法(例如,无类型或动态类型)实际上是非常古老的-最早出现在1970年代或1980年代初期。它们的使用方式以及这些思想的使用语言已经发生了变化和增长。但从根本上说,许多新事物实际上是穿着新衣服打扮的旧东西。

这是我脑中浮现的一些例子:

  • APL:动态类型。一般解释。来自1960年代/​​ 1970年代。
  • 基本:强类型或动态类型。解释或编译。1970年代及以后。
  • Fortran:强类型。已编译。1960或更早。
  • Algol68:强打字。已编译。1960年代。
  • PL / 1:强打字。已编译。1960年代。
  • 帕斯卡:强打字。已编译。1970年代。(但是在1980年代,有一些P-System编译器与JIT编译器非常相似!)
  • DEC早期对Fortran的某些实现和其他实现进行了部分编译和部分解释。
  • Smalltalk:动态键入。编译为解释的字节码。1980年代。
  • 序言:更加陌生。功能性。已编译(Turbo Prolog,有人吗?)。1980年代。
  • C:强(哈哈)打字。已编译。今天是1960年代。
  • 艾达:超级强打字。已编译。1980年代。
  • Perl:动态打字。(强语法)。解释。1990年代(?)。

我可以继续。

  • Nitpickers角落:许多解释语言在加载/读入源代码时被标记化或“字节编译”。这使解释器的后续操作更加简单。有时,您可以保存代码的字节编译版本。有时候你做不到。它仍然被解释。

更新:因为我不够清楚。

键入可能有很大差异。

编译时固定静态类型很常见(例如,C,Ada,C ++,Fortan等)。在这里,您可以声明TYPE的事物,并且永远都是这样。

动态类型化也是可能的,其中事物选择分配给它的类型。例如,PHP和一些早期的BASIC,以及APL,您将在其中为变量分配一个整数,此后便是整数类型。如果以后给它分配了一个字符串,则它是一个字符串类型。等等。

然后是松散类型,例如PHP,您可以在其中做一些真正奇怪的事情,例如为变量分配数字整数(带引号的字符串),然后向其添加数字。(例如,“ 5” + 5将得出10)。这是一块奇异的土地,但有时也非常非常有用。

但是这些是设计成语言的功能。该实现只是实现了这一点。


13
强类型化不是动态类型的对应。这是弱类型的对应。与动态类型化相对应的是静态类型化:一方面,程序中的表达式类型可以是静态的(即,无需运行程序)。在另一种类型中,只能动态知道类型(即必须运行程序)。
R. Martinho Fernandes

是的,BASIC和APL的某些变体早在1970年代末期都在这样做。APL类型并不像我们今天所了解的那样(是通用类型的整数/浮点数,但也可以是向量,字符串和多维矩阵)。
quick_now 2011年

Fortran解释器仍被广泛使用(请参阅Cernlib和PAW)。它的后代ROOT是基于C ++解释器构建的。
SK-logic

老实说,我还不太清楚强/弱类型和静态/动态类型与语法之间的关系。但是答案质量很好,所以我只是避免投票。我将C类键入为“静态/弱”(将存储的值视为另一种类型,这很简单,可能会得到错误的值)。
Vatine 2011年

@Vatine-我实际上会说在编译时很强,而在运行时不很强-如果您这样想的话。您可以使用多种语言的指针及其等效对象来实现。在经典Pascal中使用变体记录甚至在Ada中使用UNCHECKED_CONVERSION也是可能的(尽管很困难,但有可能)。
quick_now 2011年

2

我认为这是另一回事:实现取决于语法。例如,如果您的语法允许反射,则实现必须提供支持该反射的运行时。


@IntermediateHacker:但它在java中,所以我应该很棒
sehe 2011年

2

我通常同意quick_now,因为您的观察主要是历史的结果。也就是说,潜在的推理可以归结为以下内容:

The more modern a language is, the more comfortable it should be to use.

(实际上不是引号,只是我自己的表述。)当我comfortable在此处写内容时,指的是您所说的best features of both。更准确地说,我不想支持或反对静态/动态类型或严格/宽松的语法。相反,重要的是要注意将重点放在开发人员上并在使用该语言时提高其舒适度。

这是一些先前的答案中未提及的原因,这些原因可能会为您提供一些观察这些原因的想法(并且都是基于编程语言开发的历史):

  • 如今,我们有数百种编程语言。当一个新的出现时,如何找到广泛的受众?这是主要原因,为什么新语言总是试图提高开发人员的舒适度。如果该语言可以与较旧的语言进行相同的操作,但是可以更轻松/更简单/更优雅/等等。您可能要考虑实际切换。

  • 学习曲线与此并存。过去,我们只有很少的语言,花时间学习一种语言是值得的。即使那意味着要投入大量时间。如果您想出一种开发人员可以非常快速地学习的语言,那么舒适度就会再次提高。任何种类的复杂性(例如,复杂的语法)都不利于此,因此,在较新的语言中,复杂度越来越低。

  • 技术的进步(这里是直接的历史原因)使得编译器构建者现在可以更加关注开发人员的舒适度。在早期,我们很高兴能够构建一个编译器。但是,这通常意味着要进行严格的限制。随着技术知识的增加,我们能够再次取消这些限制。

因此,总的来说,编程语言和编译器的发展类似于典型的最终用户应用程序:

  1. 初始阶段:这是一件很酷的事情,但是最前沿的技术勉强能以舒适性/可用性/无所作为为代价。
  2. 技术改进:我们可以更强大,更快,更轻松地构建这些东西。
  3. 关注点转向用户:与关注用户体验的Web2.0运动类似,新的编程语言也关注开发人员角度。

(Not a quote really, just my own formulation.)好吧,您将其格式化为代码,而不是blockquote,所以我认为没有人认为这是引号:)
yannis 2011年

3
舒适感显然取决于口味(始终完全是主观的)。我最喜欢的语言是1959年设计的,我无法忍受本世纪出现的某些语言。
SK-logic

1
舒适度还取决于目的。在用于洗衣机控制器的8k嵌入式微控制器上运行PHP或Prolog可能“很舒服”,但实际上很难使其适应并以可接受的性能运行。
quick_now 2011年

0

给定的编程语言可能会(也可能不会)暴露或限制足够的语义信息,以使编译器可以推断出如何在不增加运行时决策的情况下将其简化为可执行代码(“此变量的类型是什么?”等)。这个约束是强制性的,还是容易确定的。

随着编译器变得越来越聪明,他们甚至能够猜测或分析足够的信息来为最可能的路径生成可执行代码,即使是未明确设计为暴露或约束那些决定的语言也是如此。

但是,可以在运行时创建或输入代码(evalString())的语言(以及编译器无法推断或猜测的其他内容)可能要求解释器或JIT编译器在运行时可用,即使尝试进行预编译也是如此。编译它们。

过去,编程语言及其实现可能已经发展为适应某些硬件限制,例如解释器可能适合4k还是16k,或者编译器是否可以在不到一分钟的CPU时间内完成。随着机器速度的提高,已经有可能(尽快)重新编译一些以前解释的程序,使程序员能够按回车键,或者解释以前编译的程序源代码的速度比稍早的硬件可以运行经过优化的编译后的可执行文件的速度还快。

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.