【问题标题】:What is the difference between syntax and semantics in programming languages?编程语言中的语法和语义有什么区别?
【发布时间】:2013-07-29 14:39:30
【问题描述】:

语法语义在编程语言(如C、C++)中有什么区别?

【问题讨论】:

  • 我想投票,但没有明显的研究成果。

标签: syntax programming-languages semantics


【解决方案1】:

TL;博士

总而言之,句法是只关心句子本身是否对语言的语法有效的概念。语义是关于句子是否具有有效含义。

长答案:

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

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

  • 用分号分隔语句
  • 将 IF 语句的条件表达式括在括号内
  • 通过用大括号括起来将多个语句组合成一个语句
  • 数据类型和变量必须在第一个可执行语句之前声明(此功能已在 C99 中删除。C99 及更高版本允许混合类型声明。)

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

x++;                  // increment
foo(xyz, --b, &qrs);  // call foo

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

考虑第一条语句中的 ++ 运算符。首先,尝试这样做是否有效?

  • 如果 x 是浮点数据类型,则该语句没有意义(根据 C 语言规则),因此即使该语句在语法上是正确的,它也是一个错误时间>
  • 如果x是指向some data type的指针,则语句的意思是“将sizeof(some data type)加到地址x处的值上并存储将结果存入地址 x 处的位置”。
  • 如果 x 是标量,则语句的含义是“将地址 x 处的值加一,并将结果存储到地址 x 处的位置”。

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

【讨论】:

  • 好的。如果x 处于其数据的最大值并且将1 添加到其中,则会导致一些奇怪的输出(0),这不是语义错误吗?
  • 考虑汽车中的里程表——它有一系列相互关联的轮子,每个轮子上都印有数字 0 到 9。最右边的轮子转得最快;当它从 9 回绕到 0 时,它最左边的轮子前进 1。当这个轮子从 9 前进到 0 时,它左边的那个会前进,依此类推。
  • 数据类型就像里程表的轮子:它只能保持一定的值。当达到最大值时,下一次前进会使车轮归零。这是否是语义错误取决于语言规则。在这种情况下,您需要重新参考 C 语言标准。我不确切知道 C 语言标准是怎么说的,但这里有一些选项。溢出是:-不是错误;结果为零。 -一个错误;编译器必须生成溢出异常。 -UNDEFINED;编译器可以随意做任何事情。
  • 如果有人关心具体的例子,无符号溢出被定义为模运算(所以UINT_MAX + 1 == 0)。有符号溢出未定义。现代编译器通常INT_MAX + 1 == INT_MIN,但有些情况你不能指望它(例如for (i = 0; i <= N; ++i) { ... },其中NINT_MAX不是无限的,具体取决于优化;参见blog.llvm.org/2011/05/what-every-c-programmer-should-know.html )。
  • “请注意,某些语义无法在编译时确定,因此必须在运行时进行评估”——我喜欢它与自然语言的相似之处。没有上下文,您无法知道某些短语的含义。例如,在短语“他喜欢香蕉”中,“他”的含义取决于上下文。
【解决方案2】:

语法是指一种语言的结构,将其etymology 追溯到事物的组合方式。
例如,您可能需要通过声明类型、名称和分号来将代码放在一起,以确保语法正确。

Type token;

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

【讨论】:

  • @Talespin_Kit 意义而不是结构:逻辑更多是抽象,例如P => Q 等或 !!P = P,但是当你添加语义时,事情可能会变得微妙,如果 P 是“快乐”,那么 !!P 是“我不是不快乐”!=“我是快乐”
  • +1 表示“编译器或解释器可能会抱怨语法错误。您的同事会抱怨语义。”
【解决方案3】:

维基百科有答案。阅读 syntax (programming languages)semantics (computer science) 维基页面。

或者想想compilerinterpreter 的工作。第一步是lexical analysis,其中通过将字符串划分为词位然后parsing 生成标记,从而构建一些abstract syntax tree(这是语法的表示)。接下来的步骤涉及转换或评估这些 AST(语义)。

另外,请注意,如果您定义了一个 C 的变体,其中每个关键字都转换为其法语等效项(因此 if 变为 sido 变为 faireelse 变为 sinon 等等...) 你肯定会改变你的语言的语法,但你不会改变太多的语义:用法语-C 编程不会更容易!

【讨论】:

    【解决方案4】:

    语义是您的代码的含义——您可以在伪代码中描述的含义。语法是真正的结构——从变量名到分号。

    【讨论】:

    • 是不同人之间的对话吗?或者它只是一个帖子?我不明白。例如“不知道以下应该是什么意思。这再错误不过了”。
    【解决方案5】:
    • 您需要正确的语法进行编译。
    • 您需要正确的语义才能使其发挥作用。

    【讨论】:

      【解决方案6】:

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

      【讨论】:

        【解决方案7】:

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

        务实地,我会区分三个层次:

        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 赋值语句,但在语义上它是一个错误,因为它试图将 int 分配给 String

        String firstName = 23;

        因此,类型系统旨在保护开发人员免于在低级别出现意外的含义失误。

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

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

            type ShoppingCart =
                | EmptyCart  // no data
                | ActiveCart of ActiveCartData
                | PaidCart of PaidCartData
        

        现在编译器可以检查您的代码没有试图将购物车置于非法状态。

        在 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.
        

        在这个(极其简化的)场景中,如果您的系统同时输入两笔 EURUSD 交易、输入方向错误的交易、错误计算交易规模等,您将犯下高级语义错误。

        TL;博士

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

        如果你搞砸了你的高级语义,你的程序就不适合目的,你的客户会抱怨。

        【讨论】:

        • 解释得很好!最后一段是总结。
        【解决方案8】:

        了解编译器如何看待代码

        通常,代码的语法和语义分析在编译器的“前端”部分完成。

        • 语法:编译器为每个关键字和符号生成标记:标记包含关键字的信息类型及其在代码中的位置。 使用这些标记,可以创建和分析 AST(抽象语法树的缩写)。 编译器在这里实际检查的是代码是否具有词法意义,即“关键字序列”是否符合语言规则?正如先前答案中所建议的,您可以将其视为语言的语法(而不是代码的意义/含义)。 旁注:此阶段报告语法错误。(将具有错误类型的令牌返回给系统)

        • 语义:现在,编译器将检查您的代码操作是否“有意义”。 例如如果语言支持类型推断,如果您尝试将字符串分配给浮点数,则会报告语义错误。或两次声明相同的变量。 这些是“语法上”/语法上正确的错误,但在操作期间没有任何意义。 旁注:为了检查同一个变量是否被声明了两次,编译器管理一个symbol table

        因此,这两个前端阶段的输出是带注释的 AST(带有数据类型)和符号表。

        以较少技术性的方式理解它

        考虑到我们使用的正常语言;在这里,英语:

        例如他去学校。 - 不正确的语法/句法,尽管他想传达正确的意义/语义。

        例如他去寒冷。 - 寒冷是一个形容词。在英语中,我们可能会说这不符合语法,但它实际上是我能想到的最接近错误语义和正确语法的例子。

        【讨论】:

        • Compilers此链接可能有助于了解更多信息
        • 解释语言呢?
        • 一个好问题!但我不认为我可以回答这个问题。在我看来,基本上,可以根据工具(实时/交互式或编译器)解释或编译相同的语言。不过,在传统意义上,答案有助于对任何形式的语言给出一个想法。
        【解决方案9】:

        他喝米饭(错误的语义-无意义,正确的句法-语法)

        嗨喝水(正确的语义-有意义,错误的语法-语法)

        【讨论】:

        • 欢迎来到 Stack Overflow。在回答已接受答案(寻找绿色✓)以及其他答案的旧问题之前,请确保您的答案添加了新内容或对它们有帮助。这是How to Answer 的指南。
        【解决方案10】:

        语法 编程语言是其表达式、语句和程序的形式 单位。它的语义是那些表达式、语句和程序单元的含义。例如,Java while 语句的语法是

        while (boolean_expr) statement
        

        这种语句形式的语义是当布尔值的当前值 表达式为真,执行嵌入语句。然后隐式控制 返回布尔表达式以重复该过程。如果布尔表达式 为 false,控制转移到 while 构造之后的语句。

        【讨论】:

          【解决方案11】:

          语法:它指的是语言的语法结构。如果您正在编写c语言。您必须非常小心地使用数据类型、标记 [它可以是文字或符号,如“printf()”。它有 3 个令牌,“printf, (, )”]。同样的,你必须非常小心,你如何使用函数,函数语法,函数声明,定义,初始化和调用它。

          而语义,它涉及句子或语句的逻辑或概念。如果你说或写的东西超出概念或逻辑,那么你在语义上是错误的。

          【讨论】:

            猜你喜欢
            • 2011-03-29
            • 2011-02-09
            • 1970-01-01
            • 2013-07-23
            • 2011-03-25
            • 2015-12-09
            • 2019-05-02
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多