【问题标题】:How are backslash escape sequences implemented in compilers?反斜杠转义序列是如何在编译器中实现的?
【发布时间】:2011-12-26 07:19:49
【问题描述】:

我只是想知道反斜杠转义序列是如何在编译器中实现的? 如果我们在字符串中写“\n”,编译器如何用换行符替换它?编译器如何将“\b”替换为退格符?

我问是因为我写了代码:

#include<stdio.h>
main()
{
    printf("Hello \c");
}

输出是:

你好 退出:退出失败 7

我在键盘上运行它,我正在检查 KnR 书籍问题编号 1.2。

提前致谢

【问题讨论】:

  • 嗨,欢迎来到 StackOverflow。如果您的帖子中有一些代码,您可以通过标记代码并按 ctrl+k 来格式化它

标签: c compiler-construction operating-system embedded-linux


【解决方案1】:

要理解这一点,您必须对编译器的一般工作方式有所了解。编译器通常进行的第一步称为词法分析(或简称词法分析)。词法分析是编译器获取输入代码并将其分解成它可以识别的部分。为此,它通常使用正则表达式来识别不同的部分。它识别的部分之一是字符串文字,它是像"Hello" 这样的带引号的字符串。字符串文字的正则表达式通常看起来像"([^\"]|\"|\\|\n|\b)*"。其中,在英语中,表示以双引号开头并以双引号结尾的字符列表,其间有 1)任何不是双引号或反斜杠的字符 2)反斜杠,然后是双引号引用 3) 一个反斜杠,然后是另一个反斜杠 4) 一个反斜杠,然后是一个 n 5) 一个反斜杠,然后是一个 b。该中间模式重复零次或多次。 (注意:在真正的编译器中,反斜杠后面可能出现的字符列表通常更长)。寻找这个模式可以让它找到字符串文字。

然后,一旦字符串文字被识别出来,要找出实际放入内存的字符串,它必须进行第二层处理,即遍历字符串文字并处理反斜杠。它只是从头到尾读取,寻找反斜杠序列。每个反斜杠序列都替换为不同的字符。 \" 变为 "\\ 变为 \\n 成为换行符。 \b 变为退格字符,依此类推。为了确定将哪个放在哪里,它只使用一个表格来显示为该序列放置什么。

【讨论】:

    【解决方案2】:

    经典的解释在 Ken Thompson 的著名文章'Reflections on Trusting Trust'(也可以从许多othersources,包括书ACM Turing Award Lectures: The First Twenty Years 1966-1985)中得到,这是他获得ACM 图灵奖时的获奖感言和丹尼斯·里奇一起。

    除其他外,它还描述了如何将\v 添加到无法识别它的编译器中:

    C 允许字符串构造指定一个初始化的字符数组。 字符串中的单个字符可以转义以表示 不可打印的字符。例如,

    "Hello world\n"
    

    表示带有字符“\n”的字符串,表示换行 字符。

    图 2.1 是 C 编译器中代码的理想化 解释字符转义序列。这是一个了不起的作品 代码。它以一种完全可移植的方式“知道”什么是字符代码 为任何字符集中的新行编译。那时知道的行为 允许它重新编译自己,从而使知识永存。

    假设我们希望更改 C 编译器以包含序列“\v”到 表示垂直制表符。图 2.1 的扩展是 显而易见,如图 2.2 所示。然后我们重新编译C 编译器,但我们得到了诊断。显然,由于二进制版本 的编译器不知道“\v”,来源不合法 C. 我们 必须“训练”编译器。在它“知道”“\v”是什么意思之后,我们的 新的变化将变得合法 C. 我们在一个 ASCII 图表上查找 垂直制表符是十进制 11。我们将源代码更改为如图所示 2.3.现在旧编译器接受新源。我们安装 生成的二进制文件作为新的官方 C 编译器,现在我们可以编写 便携式版本,如图 2.2 所示。

    这是一个深刻的概念。它和我一样接近“学习”计划 看到。您只需告诉它一次,然后您就可以使用它 自引用定义。

    图2.1

    c = next();
    if (c != '\\')
        return(c);
    c = next();
    if (c == '\\')
        return('\\');
    if (c == 'n')
        return('\n');
    

    图2.2

    c = next();
    if (c != '\\')
        return(c);
    c = next();
    if (c == '\\')
        return('\\');
    if (c == 'n')
        return('\n');
    if (c == 'v')
        return('\v');
    

    图2.3

    c = next();
    if (c != '\\')
        return(c);
    c = next();
    if (c == '\\')
        return('\\');
    if (c == 'n')
        return('\n');
    if (c == 'v')
        return(11);
    

    【讨论】:

    • "找不到对象该服务器上不存在对象 /who/ken/trust.html。"出于这个原因,我通常倾向于 -1 仅链接答案。
    • @Petr:很抱歉谷歌不适合你。感谢您让我知道原始链接已损坏。我提供了许多替代来源,包括作为主要来源的 ACM 网站链接。希望有帮助!
    • Stack Overflow 不是您应该提供给 google 的关键字的集合。这是不受欢迎的仅链接答案的基础知识之一。
    【解决方案3】:

    这里是编译器是什么的一个很好的概述。它列出了组件: Difference between compilers and parsers?

    简短的回答是编译器是一个字符串识别器。它看到与规则匹配的东西(基于上下文),然后决定结果应该是什么。

    这是一个相关的帖子,其中一个帖子还推荐了 Jonathan Leffler 推荐的内容。 What's the Magic Behind Escape(\) Character

    对整个编译器问题的另一个简短回答是语法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-03
      • 2015-03-29
      • 1970-01-01
      • 1970-01-01
      • 2016-06-03
      • 2019-11-12
      相关资源
      最近更新 更多