Java语言的词法分析器的Java实现
一.实验目的
1、 学会针对DFA转换图实现相应的高级语言源程序。
2、 深刻领会状态转换图的含义,逐步理解有限自动机。
3、 掌握手工生成词法分析器的方法,了解词法分析器的内部工作原理。
二.实验内容
Java语言的编译程序的词法分析部分实现。
从左到右扫描每行该语言源程序的符号,拼成单词,换成统一的内部表示送给语法分析程序。
具体的要求如下:
(1) 区分保留字、运算符、常数、界符和标识符
(2) 常数包含整型(正/负)、浮点型(正/负)、字符串和字符。
(3) 空白符是空格、回车符、制表符。
(4) 代码是自由格式。
(5) 注释包含单行注释和多行注释,并且不允许嵌套
程序的记号定义:
表2-1 Java语言记号
|
保留字 |
运算符 |
常数 |
界符 |
标识符 |
||
|
abstract |
assert |
+ |
整数 |
字符串 |
, |
以字母开头, 由字母数字 和下划线组成 |
|
case |
catch |
- |
浮点数 |
字符 |
( |
|
|
continue |
default |
* |
{ |
|||
|
enum |
extends |
= |
[ |
|||
|
for |
goto |
< |
; |
|||
|
instanceof |
int |
> |
) |
|||
|
new |
package |
+= |
} |
|||
|
return |
strictfp |
-= |
] |
|||
|
switch |
synchronized |
*= |
||||
|
transient |
try |
== |
||||
|
boolean |
break |
>= |
||||
|
char |
class |
<= |
||||
|
do |
double |
? |
||||
|
final |
finally |
. |
||||
|
if |
implements |
: |
||||
|
interface |
long |
!= |
||||
|
private |
protected |
|||||
|
short |
static |
|||||
|
this |
throw |
|||||
|
void |
volatile |
|||||
|
byte |
native |
|||||
|
constant |
public |
|||||
|
else |
super |
|||||
|
float |
throws |
|||||
三.实验要求
编译器实现的功能:
(1) 按语法规则将字符识别、分类,并转换成二元式形式打印
(2) 删除注释行(单行、多行)
(3) 删除空白符(空格、回车符、制表符)
(4) 列表打印源程序,按照源程序的行打印,在每行的前面加上行号,并且打印出每行包含的记号的二元形式
(5) 能识别词法错误并定位
Java词法分析进行具体的要求:
(1) 词法分析器每分析出一个完整的词法成分,就将该词法成分的行号和二元式添加到结果字符串info中:。
- 在所有代码分析完毕后,将info中的内容写入result.txt中;
- 若分析的过程中出现错误,则将错误信息和错误定位写入result.txt。
(2) 单词符号分种如下:
- 运算符:运算符分为由单个字符和两个字符组成的运算符。所以对于有可能组成两个运算符的字符,在分析完第一个字符后还要继续分析第二个字符才能分析出完整的运算符。
- 常量:常量又分为数字、字符串、字符。
a) 数字:分为整数,浮点数,且都有正/负两种情况。其中,“正”用数字开头的“+”标识(可省略),“负”用数字开头的“-”标识;
b) 字符串:字符串中允许有转义字符;
c) 字符:合法的字符有:1.单个字符;2.“\”加“b”、“n”、“r”、“t”、“\”;3.“\”加1到3位数字。
- 标识符
- 保留字:标示符和保留字的词法构成相同。识别出字符串后,再根据保留字数组判断该字符串是否为保留字;
- 界符
(3) 词法分析器的具体功能实现是用函数analyze()。每次都根据当前的状态和当前的字符来判断下一步操作,下一步操作有:
- 转换系统状态;
- 读取下一个字符;
- 将当前字符存入字符串中,待该完成词法成分都在字符串中时再生成对应的二元式,并清空字符串。
根据具体情况,下一步操作可同时执行以上三个动作或只执行其中一个或两个。
DFA:

四.代码
package newp2; import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException; public class Lexical {
private static final String reserveWords[] = { "abstract", "boolean", "break", "byte", "case", "catch", "char",
"class", "continue", "default", "do", "double", "else", "extends", "final", "finally", "float", "for", "if",
"implements", "import", "instanceof", "int", "interface", "long", "native", "new", "package", "private",
"protected", "public", "return", "short", "static", "super", "switch", "synchronized", "this", "throw",
"throws", "transient", "try", "void", "volatile", "while", "strictfp", "enum", "goto", "const", "assert" }; // 50
private FileReader fd;
private int state;
private char ch;
private String info; // 结果串
private String temp; // 临时存储
int lineNum; public Lexical() {
info = "";
temp = "";
lineNum = 1;
getChar(); analyze(); write(info);
} private void analyze() {
if (ch == (char) -1 && temp.equals(""))
return; // 已经读取到最后一个字符,且没有待处理字符
if (ch == '\n')
lineNum++; switch (state) {
case 0:
temp = ""; if (ch == ' ' || ch == '\r' || ch == '\t' || ch == '\n') {
toNextCharAndChangeState(0);
} else if (ch == '/') {
toNextCharAndStoreTempAndChangeState(1);
} else if (isDigital(ch)) {
toNextCharAndStoreTempAndChangeState(5);
} else if (isOperator1(ch)) {
toNextCharAndStoreTempAndChangeState(8);
} else if (ch == '!') {
toNextCharAndStoreTempAndChangeState(9);
} else if (isOperator2(ch)) {
writeInfo((ch + ""), "运算符");
getChar();
} else if (isBoundary(ch)) {
writeInfo((ch + ""), "界符");
getChar();
} else if (ch == '"') {
toNextCharAndStoreTempAndChangeState(10);
} else if (isLetter(ch)) {
toNextCharAndStoreTempAndChangeState(11);
} else if (ch == '\'') {
toNextCharAndStoreTempAndChangeState(14);
} else if (ch == '-' || ch == '+') {
toNextCharAndStoreTempAndChangeState(16);
} else if (ch == '|') {
toNextCharAndStoreTempAndChangeState(17);
} else if (ch == '&') {
toNextCharAndStoreTempAndChangeState(18);
} else if (ch == (char) -1) {
// 程序应该结束
} else { // 非法字符
error(1);
return;
}
break;
case 1:
if (ch == '/') {
toNextCharAndChangeState(2);
} else if (ch == '*') {
toNextCharAndChangeState(3);
} else {
state = 8;
}
break;
case 2: // 处理注释
if (ch == '\n') {
state = 0;
getChar();
} else {
getChar();
}
break;
case 3: // 处理注释
if (ch == '*') {
toNextCharAndChangeState(4);
} else {
getChar();
}
break;
case 4: // 处理注释
if (ch == '/') {
toNextCharAndChangeState(0);
} else {
toNextCharAndChangeState(3);
}
break;
case 5:
if (isDigital(ch)) {
temp += ch;
getChar();
} else {
state = 6;
}
break;
case 6:
if (ch == '.') {
toNextCharAndStoreTempAndChangeState(7);
} else {
writeInfo(temp, "常数");
}
break;
case 7:
if (isDigital(ch)) {
toNextCharAndStoreTempAndChangeState(13);
} else {
error(4);
return;
}
break;
case 8:
if (ch == '=') {
temp += ch;
writeInfo(temp, "运算符");
getChar();
} else {
writeInfo(temp, "运算符");
}
break;
case 9:
if (ch == '=') {
temp += ch;
writeInfo(temp, "运算符");
getChar();
} else {
error(2);
return;
}
break;
case 10:
if (ch == '"') {
temp += ch;
writeInfo(temp, "常量");
getChar();
} else if (ch == '\\') {
for (int i = 0; i < 2; i++) {
temp += ch;
getChar();
}
state = 10;
} else {
toNextCharAndStoreTempAndChangeState(10);
}
break;
case 11:
if (isDigital(ch) || isLetter(ch) || ch == '_') {
toNextCharAndStoreTempAndChangeState(11);
} else {
state = 12;
}
break;
case 12:
if (isReserve(temp)) {
writeInfo(temp, "保留字");
getChar();
} else {
writeInfo(temp, "标识符");
getChar();
}
break;
case 13:
if (isDigital(ch)) {
toNextCharAndStoreTempAndChangeState(13);
} else {
writeInfo(temp, "常数");
}
break;
case 14:
if (ch == '\'') {
temp += ch;
if (isLegalChar(temp)) {
writeInfo(temp, "常量");
} else {
error(9);
return;
}
getChar();
} else if (ch == '\\') {
for (int i = 0; i < 2; i++) {
temp += ch;
getChar();
}
state = 14;
} else {
toNextCharAndStoreTempAndChangeState(14);
}
break;
case 16:
if (isDigital(ch)) {
toNextCharAndStoreTempAndChangeState(5);
} else {
state = 8;
}
break;
case 17:
if (ch == '|') {
temp += ch;
writeInfo(temp, "运算符");
getChar();
} else {
writeInfo(temp, "运算符");
}
break;
case 18:
if (ch == '&') {
temp += ch;
writeInfo(temp, "运算符");
getChar();
} else {
writeInfo(temp, "运算符");
}
break;
default:
error(3);
return;
} analyze();
} private boolean isLegalChar(String temp) {
char[] ch = temp.toCharArray();
int length = ch.length;
boolean isLegalChar = false; /*
* Char a = '';// error char b = ' ';// length = 3; char c = '\n';//length = 4;
* b n r t " ' \ char d = '\122'; // length <= 6;
*/
if (length == 2) { // ''
isLegalChar = false;
} else if (length == 3) {
isLegalChar = true;
} else if (length == 4) {
if ((ch[1] == '\\') && (ch[2] == 'b' || ch[2] == 'n' || ch[2] == 'r' || ch[2] == 't' || ch[2] == '\"'
|| ch[2] == '\'' || ch[2] == '\\' || isDigital(ch[2]))) {
isLegalChar = true;
}
} else if (length <= 6) {
if (ch[1] == '\\') {
for (int i = 2; i < (length - 1); i++) {
if (!isDigital(ch[i])) {
isLegalChar = false;
break;
}
isLegalChar = true;
}
} else {
System.out.println('*');
isLegalChar = false;
}
} else {
isLegalChar = false;
} return isLegalChar;
} private void toNextCharAndChangeState(int state) {
this.state = state;
getChar();
} private void toNextCharAndStoreTempAndChangeState(int state) {
temp += ch;
this.state = state;
getChar();
} private boolean isReserve(String temp2) {
for (int i = 0; i < 50; i++) {
if (temp.equals(reserveWords[i])) {
return true;
}
}
return false;
} private void writeInfo(String value, String type) {
info += lineNum + ": < " + type + " , " + value + " >\r\n";
state = 0;
} private boolean isLetter(char ch) {
if ((ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122))
return true;
else
return false;
} private boolean isBoundary(char ch) {
if (ch == ',' || ch == ';' || ch == '(' || ch == ')' || ch == '[' || ch == ']' || ch == '{' || ch == '}')
return true;
return false;
} private boolean isOperator1(char ch) { // / * = < >
if (ch == '/' || ch == '*' || ch == '=' || ch == '<' || ch == '>')
return true;
return false;
} private boolean isOperator2(char ch) { // ? . :
if (ch == '?' || ch == '.' || ch == ':')
return true;
return false;
} private boolean isDigital(char ch) {
if (ch >= 48 && ch <= 57)
return true;
else
return false;
} private void error(int i) {
info = "词法分析出错\r\n错误定位:" + i;
} private void getChar() {
try {
if (fd == null) {
fd = new FileReader("D:/MyEclipse 10 Workspaces/Lexical analyzer/io file/test.txt");
} ch = (char) fd.read(); if (ch == -1) { // 当从一个文件中读取数据时,在数据最后会返回一个int型-1来表示结束
fd.close();
}
} catch (IOException e) { }
} private void write(String info) {
try {
FileWriter fw = new FileWriter("D:/MyEclipse 10 Workspaces/Lexical analyzer/io file/result.txt"); fw.write(info);
fw.flush(); // 刷新数据,将数据写入文件中 fw.close();
} catch (IOException e) { }
} public static void main(String[] args) throws IOException {
new Lexical();
}
}
Java语言的词法分析器的Java实现的更多相关文章
- Java语言的特点以及Java与C/C++的异同
Java语言的特点 1. Java为纯面向对象的语言,能够直接反应现实生活中的对象,容易理解,编程更容易. 2.跨平台,java是解释性语言,编译器会把java代码变成中间代码,然后在JVM上解释执行 ...
- 《快乐编程大本营》java语言训练班 2课:java的变量
<快乐编程大本营>java语言训练班 2课:java的变量 1变量介绍 2变量分类,数值变量 3变量分类-字符串变量 4变量分类-布尔变量 5变量分类-对象 http://code6g.c ...
- Java语言基本语法(一)————关键字&标识符(Java语言标识符命名规范&Java语言的包名、类名、接口名、变量名、函数名、常量名命名规则 )
一.关键字 关键字的定义和特点 定义:被Java语言赋予特殊含义,用做专门用途的字符串(单词). 特点:关键字中所有字母均为小写 下面列举一些常用的关键字. 用于定义数据类型的关键字:byte.sho ...
- java复习要点(一)------- java语言的特点、java的工作原理、配置环境变量、java命令的使用
一.java语言的特点: (1)简单并面向对象 (2)鲁棒并安全: java语言在编译及运行程序时,都要进行严格的检查,防止不匹配问题的发生.如果引用一个非法类型,或执行一个非法类型操作,java减肥 ...
- 2020重新出发,JAVA语言,什么是JAVA?
@ 目录 什么是 java? JAVA三大体系 Java SE Java EE JavaME java的主要特性和优势 1. 面向对象 2. 平台无关性 3. 可移植性 4. 简单性 5. 解释执行 ...
- LeapMotion控制器 java语言开发笔记--(Java开发环境的准备)
(1)官方文档说的是必须是JDK6,JDK7,我试了一下JDK8也是可以的 (2)我是在Windows系统下用的是Eclipse Java的开发环境这里不再多说.将下载的JDK里面的java.dll和 ...
- 《快乐编程大本营》java语言训练班 3课:java的运算符
第1节. 算术运算符 第2节. 递增和递减运算符 第3节. 比较运算符 第4节. 逻辑运算符 第5节. 运算符优先级 第6节. 字符串运算 http://code6g.com/pxphp/px/ban ...
- Java语言程序设计(基础篇)第一章
第一章 计算机.程序和Java概述 1.1 引言 什么是程序设计呢? 程序设计就是创建(或者开发)软件,软件也称为程序. 1.2 什么是计算机 计算机是存储和处理数据的电子设备,计算机包括硬件(har ...
- [Java入门笔记] Java语言简介
前言 学习Java有一段时间了,但是一直缺少一个系统的思想,现在重新通过书籍中.网上的文章,视频等资料,整理与回顾Java的知识点. 言归正传,让我们先从了解Java语言开始. Java语言的由来 J ...
随机推荐
- 什么是 FutureTask?使用 ExecutorService 启动任务?
在 Java 并发程序中 FutureTask 表示一个可以取消的异步运算.它有启动和取消 运算.查询运算是否完成和取回运算结果等方法.只有当运算完成的时候结果才 能取回,如果运算尚未完成 get 方 ...
- Dubbo 必须依赖的包有哪些?
Dubbo 必须依赖 JDK,其他为可选.
- 解释 MySQL 外连接、内连接与自连接的区别 ?
先说什么是交叉连接: 交叉连接又叫笛卡尔积,它是指不使用任何条件,直接将一 个表的所有记录和另一个表中的所有记录一一匹配. 内连接 则是只有条件的交叉连接,根据某个条件筛选出符合条件的记录,不符合 条 ...
- 常见算法的时间复杂度(大O计数法)
定义 对于不同的机器环境而言,确切的单位时间是不同的,但是对于算法进行多少个基本操作(即花费多少时间单位)在规模数量级上却是相同的,由此可以忽略机器环境的影响而客观的反应算法的时间效率. 对于算法 ...
- Spring系列28:@Transactional事务源码分析
本文内容 @Transactional事务使用 @EnableTransactionManagement 详解 @Transactional事务属性的解析 TransactionInterceptor ...
- 判断集合中存在String字符串 或 判断集合中不存在String字符串
一.使用场景 用于集合中有多个相近的字符,无法使用包含判断 如: 这里如果我想判断以上集合中是否包含"信封件-DE"就会被"信封件-DE2"影响到 毕竟:&qu ...
- 一个模仿微信群聊的H5页面
开始 上半年小米Max发布的时候,做了一个在朋友圈传播的模仿微信的群聊界面H5页面:一群公司的大咖在群里聊小米Max,用户可以向大咖们提问,以此了解产品. 页面的主体是群聊对话,同时在对话中包含了很多 ...
- HTML 初学整理
一.HTML简介 HTML的概念 HTML是HyperText Markup Language(超文本标记语言)的简写,超文本标记语言,标准通用标记语言下的一个应用."超文本"就是 ...
- CCF201903-2二十四点
思路描述:最开始的思路是拿一个栈来存储数据和符号,在动手实践的过程中发现行不通,单个数字的char和int转换可以,但是加起来的数据两位数字就很难处理了. 然后就去看了看别人的思路,给了我一个很好的启 ...
- 谷歌开发者工具 Network:Disable cache 和 Preserve log
参考博文地址:https://my.oschina.net/af666/blog/871793 Network Disable cache(禁止缓存):勾上,修改代码之后,刷新页面没有更新,看有没有禁 ...