在 Aho Ullman 和 Sethi 的 Compiler Construction 中,给出了将源程序的输入字符串划分为具有逻辑意义的字符序列,称为标记,词位是组成标记的序列,所以是基本的区别吗?
13 回答
使用Aho、Lam、Sethi 和 Ullman 的“编译器原理、技术和工具,第 2 版” (WorldCat) ,又名紫龙书,
词素 pg。111
词位是源程序中与标记模式匹配的字符序列,并被词法分析器识别为该标记的实例。
令牌 pg。111
令牌是由令牌名称和可选属性值组成的对。令牌名称是表示一种词汇单元的抽象符号,例如,特定关键字或表示标识符的输入字符序列。标记名称是解析器处理的输入符号。
模式 pg。111
模式是对标记的词位可能采用的形式的描述。在关键字作为记号的情况下,模式只是形成关键字的字符序列。对于标识符和其他一些标记,模式是由许多字符串匹配的更复杂的结构。
图 3.2:令牌示例 pg.112
[Token] [Informal Description] [Sample Lexemes]
if characters i, f if
else characters e, l, s, e else
comparison < or > or <= or >= or == or != <=, !=
id letter followed by letters and digits pi, score, D2
number any numeric constant 3.14159, 0, 6.02e23
literal anything but ", surrounded by "'s "core dumped"
为了更好地理解这种与词法分析器和解析器的关系,我们将从解析器开始,然后逆向输入。
为了更容易设计解析器,解析器不直接处理输入,而是接收由词法分析器生成的标记列表。查看图 3.2 中的标记列,我们看到诸如if
、else
、comparison
、和;之类的标记id
。这些是令牌的名称。通常,对于词法分析器/解析器,标记是一种结构,它不仅包含标记的名称,还包含组成标记的字符/符号以及组成标记的字符串的开始和结束位置,其中用于错误报告、突出显示等的开始和结束位置。number
literal
现在词法分析器接受字符/符号的输入,并使用词法分析器的规则将输入的字符/符号转换为标记。现在使用词法分析器/解析器的人对他们经常使用的东西有自己的说法。您认为构成标记的字符/符号序列是使用词法分析器/解析器的人所说的词素。因此,当您看到词素时,只需想到代表令牌的一系列字符/符号。在比较示例中,字符/符号的序列可以是不同的模式,例如<
or>
或else
or3.14
等。
考虑两者之间关系的另一种方法是,令牌是解析器使用的编程结构,具有称为词素的属性,用于保存输入中的字符/符号。现在,如果您查看代码中标记的大多数定义,您可能不会将词位视为标记的属性之一。这是因为标记更有可能保存表示标记和词位的字符/符号的开始和结束位置,字符/符号的序列可以根据需要从开始和结束位置导出,因为输入是静态的。
当一个源程序被输入词法分析器时,它首先将字符分解为词素序列。然后将词位用于构建标记,其中词位被映射到标记中。一个名为myVar的变量将被映射到一个表示 < id , "num"> 的标记中,其中 "num" 应该指向变量在符号表中的位置。
简单地说:
- 词位是从字符输入流派生的词。
- 标记是映射到标记名称和属性值的词位。
一个例子包括:
x = a + b * 2
产生词位:{x, =, a, +, b, *, 2}
对应的记号:{< id , 0>, <=>, < id , 1 >, <+>, < id , 2>, <*>, < id , 3>}
LEXEME - 由形成 TOKEN 的 PATTERN 匹配的字符序列
PATTERN - 定义 TOKEN 的规则集
TOKEN - 编程语言字符集上有意义的字符集合,例如:ID、常量、关键字、运算符、标点符号、文字字符串
a) 标记是构成程序文本的实体的符号名称;例如,if 用于关键字 if,id 用于任何标识符。这些构成了词法分析器的输出。5
(b) 模式是指定输入中的字符序列何时构成记号的规则;例如,令牌 if 的序列 i、f 以及令牌 id 以字母开头的任何字母数字序列。
(c) 词位是来自输入的与模式匹配的字符序列(因此构成记号的实例);例如 if 匹配 if 的模式,而 foo123bar 匹配 id 的模式。
Lexeme - 词位是源程序中与标记的模式匹配的字符序列,并被词法分析器识别为该标记的实例。
令牌- 令牌是由令牌名称和可选令牌值组成的对。令牌名称是词汇单元的一个类别。常见的令牌名称是
- 标识符:程序员选择的名称
- 关键字:已经在编程语言中的名称
- 分隔符(也称为标点符号):标点符号和成对分隔符
- 运算符:对参数进行运算并产生结果的符号
- 文字:数字、逻辑、文本、参考文字
考虑编程语言 C 中的这个表达式:
总和 = 3 + 2;
标记化并由下表表示:
Lexeme Token category
------------------------------
sum | Identifier
= | Assignment operator
3 | Integer literal
+ | Addition operator
2 | Integer literal
; | End of statement
Token:(关键字、标识符、标点符号、多字符运算符)的种类,简单来说就是一个Token。
模式:从输入字符形成标记的规则。
Lexeme :它是 SOURCE PROGRAM 中的字符序列,与令牌的模式匹配。基本上,它是 Token 的一个元素。
令牌: 令牌是可以被视为单个逻辑实体的字符序列。典型的标记是,
1) 标识符
2) 关键字
3) 运算符
4) 特殊符号
5) 常量
模式:输入中的一组字符串,为其生成相同的标记作为输出。这组字符串由称为与令牌关联的模式的规则描述。
词位:词位是源程序中与标记模式匹配的字符序列。
让我们看看词法分析器(也称为 Scanner )的工作原理
让我们举个例子:
INPUT : cout << 3+2+3;
FORMATTING PERFORMED BY SCANNER : {cout}|space|{<<}|space|{3}{+}{2}{+}{3}{;}
虽然不是实际输出。
扫描仪简单地重复查找源程序文本中的词汇,直到输入用尽
Lexeme 是输入的子串,形成语法中存在的有效终端字符串。每个词位都遵循最后解释的模式(读者可以跳过的部分)
(重要的规则是寻找形成有效终端字符串的最长可能前缀,直到遇到下一个空格......下面解释)
词法:
- 考特
- <<
(虽然“<”也是有效的终端字符串,但上述规则应选择词位“<<”的模式,以便生成扫描仪返回的令牌)
- 3
- +
- 2
- ;
TOKENS :每次 Scanner 找到一个(有效的)词位时,一次返回一个令牌(当 Parser 请求时由 Scanner )。扫描器创建一个符号表条目(如果尚未存在)(具有属性:主要是令牌类别和少数其他属性),当它找到一个词素时,以生成它的令牌
'#' 表示符号表条目。为了便于理解,我在上面的列表中指出了词位编号,但从技术上讲,它应该是符号表中记录的实际索引。
扫描仪按上述示例的指定顺序将以下标记返回给解析器。
<标识符,#1>
< 运算符 , #2 >
< 字面量 , #3 >
< 运算符 , #4 >
< 字面量 , #5 >
< 运算符 , #4 >
< 字面量 , #3 >
< 标点符号 , #6 >
正如你所看到的不同,一个标记是一对不像词素,词素是输入的子串。
该对的第一个元素是令牌类/类别
下面列出了令牌类:
还有一件事,Scanner 检测到空格,忽略它们并且根本不为空格形成任何标记。并非所有分隔符都是空格,空格是扫描仪用于其目的的分隔符的一种形式。输入中的 Tabs 、 Newlines 、 Spaces 、 Escaped Characters 统称为空白分隔符。很少有其他分隔符是';' ',' ':' 等,它们被广泛认为是形成标记的词位。
此处返回的记号总数为 8,但仅为词位创建了 6 个符号表条目。词素也是8个(见词素的定义)
--- 你可以跳过这部分
A ***pattern*** is a rule ( say, a regular expression ) that is used to check if a string-of-terminals is valid or not
.
If a substring of input composed only of grammar terminals is
following the rule specified by any of the listed patterns , it is
validated as a lexeme and selected pattern will identify the category
of lexeme, else a lexical error is reported due to either (i) not
following any of the rules or (ii) input consists of a bad
terminal-character not present in grammar itself.
for example :
1. No Pattern Exists : In C++ , "99Id_Var" is grammar-supported string-of-terminals but is not recognised by any of patterns hence lexical error is reported .
2. Bad Input Character : $,@,unicode characters may not be supported as a valid character in few programming languages.`
CS 研究人员,就像来自数学的研究人员一样,喜欢创造“新”术语。上面的答案都很好,但显然,没有那么大的需要区分令牌和词位恕我直言。它们就像代表同一事物的两种方式。一个词位是具体的——这里是一组字符;另一方面,标记是抽象的——如果有意义的话,通常指的是词位的类型及其语义值。只是我的两分钱。
Lexeme Lexemes 被称为是记号中的一系列字符(字母数字)。
标记 标记是可以被识别为单个逻辑实体的字符序列。通常,标记是关键字、标识符、常量、字符串、标点符号、运算符。数字。
模式 由称为模式的规则描述的一组字符串。模式解释了什么可以是标记,这些模式是通过与标记相关联的正则表达式定义的。
词法分析器采用一系列字符识别与正则表达式匹配的词位,并将其进一步分类为标记。因此,Lexeme 是匹配的字符串,而 Token 名称是该词位的类别。
例如,考虑下面带有输入“int foo, bar;”的标识符的正则表达式
字母(字母|数字|_)*
在这里,foo
和bar
匹配正则表达式因此都是词位,但被归类为一个标记,ID
即标识符。
还要注意,下一阶段,即语法分析器不必知道词素而是一个标记。
Lexeme 基本上是标记的单元,它基本上是与标记匹配的字符序列,有助于将源代码分解为标记。
例如:如果源是x=b
,则词位是x
, =
,b
而标记是<id, 0>
, <=>
, <id, 1>
。