Javac (J2SE) 编译器的词法分析介绍
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第二章词法分析 (1)
2.1 单词符号的定义 (3)
2.2 词法分析程序的基本数据结构 (4)
2.3 词法分析程序的初始化 (7)
2.4 扫描下一个字符 (8)
2.5 扫描下一个符号 (9)
2.6 滤除源程序中注释 (14)
2.7 读取一个标识符 (15)
2.8 读取一个数值常量 (16)
2.9 词法分析程序运行实例 (17)
3.0 词法分析程序小结 (19)
第二章词法分析
将高级语言翻译成较低级的、面向机器的汇编语言或者某种中间表示,是一件非常复杂和困难的事情。自从IBM的计算机科学家第一次实现Fortran语言的编译器以来,全世界的计算机科学家对编译的技术进行了长期的研究和探索,总结出了一套行之有效的、对一般的高级程序设计语言普遍适用的翻译方法。这套方法的主要思想就是,把高级语言的翻译这个大问题划分为若干个相对容易解决的小问题,然后采用分而治之的策略逐个给出解决的方法。该划分一般是把编译器的主要任务分为:词法分析,语法分析和语义分析。其中词法分析要解决的问题是:从输入文件中读取字符形式的高级语言源程序,并把输入转化为一个由单词符号组成的流供语法分析部分进一步分析。这样使语法分析部分不必关心,例如单词符号如何组成,这样的细节问题,从而简化了语法分析的设计。
词法分析程序要完成的工作有:
过滤掉源程序中空白字符和注释,因为这些信息仅仅增加了源程序的可读性便于程序员阅读和维护程序,而对于语法分析是完全无用的。
识别各种常量,并且把字符形式的表示翻译成编译器的内部表示。
识别标识符和关键字
识别源程序中的各种符号
程序设计语言的单词符号可以用乔姆斯基3型文法,也即正则文法描述。所谓正则文法,其产生式集合中仅含有如下形式的产生式:
α→β α∈Vn, β=a 或者β=aB
其中 a∈Vt, B∈Vn
由这种文法所产生的语言被认为是正则的。由形式语言和自动机理论可知,正则文法与正则表达式是等价的,并且正则文法所描述的语言可以用一种有穷自动机来识别。
下面是正则表达式的递归定义:
(1) Φ是一个表示空集的正则表达式
(2) ε是一个正则表达式,它所表示的语言仅包含一个空符号串,即{ε}
(3) a是一个正则表达式,a∈Vt。它所表示的语言是由单个符号所组成的,即{a}
(4) 如果e1和e2是正则表达式,其表示的语言分别为L1和L2,则:
(e1)|(e2)是一个表示语言L1∪L2的正则表达式
(e1)(e2)是一个表示语言L1L2的正则表达式
{e1}是一个表示语言L1*的正则表达式
确定性有穷自动机,简称作DFA,它的定义如下。
一个确定性有穷自动机M是一个五元式:
M=(Q,Vt,δ,q0,F)
其中:
Q:有穷状态集合
Vt:输入符号表
δ:状态转换函数,为QⅹVt→Q的映射
q0:初始状态,q0∈Q
F:终止状态集,F⊆Q
非确定性有穷自动机,简称NFA,它的定义如下。
一个非确定性有穷自动机M’是一个五元式:
M’=(Q,Vt∪{ε},δ,q0,F)
其中:
Q:有穷状态集合
Vt∪{ε}:输入符号表与空符号串组成的集合
δ:状态转换函数,为QⅹVt∪{ε}→2Q的映射,2Q表示Q的幂集
q0:初始状态,q0∈Q
F:终止状态集,F⊆Q
词法分析程序一般来说比较简单,很容易手工编程实现。另一种方法就是利用lex等自动生成工具来生成。(lex生成的是用C语言来实现的词法分析程序,要生成java语言实现的词法分析程序,可以使用javaCC,它是语法分析程序和词法分析程序的自动生成工具。)使用自动生成工具以后,编译器的构造过程变成了如下形式:(以lex为例)
图2.1 编译器的构造过程
词法分析程序的自动生成器一般采用如下原理工作。它接受以正则表达式为输入形式的对程序设计语言所使用的单词符号的描述。构造一个能够识别这个正则表达式所描述的正则语言的确定性有穷自动机(DFA)。在这个构造过程中,一般来说要借助于非确定性有穷自动机(NFA),也就是说,把正则表达式的描述首先转化为与其等价的非确定性有穷自动机,然后再转化为与其等价的确定性有穷自动机。最后生成(输出)的词法分析程序,就是这个确定性有穷自动机的实现,它能够识别程序设计语言中的各种单词符号。
一般来说,开发一种新语言时,由于它的单词符号在不停地修改,采用lex等工具生成的词法分析程序比较易于修改和维护。一旦一种语言确定了,则采用手工编写词法分析程序效率更高。在gcj中,采用了手工的方式而没有借助任何工具,使用java语言实现了一个java 语言的词法分析程序。
2.1 单词符号的定义
一般来说,不论什么语言实现编译器,都要使用整型的常量来定义各种单词符号。例如在C语言中可以用如下的形式来对单词符号来进行定义:
#define NUMBER 0
#define IDENTIFIER 1
……
下面看一下在GJC中是如何使用java语言来定义各种单词符号的。下面的程序片断出自parser/Tokens.java
1 /**
2 * @(#)Tokens.java 1.11 03/01/23
3 *
4 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
5 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6 */
7 package com.sun.tools.javac.v8.parser;
8
9 /**
10 * An interface that defines codes for Java source tokens
11 * returned from lexical analysis.
12 */
13 public interface Tokens {
14 public static final int EOF = 0;
15 public static final int ERROR = EOF + 1;
16 public static final int IDENTIFIER = ERROR + 1;
17 public static final int ABSTRACT = IDENTIFIER + 1;
18 public static final int ASSERT = ABSTRACT + 1;
19 public static final int BOOLEAN = ASSERT + 1;
20 public static final int BREAK = BOOLEAN + 1;
21 public static final int BYTE = BREAK + 1;
。。。。。。
119 public static final int GTGTEQ = LTLTEQ + 1;
120 public static final int GTGTGTEQ = GTGTEQ + 1;
121 public static final int TokenCount = GTGTGTEQ + 1;
122 }
需要注意在GJC中,对于java语言中的每一个关键字都有一个常量与其对应(例如EOF = 0),而不是采用一个统一的单词符号,例如KEYWORD,来标记它们。