编译原理中的词法分析算是很重要的一个部分,原理比较简单,不过网上大部分都是用C语言或者C++来编写,笔者近期在学习Java,故用Java语言实现了简单的词法分析器。

要分析的代码段如下:

输出结果如下:

括号里是一个二元式:(单词类别编码,单词位置编号)

代码如下:

package Yue.LexicalAnalyzer;

import java.io.*;

/*
* 主程序
*/
public class Main {
public static void main(String[] args) throws IOException {
Lexer lexer = new Lexer();
lexer.printToken();
lexer.printSymbolsTable();
}
}
package Yue.LexicalAnalyzer;

import java.io.*;
import java.util.*; /*
* 词法分析并输出
*/
public class Lexer {
/*记录行号*/
public static int line = 1;
/*存放最新读入的字符*/
char character = ' '; /*保留字*/
Hashtable<String, KeyWord> keywords = new Hashtable<String, KeyWord>();
/*token序列*/
private ArrayList<Token> tokens = new ArrayList<Token>();
/*符号表*/
private ArrayList<Symbol> symtable = new ArrayList<Symbol>(); /*读取文件变量*/
BufferedReader reader = null;
/*保存当前是否读取到了文件的结尾*/
private Boolean isEnd = false; /* 是否读取到文件的结尾 */
public Boolean getReaderState() {
return this.isEnd;
} /*打印tokens序列*/
public void printToken() throws IOException {
FileWriter writer = new FileWriter("E:\\lex.txt");
System.out.println("词法分析结果如下:");
System.out.print("杜悦-2015220201031\r\n\n");
writer.write("杜悦-2015220201031\r\n\r\n");
while (getReaderState() == false) {
Token tok = scan();
String str = "line " + tok.line + "\t(" + tok.tag + "," + tok.pos + ")\t\t"
+ tok.name + ": " + tok.toString() + "\r\n";
writer.write(str);
System.out.print(str);
}
writer.flush(); } /*打印符号表*/
public void printSymbolsTable() throws IOException {
FileWriter writer = new FileWriter("E:\\symtab1.txt");
System.out.print("\r\n\r\n符号表\r\n");
System.out.print("编号\t行号\t名称\r\n");
writer.write("符号表\r\n");
writer.write("编号 " + "\t行号 " + "\t名称 \r\n");
Iterator<Symbol> e = symtable.iterator();
while (e.hasNext()) {
Symbol symbol = e.next();
String desc = symbol.pos + "\t" + symbol.line + "\t" + symbol.toString();
System.out.print(desc + "\r\n");
writer.write(desc + "\r\n");
} writer.flush();
} /*打印错误*/
public void printError(Token tok) throws IOException{
FileWriter writer = new FileWriter("E:\\error.txt");
System.out.print("\r\n\r\n错误词法如下:\r\n");
writer.write("错误词法如下:\r\n");
String str = "line " + tok.line + "\t(" + tok.tag + "," + tok.pos + ")\t\t"
+ tok.name + ": " + tok.toString() + "\r\n";
writer.write(str);
} /*添加保留字*/
void reserve(KeyWord w) {
keywords.put(w.lexme, w);
} public Lexer() {
/*初始化读取文件变量*/
try {
reader = new BufferedReader(new FileReader("E:\\输入.txt"));
} catch (IOException e) {
System.out.print(e);
} /*添加保留字*/
this.reserve(KeyWord.begin);
this.reserve(KeyWord.end);
this.reserve(KeyWord.integer);
this.reserve(KeyWord.function);
this.reserve(KeyWord.read);
this.reserve(KeyWord.write);
this.reserve(KeyWord.aIf);
this.reserve(KeyWord.aThen);
this.reserve(KeyWord.aElse);
} /*按字符读*/
public void readch() throws IOException {
character = (char) reader.read();
if ((int) character == 0xffff) {
this.isEnd = true;
}
} /*判断是否匹配*/
public Boolean readch(char ch) throws IOException {
readch();
if (this.character != ch) {
return false;
} this.character = ' ';
return true;
} /*数字的识别*/
public Boolean isDigit() throws IOException {
if (Character.isDigit(character)) {
int value = 0;
while (Character.isDigit(character)) {
value = 10 * value + Character.digit(character, 10);
readch();
} Num n = new Num(value);
n.line = line;
tokens.add(n);
return true;
} else
return false;
} /*保留字、标识符的识别*/
public Boolean isLetter() throws IOException {
if (Character.isLetter(character)) {
StringBuffer sb = new StringBuffer(); /*首先得到整个的一个分割*/
while (Character.isLetterOrDigit(character)) {
sb.append(character);
readch();
} /*判断是保留字还是标识符*/
String s = sb.toString();
KeyWord w = keywords.get(s); /*如果是保留字的话,w不应该是空的*/
if (w != null) {
w.line = line;
tokens.add(w);
} else {
/*否则就是标识符,此处多出记录标识符编号的语句*/
Symbol sy = new Symbol(s);
Symbol mark = sy; //用于标记已存在标识符
Boolean isRepeat = false;
sy.line = line;
for (Symbol i : symtable) {
if (sy.toString().equals(i.toString())) {
mark = i;
isRepeat = true;
}
}
if (!isRepeat) {
sy.pos = symtable.size() + 1;
symtable.add(sy);
} else if (isRepeat) {
sy.pos = mark.pos;
}
tokens.add(sy);
}
return true;
} else
return false;
} /*符号的识别*/
public Boolean isSign() throws IOException {
switch (character) {
case '#':
readch();
AllEnd.allEnd.line = line;
tokens.add(AllEnd.allEnd);
return true;
case '\r':
if (readch('\n')) {
readch();
LineEnd.lineEnd.line = line;
tokens.add(LineEnd.lineEnd);
line++;
return true;
}
case '(':
readch();
Delimiter.lpar.line = line;
tokens.add(Delimiter.lpar);
return true;
case ')':
readch();
Delimiter.rpar.line = line;
tokens.add(Delimiter.rpar);
return true;
case ';':
readch();
Delimiter.sem.line = line;
tokens.add(Delimiter.sem);
return true;
case '+':
readch();
CalcWord.add.line = line;
tokens.add(CalcWord.add);
return true;
case '-':
readch();
CalcWord.sub.line = line;
tokens.add(CalcWord.sub);
return true;
case '*':
readch();
CalcWord.mul.line = line;
tokens.add(CalcWord.mul);
return true;
case '/':
readch();
CalcWord.div.line = line;
tokens.add(CalcWord.div);
return true;
case ':':
if (readch('=')) {
readch();
CalcWord.assign.line = line;
tokens.add(CalcWord.assign);
return true;
}
break;
case '>':
if (readch('=')) {
readch();
CalcWord.ge.line = line;
tokens.add(CalcWord.ge);
return true;
}
break;
case '<':
if (readch('=')) {
readch();
CalcWord.le.line = line;
tokens.add(CalcWord.le);
return true;
}
break;
case '!':
if (readch('=')) {
readch();
CalcWord.ne.line = line;
tokens.add(CalcWord.ne);
return true;
}
break;
}
return false;
} /*下面开始分割关键字,标识符等信息*/
public Token scan() throws IOException {
Token tok;
while (character == ' ')
readch();
if (isDigit() || isSign() || isLetter()) {
tok = tokens.get(tokens.size() - 1);
} else {
tok = new Token(character);
printError(tok);
}
return tok;
}
}
package Yue.LexicalAnalyzer;

/*
* Token父类
*/
public class Token {
public final int tag;
public int line = 1;
public String name = "";
public int pos = 0; public Token(int t) {
this.tag = t;
} public String toString() {
return "" + (char) tag;
} }
package Yue.LexicalAnalyzer;

/*
* 单词类别赋值
*/
public class Tag {
public final static int
BEGIN = 1, //保留字
END = 2, //保留字
INTEGER = 3, //保留字
FUNCTION = 4, //保留字
READ = 5, //保留字
WRITE = 6, //保留字
IF = 7, //保留字
THEN = 8, //保留字
ELSE = 9, //保留字
SYMBOL = 11, //标识符
CONSTANT = 12, //常数
ADD = 13, //运算符 "+"
SUB = 14, //运算符 "-"
MUL = 15, //运算符 "*"
DIV = 16, //运算符 "/"
LE = 18, //运算符 "<="
GE = 19, //运算符 ">="
NE = 20, //运算符 "!="
ASSIGN = 23, //运算符 ":="
LPAR = 24, //界符 "("
RPAR = 25, //界符 ")"
SEM = 26, //界符 ";"
LINE_END = 27, //行尾符
ALL_END = 28; //结尾符 "#"
}
package Yue.LexicalAnalyzer;

/**
* 保留字
*/
public class KeyWord extends Token {
public String lexme = ""; public KeyWord(String s, int t) {
super(t);
this.lexme = s;
this.name = "保留字";
} public String toString() {
return this.lexme;
} public static final KeyWord
begin = new KeyWord("begin", Tag.BEGIN),
end = new KeyWord("end", Tag.END),
integer = new KeyWord("integer", Tag.INTEGER),
function = new KeyWord("function", Tag.FUNCTION),
read = new KeyWord("read", Tag.READ),
write = new KeyWord("write", Tag.WRITE),
aIf = new KeyWord("if", Tag.IF),
aThen = new KeyWord("then", Tag.THEN),
aElse = new KeyWord("else", Tag.ELSE);
}
package Yue.LexicalAnalyzer;

/*
* 标识符
*/
public class Symbol extends Token {
public String lexme = ""; public Symbol(String s) {
super(Tag.SYMBOL);
this.lexme = s;
this.name = "标识符";
} public String toString() {
return this.lexme;
} }
package Yue.LexicalAnalyzer;

/**
* 运算符
*/
public class CalcWord extends Token {
public String lexme = ""; public CalcWord(String s, int t) {
super(t);
this.lexme = s;
this.name = "运算符";
} public String toString() {
return this.lexme;
} public static final CalcWord
add = new CalcWord("+", Tag.ADD),
sub = new CalcWord("-", Tag.SUB),
mul = new CalcWord("*", Tag.MUL),
div = new CalcWord("/", Tag.DIV),
le = new CalcWord("<=", Tag.LE),
ge = new CalcWord(">=", Tag.GE),
ne = new CalcWord("!=", Tag.NE),
assign = new CalcWord(":=", Tag.ASSIGN);
}
package Yue.LexicalAnalyzer;

/**
* 界符
*/
public class Delimiter extends Token {
public String lexme = ""; public Delimiter(String s, int t) {
super(t);
this.lexme = s;
this.name = "界符";
} public String toString() {
return this.lexme;
} public static final Delimiter
lpar = new Delimiter("(", Tag.LPAR),
rpar = new Delimiter(")", Tag.RPAR),
sem = new Delimiter(";", Tag.SEM);
}
package Yue.LexicalAnalyzer;

/*
* 常数
*/
public class Num extends Token {
public final int value; public Num(int v) {
super(Tag.CONSTANT);
this.value = v;
this.name = "常数";
} public String toString() {
return "" + value;
}
}
package Yue.LexicalAnalyzer;

/**
* 行尾符
*/
public class LineEnd extends Token {
public String lexme = ""; public LineEnd(String s) {
super(Tag.LINE_END);
this.lexme = s;
this.name = "行尾符";
} public String toString() {
return this.lexme;
} public static final LineEnd lineEnd = new LineEnd("\r\n");
}
package Yue.LexicalAnalyzer;

/**
* 结尾符
*/
public class AllEnd extends Token {
public String lexme = ""; public AllEnd(String s) {
super(Tag.ALL_END);
this.lexme = s;
this.name = "结尾符";
} public String toString() {
return this.lexme;
} public static final AllEnd allEnd = new AllEnd("#");
}

用Java语言实现简单的词法分析器的更多相关文章

  1. Java语言实现简单FTP软件------>FTP软件主界面的实现(四)

    首先看一下该软件的整体代码框架                        1.首先介绍程序的主入口FTPMain.java,采用了一个漂亮的外观风格 package com.oyp.ftp; im ...

  2. Java语言实现简单FTP软件------>源码放送(十三)

    Java语言实现简单FTP软件------>FTP协议分析(一) Java语言实现简单FTP软件------>FTP软件效果图预览之下载功能(二) Java语言实现简单FTP软件----- ...

  3. Java语言实现简单FTP软件------>上传下载管理模块的实现(十一)

    1.上传本地文件或文件夹到远程FTP服务器端的功能. 当用户在本地文件列表中选择想要上传的文件后,点击上传按钮,将本机上指定的文件上传到FTP服务器当前展现的目录,下图为上传子模块流程图 选择好要上传 ...

  4. Java语言的简单基础

    1.Java 是一种高级程序设计语言. 2.Java 是大小敏感的程序语言. 3.Java 中的 public 修饰的类名一般要与文件名相同,但也有特列:内部类. 4.Java 程序能在任何操作系统中 ...

  5. 设计模式(Java语言)- 简单工厂模式

    简单工厂模式有称为静态工厂模式,属于设计模式中的创建型模式.简单工厂模式通过对外提供一个静态方法来统一为类创建实例.简单工厂模式的目的是实现类与类之间解耦,其次是客户端不需要知道这个对象是如何被穿创建 ...

  6. java语言实现简单接口工具--粗简版

    2016注定是变化的一年,忙碌.网红.项目融资失败,现在有点时间整整帖子~~ 目标: 提高工作效率与质量,能支持平台全量接口回归测试与迭代测试也要满足单一接口联调测试. 使用人员: 测试,开发 工具包 ...

  7. Java语言实现简单FTP软件------>FTP软件本地窗口的实现(五)

    1.首先看一下本地窗口的布局效果 2.看一下本地窗口实现的代码框架 2.本地窗口的具体实现代码LocalPanel.java package com.oyp.ftp.panel.local; impo ...

  8. Java语言实现简单FTP软件------>FTP软件远程窗口的实现(六)

    1.首先看一下远程窗口的布局效果 2.看一下本地窗口实现的代码框架 3.远程窗口主要实现代码FtpPanel.java package com.oyp.ftp.panel.ftp; import ja ...

  9. Java语言实现简单FTP软件------>上传下载队列窗口的实现(七)

    1.首先看一下队列窗口的界面 2.看一下上传队列窗口的界面 3.看一下下载队列窗口的界面 4.队列窗口的实现 package com.oyp.ftp.panel.queue; import stati ...

随机推荐

  1. MSIL实用指南-加载bool、sbyte、byte、char、short等值

    这一篇讲解怎么加载bool值.sbyte值.byte值.char值.short值. 加载bool值在.NET程序实际运行中,是没有true和false值的,实际上是以1和0表示它们,加载它们的指令是L ...

  2. mybatis——分页插件

    1.引入依赖的jar 2.在mybatis的配置文件中注册该插件(如果不注册,PageInfo永远为NULL) 3.使用分页插件

  3. Python爬虫获取异步加载站点pexels并下载图片(Python爬虫实战3)

    1. 异步加载爬虫 对于静态页面爬虫很容易获取到站点的数据内容,然而静态页面需要全量加载站点的所有数据,对于网站的访问和带宽是巨大的挑战,对于高并发和大访问访问量的站点来说,需要使用AJAX相关的技术 ...

  4. Intellij IDEA查看所有断点

    项目中打的断点太多,有时自己也想不到打在哪里了,也不知道哪些方法.哪些代码行上打了断点,在IDEA中如何查看所有断点呢? 方法如下: step 1 IDEA的debug面板中有一个名称为View Br ...

  5. css 如何隐藏滚动条

    原理: 把滚动条设为完全透明: /* 设置滚动条的样式 */::-webkit-scrollbar { width: 12px;} /* 滚动槽 */::-webkit-scrollbar-track ...

  6. iOS 提交审核报错 ERROR ITMS-90087解决办法

    ERROR ITMS-: "Unsupported Architectures. The executable for yht.temp_caseinsensitive_rename.app ...

  7. videojs双击全屏幕观看,videojs动态加载视频

    前段时间闲来无事弄了弄video.js,感觉蛮好玩,能应用到各个应用端,自己在最后玩耍的时候,需要注意的只剩下两方面了,1,动态加载播放视频内容2,双击全屏观看, var urlRoad = &quo ...

  8. 手把手的SpringBoot教程,SpringBoot创建web项目(五)

    这一节,我们来演示如何在SpringBoot项目中连接数据库,并且自动创建一张表. 按照惯例,数据库我们依然使用mysql,至于什么是jpa呢? jpa是sun推出的持久化规范(java persis ...

  9. 笔记:Maven 聚合和继承

    聚合模块 我们希望一次构建两个或更多项目,而不是到每个模块的目录下分别执行mvn命令,Maven 聚合这一特性就是为该需求服务的, 为了使用聚合,我们必须创建一个聚合模块,通过该模块与其他项目聚合,并 ...

  10. Dagger2的基本概念与实际应用。

    本文系原创博客,文中不妥烦请指出,如需转载摘要请注明出处! Dagger2的基本概念与实际应用 Alpha Dog 2016-11-30  10:00:00 本文Demo的github地址:https ...