一个简单词法分析器的实现代码(java实现)
http://www.cnblogs.com/xuqiang/archive/2010/09/21/1953501.html
Main.java
/* * 主程序 */ import java.io.*; import lexer.*; public class Main { public static void main(String[] args) throws IOException { Lexer lexer = new Lexer(); while (lexer.getReaderState() == false) { lexer.scan(); } /* 保存相关信息 */ lexer.saveTokens(); lexer.saveSymbolsTable(); } }
Lexer.java
package lexer; import java.io.*; import java.util.*; import symbols.*; public class Lexer { public static int line = 1; /* 记录行号 */ char peek = ' '; /* 下一个读入字符 */ Hashtable<String, Word> words = new Hashtable<String, Word>(); /* 符号表 */ private Hashtable<Token, String> table = new Hashtable<Token, String>(); /* token序列 */ private List<String> tokens = new LinkedList<String> (); /* 读取文件变量 */ BufferedReader reader = null; /* 保存当前是否读取到了文件的结尾 */ private Boolean isEnd = false; /* 是否读取到文件的结尾 */ public Boolean getReaderState() { return this.isEnd; } /* 保存存储在table中的 */ public void saveSymbolsTable() throws IOException { FileWriter writer = new FileWriter("符号表.txt"); writer.write("[符号] [符号类型信息]\n"); writer.write("\r\n"); Enumeration<Token> e = table.keys(); while( e.hasMoreElements() ){ Token token = (Token)e.nextElement(); String desc = table.get(token); /* 写入文件 */ writer.write(token + "\t\t\t" + desc + "\r\n"); } writer.flush(); } /* 保存Tokens */ public void saveTokens() throws IOException { FileWriter writer = new FileWriter("Tokens表.txt"); writer.write("[符号] \n"); writer.write("\r\n"); for(int i = 0; i < tokens.size(); ++i) { String tok = (String)tokens.get(i); /* 写入文件 */ writer.write(tok + "\r\n"); } writer.flush(); } void reserve(Word w) { words.put(w.lexme, w); } /* * 构造函数中将关键字和类型添加到hashtable words中 */ public Lexer() { /* 初始化读取文件变量 */ try { reader = new BufferedReader(new FileReader("输入.txt")); } catch(IOException e) { System.out.print(e); } /* 关键字 */ this.reserve(new Word("if", Tag.IF)); this.reserve(new Word("then", Tag.THEN)); this.reserve(new Word("else", Tag.ELSE)); this.reserve(new Word("while", Tag.WHILE)); this.reserve(new Word("do", Tag.DO)); /* 类型 */ this.reserve(Word.True); this.reserve(Word.False); this.reserve(Type.Int); this.reserve(Type.Char); this.reserve(Type.Bool); this.reserve(Type.Float); } public void readch() throws IOException { /* 这里应该是使用的是 */ peek = (char)reader.read(); if((int)peek == 0xffff){ this.isEnd = true; } // peek = (char)System.in.read(); } public Boolean readch(char ch) throws IOException { readch(); if (this.peek != ch) { return false; } this.peek = ' '; return true; } public Token scan() throws IOException { /* 消除空白 */ for( ; ; readch() ) { if(peek == ' ' || peek == '\t') continue; else if (peek == '\n') line = line + 1; else break; } /* 下面开始分割关键字,标识符等信息 */ switch (peek) { /* 对于 ==, >=, <=, !=的区分使用状态机实现 */ case '=' : if (readch('=')) { tokens.add("=="); return Word.eq; } else { tokens.add("="); return new Token('='); } case '>' : if (readch('=')) { tokens.add(">="); return Word.ge; } else { tokens.add(">"); return new Token('>'); } case '<' : if (readch('=')) { tokens.add("<="); return Word.le; } else { tokens.add("<"); return new Token('<'); } case '!' : if (readch('=')) { tokens.add("!="); return Word.ne; } else { tokens.add("!"); return new Token('!'); } } /* 下面是对数字的识别,根据文法的规定的话,这里的 * 数字只要是能够识别整数就行. */ if(Character.isDigit(peek)) { int value = 0; do { value = 10 * value + Character.digit(peek, 10); readch(); } while (Character.isDigit(peek)); Num n = new Num(value); tokens.add(n.toString()); //table.put(n, "Num"); return n; } /* * 关键字或者是标识符的识别 */ if(Character.isLetter(peek)) { StringBuffer sb = new StringBuffer(); /* 首先得到整个的一个分割 */ do { sb.append(peek); readch(); } while (Character.isLetterOrDigit(peek)); /* 判断是关键字还是标识符 */ String s = sb.toString(); Word w = (Word)words.get(s); /* 如果是关键字或者是类型的话,w不应该是空的 */ if(w != null) { // table.put(w, "KeyWord or Type"); tokens.add(w.toString()); return w; /* 说明是关键字 或者是类型名 */ } /* 否则就是一个标识符id */ w = new Word(s, Tag.ID); tokens.add(w.toString()); table.put(w, "id"); words.put(s, w); return w; } /* peek中的任意字符都被认为是词法单元返回 */ Token tok = new Token(peek); // table.put(tok, "Token or Seprator"); if ((int)peek != 0xffff ) tokens.add(tok.toString()); peek = ' '; return tok; } }
Num.java
package lexer; public class Num extends Token{ public final int value; public Num(int v) { super(Tag.NUM); this.value = v; } public String toString() { return "" + value; } }
Tag.java
package lexer; public class Tag { public final static int AND = 256, BASIC = 257, BREAK = 258, DO = 259, ELSE = 260, EQ = 261, /* == */ FALSE = 262, GE = 263, ID = 264, IF = 265, INDEX = 266, LE = 267, MINUS = 268, NE = 269, NUM = 270, OR = 271, REAL = 272, TEMP = 273, TRUE = 274, WHILE = 275, /* 后面添加 */ THEN = 276; }
Token.java
package lexer; public class Token { public final int tag; public Token(int t) { this.tag = t; } public String toString() { return "" + (char)tag; } public static void main(String[] args) { Token tok = new Token('a'); System.out.println(tok); } }
Word.java
/* * 类word用于管理保留字,标识符以及像&&这样的复合单词元素 。 */ package lexer; public class Word extends Token { public String lexme = ""; public Word (String s, int t) { super(t); this.lexme = s; } public String toString() { return this.lexme; } public static final Word and = new Word("&&", Tag.AND), or = new Word("||", Tag.OR), eq = new Word ("==", Tag.EQ), ne = new Word("!=", Tag.NE), le = new Word("<=", Tag.LE), ge = new Word(">=", Tag.GE), minus = new Word("minus", Tag.MINUS), True = new Word("true", Tag.TRUE), False = new Word("false", Tag.FALSE), temp = new Word("t", Tag.TEMP); }
Type.java
/* * 说明数据类型 */ package symbols; import lexer.*; public class Type extends Word{ public Type(String s, int tag) { super(s, tag); } public static final Type Int = new Type("int", Tag.BASIC), Float = new Type("float", Tag.BASIC), Char = new Type ("char", Tag.BASIC), Bool = new Type("bool", Tag.BASIC); }
============
http://freewxy.iteye.com/blog/870016
什么是词法?
所谓词法,源代码由字符流组成,字符流中包括关键字,变量名,方法名,括号等等符号,其中变量名要满足不能包括标点符号,不能以数字开头的数字与字母的字符串这个条件,对于括号要成对出现等等,这就是词法;
什么是词法分析?
词法分析阶段是编译过程的第一个阶段。这个阶段的任务是从左到右一个字符一个字符地读入源程序,即对构成源程序的字符流进行扫描然后根据构词规则识别单词(也称单词符号或符号)。
待分析的简单语言的词法:
1) 关键字
begin if then while do end
2) 运算符和界符
:= + - * / < <= > >= <> = ; ( ) #
3) 其他单词是标识符(ID)和整形常数(NUM),通过以下正规式定义:
ID=letter(letter|digit)*
NUM=digitdigit*
4) 空格由空白、制表符和换行符组成。空格一般用来分隔ID、NUM、运算符、界符和关键字,词法分析阶段通常被忽略。
各种单词符号对应的种别编码
单词符号 |
种别码 |
单词符号 |
种别码 |
begin |
1 |
: |
17 |
if |
2 |
:= |
18 |
then |
3 |
< |
20 |
while |
4 |
<> |
21 |
do |
5 |
<= |
22 |
end |
6 |
> |
23 |
letter(letter|digit)* |
10 |
>= |
24 |
digitdigit* |
11 |
= |
25 |
+ |
13 |
; |
26 |
- |
14 |
( |
27 |
* |
15 |
) |
28 |
/ |
16 |
# |
0 |
词法分析程序的功能:
输入:所给文法的源程序字符串
输出:二元组(syn, token或sum)构成的序列。
syn为单词种别码;
token为存放的单词自身字符串;
sum为整形常数。
例如:对源程序begin x:=9;if x>0 then x:=2*x+1/3;end# 经词法分析后输出如下序列:(1,begin)(10,’x’) (18,:=) (11,9) (26,;) (2,if)……
流程图:
源码:
- public class 词法分析 {
- /* 初始化数据
- syn为单词种别码;
- token为存放的单词自身字符串;
- sum为整型常数。
- */
- static String prog;
- static char ch;
- static char[]token=new char[8];
- static int syn,p,m,n,sum;
- static //关键字表的初值
- String[] rwtable={"begin","if","then","while","do","end"};
- /**
- * @param args
- * @throws IOException
- */
- public static void main(String[] args) throws IOException {
- //1、输入字符串
- //prog="begin x:=9; if x>0 then x:=2*x+1/3;end #";
- //1、从文件中读取字符串
- prog=dofile.readFileByChars("src/data.txt");
- //2、扫描输出
- p=0;
- do{
- scaner();
- switch(syn){
- case 11:System.out.print("("+syn+" , ");//单词符号:Digit digit*
- System.out.print(sum);
- System.out.println(")");
- break;
- case -1:System.out.println("error!");
- break;
- default:
- System.out.print("(");
- System.out.print(syn);
- System.out.print(" , ");
- String str=new String(token);
- System.out.print(str);
- System.out.println(")");
- }
- }while(syn!=0);
- }
- //扫描程序
- private static void scaner() throws IOException {
- // 1、初始化
- for(int i=0;i<8;i++)
- token[i]=' ';
- // 2、读字母
- ch=prog.charAt(p++);
- while(ch==' '){//如果是空格,则取下一个字符
- ch=prog.charAt(p++);
- }
- // 3、开始执行扫描
- // 1、是字母
- // 读标识符,查保留字表
- // 查到,换成属性字表,写到输出流
- // 没查到, 查名表,换成属性字,写到输出流
- if(ch>='a'&&ch<='z'){
- m=0;
- //获取完整单词
- while((ch>='a'&&ch<='z')||(ch>='0'&&ch<='9')){
- token[m++]=ch;
- ch=prog.charAt(p++);
- }
- token[m++]='\0';
- --p;
- syn=10;//单词符号为letter(letter|digit)*
- //判断是哪个关键字
- String newStr=new String(token);
- newStr=newStr.trim();
- //System.out.println("newStr:"+newStr);
- for(n=0;n<6;n++){
- //System.out.println("rwtable:"+rwtable[n]);
- if(newStr.equals(rwtable[n])){
- syn=n+1;
- System.out.println("syn 的值是:"+syn);
- break;
- }
- }
- token[m++]='\0';
- }
- // 2、是数字
- // 取数字,查常量表,换成属性字表,写到输出流
- else if(ch>='0'&&ch<='9'){
- while(ch>='0'&&ch<='9'){
- sum=sum*10+ch-'0';
- ch=prog.charAt(p++);
- }
- --p;
- syn=11;//digitdigit*
- token[m++]='\0';
- }
- // 3、是特殊符号
- // 查特殊符号表,换成属性字。写到输出流
- // 4、错误error
- // 4、是否分析结束
- // 未结束,到2
- // 结束,到出口
- else
- switch(ch){
- case'<':
- m=0;
- token[m++]=ch;
- ch=prog.charAt(p++);
- if(ch=='>'){
- syn=21;//<>
- }
- else if(ch=='='){
- syn=22;//<=
- token[m++]=ch;
- }
- else{
- syn=20;//<
- --p;
- }
- break;
- case'>':
- token[m++]=ch;
- ch=prog.charAt(p++);
- if(ch=='='){
- syn=24;//>=
- }
- else{
- syn=23;//>
- --p;
- }
- break;
- case':':
- token[m++]=ch;
- ch=prog.charAt(p++);
- if(ch=='='){
- syn=18;//:=
- token[m++]=ch;
- }
- else{
- syn=17;//:
- --p;
- }
- break;
- case'+':
- syn=13;token[0]=ch;token[1]='\0';break;
- case'-':
- syn=14;token[0]=ch;token[1]='\0';break;
- case'*':
- syn=15;token[0]=ch;token[1]='\0';break;
- case'/':
- syn=16;token[0]=ch;token[1]='\0';break;
- case'=':
- syn=25;token[0]=ch;token[1]='\0';break;
- case';':
- syn=26;token[0]=ch;token[1]='\0';break;
- case'(':
- syn=27;token[0]=ch;token[1]='\0';break;
- case')':
- syn=28;token[0]=ch;token[1]='\0';break;
- case'#':
- syn=0;token[0]=ch;token[1]='\0';break;
- default:
- syn=-1;
- }
- File txt=new File("src/nihao.txt");
- if(!txt.exists()){
- txt.createNewFile();
- }
- byte[] bytes=new byte[token.length];//定义一个长度与需要转换的char数组相同的byte数组
- for(int i=0;i<bytes.length ;i++){//循环将char的每个元素转换并存放在上面定义的byte数组中
- byte b=(byte)token[i];//将每个char转换成byte
- bytes[i]=b;//保存到数组中
- }
- FileOutputStream fos;
- try {
- fos = new FileOutputStream(txt,true);
- fos.write(syn);
- fos.write(bytes);
- fos.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
public class 词法分析 {
/* 初始化数据
syn为单词种别码;
token为存放的单词自身字符串;
sum为整型常数。
*/
static String prog;
static char ch;
static char[]token=new char[8];
static int syn,p,m,n,sum;
static //关键字表的初值
String[] rwtable={"begin","if","then","while","do","end"};
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//1、输入字符串
//prog="begin x:=9; if x>0 then x:=2*x+1/3;end #";
//1、从文件中读取字符串
prog=dofile.readFileByChars("src/data.txt");
//2、扫描输出
p=0;
do{
scaner();
switch(syn){
case 11:System.out.print("("+syn+" , ");//单词符号:Digit digit*
System.out.print(sum);
System.out.println(")");
break;
case -1:System.out.println("error!");
break;
default:
System.out.print("(");
System.out.print(syn);
System.out.print(" , ");
String str=new String(token);
System.out.print(str);
System.out.println(")");
}
}while(syn!=0);
}
//扫描程序
private static void scaner() throws IOException {
// 1、初始化
for(int i=0;i<8;i++)
token[i]=' ';
// 2、读字母
ch=prog.charAt(p++);
while(ch==' '){//如果是空格,则取下一个字符
ch=prog.charAt(p++);
}
// 3、开始执行扫描
// 1、是字母
// 读标识符,查保留字表
// 查到,换成属性字表,写到输出流
// 没查到, 查名表,换成属性字,写到输出流
if(ch>='a'&&ch<='z'){
m=0;
//获取完整单词
while((ch>='a'&&ch<='z')||(ch>='0'&&ch<='9')){
token[m++]=ch;
ch=prog.charAt(p++);
}
token[m++]='\0';
--p;
syn=10;//单词符号为letter(letter|digit)*
//判断是哪个关键字
String newStr=new String(token);
newStr=newStr.trim();
//System.out.println("newStr:"+newStr);
for(n=0;n<6;n++){
//System.out.println("rwtable:"+rwtable[n]);
if(newStr.equals(rwtable[n])){
syn=n+1;
System.out.println("syn 的值是:"+syn);
break;
}
}
token[m++]='\0';
}
// 2、是数字
// 取数字,查常量表,换成属性字表,写到输出流
else if(ch>='0'&&ch<='9'){
while(ch>='0'&&ch<='9'){
sum=sum*10+ch-'0';
ch=prog.charAt(p++);
}
--p;
syn=11;//digitdigit*
token[m++]='\0';
}
// 3、是特殊符号
// 查特殊符号表,换成属性字。写到输出流
// 4、错误error
// 4、是否分析结束
// 未结束,到2
// 结束,到出口
else
switch(ch){
case'<':
m=0;
token[m++]=ch;
ch=prog.charAt(p++);
if(ch=='>'){
syn=21;//<>
}
else if(ch=='='){
syn=22;//<=
token[m++]=ch;
}
else{
syn=20;//<
--p;
}
break;
case'>':
token[m++]=ch;
ch=prog.charAt(p++);
if(ch=='='){
syn=24;//>=
}
else{
syn=23;//>
--p;
}
break;
case':':
token[m++]=ch;
ch=prog.charAt(p++);
if(ch=='='){
syn=18;//:=
token[m++]=ch;
}
else{
syn=17;//:
--p;
}
break;
case'+':
syn=13;token[0]=ch;token[1]='\0';break;
case'-':
syn=14;token[0]=ch;token[1]='\0';break;
case'*':
syn=15;token[0]=ch;token[1]='\0';break;
case'/':
syn=16;token[0]=ch;token[1]='\0';break;
case'=':
syn=25;token[0]=ch;token[1]='\0';break;
case';':
syn=26;token[0]=ch;token[1]='\0';break;
case'(':
syn=27;token[0]=ch;token[1]='\0';break;
case')':
syn=28;token[0]=ch;token[1]='\0';break;
case'#':
syn=0;token[0]=ch;token[1]='\0';break;
default:
syn=-1;
}
File txt=new File("src/nihao.txt");
if(!txt.exists()){
txt.createNewFile();
}
byte[] bytes=new byte[token.length];//定义一个长度与需要转换的char数组相同的byte数组
for(int i=0;i<bytes.length ;i++){//循环将char的每个元素转换并存放在上面定义的byte数组中
byte b=(byte)token[i];//将每个char转换成byte
bytes[i]=b;//保存到数组中
}
FileOutputStream fos;
try {
fos = new FileOutputStream(txt,true);
fos.write(syn);
fos.write(bytes);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
文件data.txt中的内容为:
begin x:=9; if x>0 then x:=2*x+1/3;end #
程序执行结果(控制台输出):
打开文件 src/data.txt 读取内容为:
beginx:=9;ifx>0thenx:=2*x+1/3;end#
syn 的值是:1
(1 , begin)
(10,x)
(18,:=)
(11,9)
(26,;)
syn的值是:2
(2,if)
(10,x)
(23,>)
(11,90)
syn的值是:3
(3,then)
(10,x)
(13,+)
(11,902)
(15,*)
(10,x)
(13,+)
(11,9021)
(16,)
(11,90213)
(26,;)
syn的值是:6
(6,end)
(0,#)
<!--EndFragment-->
一个简单词法分析器的实现代码(java实现)相关推荐
- 从入门到入土:基于C语言采用UDP协议实现远程控制|详细说明|利用流套接字实现一个简单的远程控制系统|代码展示
此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出.欢迎各位前来交流.(部分材料来源网络,若有侵权,立即删除) 本人博客所有文章纯属学习之用,不涉及商业利益.不合适引用,自当删除! 若 ...
- 一个简单的租车系统-----java
一个简单的租车系统–java 1.创建一个Car父类 定义Car父类的三个属性并封装 package demo; public class Car {private int numbers;//编号p ...
- 搭建去中心化交易所——分享一个简单的DEX项目代码及文档
分享一个简单的DEX项目代码及文档 Dex.top项目源码及文档分享 // DEx.top - Instant Trading on Chain // // Author: DEx.top Teamp ...
- 一个简单的winfrom整人代码
@[TOC]` 安装包下载地址:https://download.csdn.net/download/qq_39883903/11228658 源码下载地址:https://download.csdn ...
- java制作一个简单的画板_【Java】Thymeleaf一个简单示例
Thymeleaf简单介绍 Thymeleaf是用来开发Web和独立环境项目的服务器端的Java模版引擎 Spring官方支持的服务的渲染模板中,并不包含jsp.而是Thymeleaf和Freemar ...
- 一个简单音乐播放器的java实现(一)
写在前面 这几天正在读head first系列的书籍,现在正好读的是java.这本书讲的深入浅出,环环相扣,非常精彩,不妨安利给大家,顺便把我学习过程中的一些心得体会已经实例分享出来. 1.一个最简单 ...
- JavaSE基础知识(五)--面向对象代码实现初步(实现一个简单的类类型代码)
Java SE 是什么,包括哪些内容(五)? 本文内容参考自Java8标准 一.面向对象(代码实现): 首先,在这里我需要说明一个根本性的问题:实际上,面向对象编程包括了两部分,一个是你的编程思想,一 ...
- 一个简单的C语言代码段,逻辑题
最近在练习写C代码,发觉自己真的很喜欢写代码,就分享下自己写的代码,我的代码也是在原有作者的基础上改成自己的代码. 程序猿有一种分享欲,自己一个人闷着,戴着耳机写代码,就想分享出来,希望有人可以看见可 ...
- RUN__IT # 一个简单的爬妹子代码送福利(正则表达式总结)
先来个诱惑再看代码吧!再来复习下正则表达式吧! 代码很简单,若有建议请留言! 案例 import gevent from gevent import monkey import urllib.requ ...
最新文章
- calibrate_cameras算子说明
- Vue学习(常用实例、脚手架搭建)-学习笔记
- linux下Qt编写串口调试助手,如何在linux下用QT写一个简单的串口调试助手
- lamp mysql5.0_CentOS 5/6 LAMP(Apache MySQL PHP)一键安装脚本
- MySQL数据库的远程连接配置
- 优秀博客 --敏感词汇过滤
- Intel VMM-虚拟机监控器
- Codeforces Round #121 (Div. 1) A. Dynasty Puzzles DP
- Nginx负载均衡与反向代理——基础功能
- MySql中的count函数
- 如何在微博侧栏中加入自己的微博[js]
- ZOJ1109_Language of FatMouse(STL/map)
- 互联网周刊封面文章:全球网络广告三大趋势
- 走好职场每一步:关于求职技巧、跳槽迷思、职场困惑
- SDCC编译器 + VSCode开发 8位微控制器
- MySQL 英文格式日期转换
- Vanishing Point Constrained Lane DetectionWith a Stereo Camera (IEEE 2017)
- java加法处理器 图形界面,java作业设置加法器界面
- java 小数乘法,乐乐课堂四年级数学网课-四年级下册01-第08讲-四边形分类(1).mp4...
- 【进程间通信】Unix domain socket (进程间通信)
热门文章
- 【数据结构与算法】之深入解析“求根节点到叶节点数字之和”的求解思路与算法示例
- 传阿里旗下蚂蚁集团拟上市集资300亿美元,最快9月IPO
- 1037:计算2的幂
- 信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言—— 1114:白细胞计数
- 【Qt】 Qt中实时更新UI程序示例
- 【工业控制】OmniCal软件安装和使用详解
- java amqp_AMQP协议
- h5封装去底部_干货分享 | 一步一步教你在SpringBoot中集成微信支付H5支付
- select选择后生成html,Javascript - 从select中添加选择列表
- 专科 java转go 翱翔之路(二)基础语法:匿名组合,方法,接口,map,json,异常处理,channel管道,select用法