编程语言的语法和语义有什么区别?

hac*_*cks 100 syntax programming-languages semantics

编程语言(如C,C++)中语法语义的区别是什么?

小智 172

语法是关于语言的结构或语法.它回答了这个问题:我如何构建一个有效的句子?所有语言,甚至英语和其他人类(又称"自然")语言都有语法,即定义句子是否正确构造的规则.

以下是一些C语言语法规则:

  • 用分号分隔的单词
  • 在括号内包含IF语句的条件表达式
  • 通过用大括号括起来将多个语句分组到一个语句中
  • 必须在第一个可执行语句之前声明数据类型和变量(此功能已在C99中删除.C99和后者允许混合类型声明.)

语义是关于句子的意思.它回答了这个问题:这句话有效吗?如果是这样,这句话是什么意思?例如:

x++;                  // increment
foo(xyz, --b, &qrs);  // call foo
Run Code Online (Sandbox Code Playgroud)

是语法上有效的C语句.但他们的意思是什么?尝试将这些语句转换为可执行的指令序列是否有效?这些问题是语义学的核心.

在第一个语句中考虑++运算符.首先,尝试这个甚至是有效的吗?

  • 如果x是float数据类型,则此语句没有意义(根据C语言规则),因此即使语句在语法上正确也是错误的.
  • 如果x是指向某种数据类型的指针,则该语句的含义是"将sizeof(某些数据类型)添加到地址x处的值,并将结果存储到地址x"处的位置.
  • 如果x是标量,则语句的含义是"将地址x处的值加1并将结果存储到地址x处的位置".

最后,请注意,某些语义无法在编译时确定,因此必须在运行时进行评估.在++运算符示例中,如果x已经处于其数据类型的最大值,那么当您尝试向其添加1时会发生什么?另一个例子:如果你的程序试图取消引用值为NULL的指针会发生什么?

总之,语法是仅关注句子是否对语言语法有效的概念.语义是关于句子是否具有有效含义.

  • 如果有人关心具体的例子,无符号溢出被定义为模运算(所以'UINT_MAX + 1 == 0`).签名溢出未定义.现代编译器*通常*具有`INT_MAX + 1 == INT_MIN`,但有些情况下你不能指望它(例如`for(for = i; i <= N; ++ i){...}`其中`N`是`INT_MAX`不是无限的,具体取决于优化;参见http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html). (2认同)

doc*_*ove 20

语法是指语言的结构,将其词源描述为事物如何组合在一起.
例如,您可能需要通过声明类型然后是名称然后使用分号来将代码放在一起,以在语法上正确.

Type token;
Run Code Online (Sandbox Code Playgroud)

另一方面,语义是关于意义的.编译器或解释器可能会抱怨语法错误.你的同事会抱怨语义.

  • +1"编译器或解释器可能会抱怨语法错误.你的同事会抱怨语义错误." (4认同)

Tul*_*rum 12

聚会迟到了 - 但对我来说,这里的答案似乎是正确的但不完整。

实际上,我会区分三个级别:

  1. 句法
  2. 低级语义
  3. 高级语义

1. 语法

语法是语言的形式语法,它指定编译器将识别的格式良好的语句。

所以在C语言中,变量初始化的语法是:

data_type variable_name = value_expression;

例子:

int volume = 66 * 22 * 55;

在提供类型推断的 Go 中,一种初始化形式是:

variable_name := value_expression

例子:

volume := 66 * 22 * 55

显然,Go 编译器无法识别 C 语法,反之亦然。

2. 低级语义

句法与形式有关,而语义与意义有关。

在自然语言中,一个句子可能在语法上是正确的,但在语义上却毫无意义。例如:

The man bought the infinity from the store.

这句话在语法上是正确的,但在现实世界中没有意义。

在底层,编程语义关注的是语法正确的语句是否也符合开发人员使用语言类型系统表达的语义规则。

例如,这是 Java 中语法上正确的赋值语句,但在语义上它是错误的,因为它试图将 an 分配给intaString

String firstName = 23;

因此类型系统的目的是保护开发人员免受低级别无意的含义错误的影响。

JavaScript 或 Python 等松散类型语言提供的语义保护非常少,而具有表达类型系统的 Haskell 或 F# 等语言为熟练的开发人员提供了更高级别的保护。

例如,在 F# 中,您的 ShoppingCart 类型可以指定购物车必须处于以下三种状态之一:

    type ShoppingCart =
        | EmptyCart  // no data
        | ActiveCart of ActiveCartData
        | PaidCart of PaidCartData
Run Code Online (Sandbox Code Playgroud)

现在,编译器可以检查您的代码是否未尝试将购物车置于非法状态。

在 Python 中,您必须编写自己的代码来检查有效状态。

3. 高级语义

最后,在更高的层面上,语义关注的是代码想要实现的目标——编写程序的原因。

这可以表示为可以用任何完整语言实现的伪代码。例如:

    // Check for an open trade for EURUSD
    // For any open trade, close if the profit target is reached
    // If there is no open trade for EURUSD, check for an entry signal
    // For an entry signal, use risk settings to calculate trade size
    // Submit the order.
Run Code Online (Sandbox Code Playgroud)

在这种(非常简单的)场景中,如果您的系统同时输入 EURUSD 的两笔交易、以错误的方向输入交易、错误计算交易规模等,您就会犯下高级语义错误。

TL; DR

如果你搞砸了你的语法或低级语义,你的编译器会抱怨。

如果你搞砸了你的高级语义,你的程序就无法达到目的,你的客户就会抱怨。


Bas*_*tch 8

维基百科有答案.阅读语法(编程语言)语义(计算机科学) wikipages.

或者考虑任何编译器解释的工作.第一步是词法分析 ,其中通过将字符串划分为词汇然后解析来生成令牌,其构建一些抽象语法树(这是语法的表示).接下来的步骤涉及转换或评估这些AST(语义).

另外,请注意,如果你定义了一个C的变体,其中每个关键字都被转换为它的法语等价物(if变成si,do成为faire,else变成sinon等等......)你肯定会改变你的语言的语法,但你不会改变太多语义:用法语C编程并不容易!


mea*_*ers 8

  • 您需要正确的语法才能编译。
  • 您需要正确的语义才能使其工作。


thu*_*ief 6

语义就是您的代码所意味着的 - 您可能在伪代码中描述的内容.语法是实际的结构 - 从变量名到分号.


小智 6

语法是表达式、语句和程序单元的结构或形式,而语义是这些表达式、语句和程序单元的含义。语义直接来自语法语法是指特定编程语言指定的代码的结构/形式,但语义处理分配给符号、字符和单词的含义。