Tokens做了什么以及为什么需要在C ++编程中创建它们?

时间:2017-11-15 13:03:09

标签: c++ c++11 token

我正在读一本书(Bjarne Stroustrup的编程原则与实践)。

他介绍了Tokens:

“令牌是一系列字符,代表我们认为是单位的东西,例如数字或运算符。这就是C ++编译器处理其源代码的方式。实际上,以某种形式“标记化”是大多数文本分析开始的方式。“

class Token {
public:
    char kind;
    double value;
};

我确实得到了他们的样子,但他从来没有详细解释过这一点,而且对我来说很困惑。

4 个答案:

答案 0 :(得分:7)

标记化对于确定程序的功能非常重要。 Bjarne所指的与C ++源有关的内容涉及程序含义如何受到标记化规则的影响。特别是,我们必须知道令牌是什么,以及它们是如何确定的。具体来说,当一个令牌出现在其他字符旁边时,我们如何识别它?如果存在歧义,我们应该如何划分令牌。

例如,考虑前缀运算符+++。假设我们只有一个令牌+可以使用。以下代码段的含义是什么?

int i = 1;
++i;

仅使用+,上述内容只会在+上两次应用一元i吗?或者它会增加一次?它自然是暧昧的。我们需要一个额外的令牌,因此在语言中引入++作为自己的“单词”。

但现在还有另一个问题(虽然规模较小)。如果程序员希望只应用一次+两次而不是递增,该怎么办?需要令牌处理规则。因此,如果我们确定空格始终是令牌的分隔符,我们的程序员可能会写:

int i = 1;
+ +i;

粗略地说,C ++实现以一个充满字符的文件开始,最初将它们转换为一系列标记(“C ++语言中含有”字样),然后检查标记是否出现在“句子”中有一些有效的意思。

答案 1 :(得分:5)

他正在引用the lexical analysis - 每个编译器的必要部分。它是编译器以有意义的方式处理文本(如:字节序列)的工具。例如,考虑C ++中的以下行

double x  = (15*3.0);  // my variable

当编译器查看文本时,它首先将该行拆分为一系列令牌,如下所示:

Token {"identifier", "double"}
Token {"space", " "}
Token {"identifier", "x"}
Token {"space", "  "}
Token {"operator", "="}
Token {"space", " "}
Token {"separator", "("}
Token {"literal_integer", "15"}
Token {"operator", "*"}
Token {"literal_float", "3.0"}
Token {"separator", ")"}
Token {"separator", ";"}
Token {"space", "  "}
Token {"comment", "// my variable"}
Token {"end_of_line"}

它不必像上面那样解释(请注意,在我的情况下,kindvalue都是字符串),它只是一个例子,它是如何完成的。你通常通过一些正则表达式来做到这一点。

无论如何,对于机器而言,原始文本更容易理解。编译器的下一步是基于标记化创建所谓的abstract syntax tree,最后为所有内容添加含义。

另请注意,除非您正在编写parser,否则您不可能使用此概念。

答案 2 :(得分:2)

正如其他人所说,Bjrane指的是词汇分析。

一般来说,标记化||创建令牌,是一个处理输入流并将它们分成块的过程,而不必担心@StoryTeller早先最好描述的空格等。  "或者如bjrane所说:是一系列字符代表我们认为是单位的字符"。

令牌本身就是C ++用户定义类型的一个例子' UDT'像int或char,因此token可用于定义变量和保存值。

UDT可以包含成员函数和数据成员。在您的代码中,您定义了两个非常基本的成员函数。

1)种类,2)价值

class Token {
public:
   char kind;
   double value;
};

基于它,我们可以初始化或构建它的对象。

Token token_kind_one{'+'};

使用其类型(运算符)' +'初始化token_kind_one。

Token token_kind_two{'8',3.14};

和token_kind_two及其种类(整数/数字)' 8'并且值为3.14。

让我们假设我们有一个10个字符的表达式1 + 2 * 3(5/4),这意味着10个令牌。

令牌:

        |----------------------|---------------------|
Kind    |'8' |'+' |'8' |'*'|'8'|'('|'8' |'/'|'8' |')'|
        |----------------------|---------------------|
Value   | 1  |    | 2  |   | 3 |   | 5  |   | 4  |   |
        |----------------------|---------------------|

C ++编译器将文件数据传输到跳过所有空格的标记序列。让它自己理解。

答案 3 :(得分:-1)

从广义上讲,编译器将在给定源代码上运行多个操作,然后再将其转换为二进制格式。第一阶段之一是运行标记化器,其中源文件的内容被转换为标记,标记是编译器理解的单元。例如,如果您编写语句int a,则标记生成器可能会创建一个结构来存储此信息。

Type: integer
Identifier: A
Reserved Word: No
Line number: 10

这将被称为令牌,源文件中的大多数代码将被分解为类似的结构。