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)……

流程图:

源码:

Java代码  
  1. public class 词法分析 {
  2. /*  初始化数据
  3. syn为单词种别码;
  4. token为存放的单词自身字符串;
  5. sum为整型常数。
  6. */
  7. static String prog;
  8. static char ch;
  9. static char[]token=new char[8];
  10. static int syn,p,m,n,sum;
  11. static //关键字表的初值
  12. String[] rwtable={"begin","if","then","while","do","end"};
  13. /**
  14. * @param args
  15. * @throws IOException
  16. */
  17. public static void main(String[] args) throws IOException {
  18. //1、输入字符串
  19. //prog="begin  x:=9; if x>0  then   x:=2*x+1/3;end #";
  20. //1、从文件中读取字符串
  21. prog=dofile.readFileByChars("src/data.txt");
  22. //2、扫描输出
  23. p=0;
  24. do{
  25. scaner();
  26. switch(syn){
  27. case 11:System.out.print("("+syn+" , ");//单词符号:Digit digit*
  28. System.out.print(sum);
  29. System.out.println(")");
  30. break;
  31. case -1:System.out.println("error!");
  32. break;
  33. default:
  34. System.out.print("(");
  35. System.out.print(syn);
  36. System.out.print(" , ");
  37. String str=new String(token);
  38. System.out.print(str);
  39. System.out.println(")");
  40. }
  41. }while(syn!=0);
  42. }
  43. //扫描程序
  44. private static void scaner() throws IOException {
  45. //      1、初始化
  46. for(int i=0;i<8;i++)
  47. token[i]=' ';
  48. //      2、读字母
  49. ch=prog.charAt(p++);
  50. while(ch==' '){//如果是空格,则取下一个字符
  51. ch=prog.charAt(p++);
  52. }
  53. //      3、开始执行扫描
  54. //          1、是字母
  55. //                     读标识符,查保留字表
  56. //                         查到,换成属性字表,写到输出流
  57. //                         没查到, 查名表,换成属性字,写到输出流
  58. if(ch>='a'&&ch<='z'){
  59. m=0;
  60. //获取完整单词
  61. while((ch>='a'&&ch<='z')||(ch>='0'&&ch<='9')){
  62. token[m++]=ch;
  63. ch=prog.charAt(p++);
  64. }
  65. token[m++]='\0';
  66. --p;
  67. syn=10;//单词符号为letter(letter|digit)*
  68. //判断是哪个关键字
  69. String newStr=new String(token);
  70. newStr=newStr.trim();
  71. //System.out.println("newStr:"+newStr);
  72. for(n=0;n<6;n++){
  73. //System.out.println("rwtable:"+rwtable[n]);
  74. if(newStr.equals(rwtable[n])){
  75. syn=n+1;
  76. System.out.println("syn 的值是:"+syn);
  77. break;
  78. }
  79. }
  80. token[m++]='\0';
  81. }
  82. //          2、是数字
  83. //                         取数字,查常量表,换成属性字表,写到输出流
  84. else if(ch>='0'&&ch<='9'){
  85. while(ch>='0'&&ch<='9'){
  86. sum=sum*10+ch-'0';
  87. ch=prog.charAt(p++);
  88. }
  89. --p;
  90. syn=11;//digitdigit*
  91. token[m++]='\0';
  92. }
  93. //          3、是特殊符号
  94. //                         查特殊符号表,换成属性字。写到输出流
  95. //          4、错误error
  96. //      4、是否分析结束
  97. //              未结束,到2
  98. //              结束,到出口
  99. else
  100. switch(ch){
  101. case'<':
  102. m=0;
  103. token[m++]=ch;
  104. ch=prog.charAt(p++);
  105. if(ch=='>'){
  106. syn=21;//<>
  107. }
  108. else if(ch=='='){
  109. syn=22;//<=
  110. token[m++]=ch;
  111. }
  112. else{
  113. syn=20;//<
  114. --p;
  115. }
  116. break;
  117. case'>':
  118. token[m++]=ch;
  119. ch=prog.charAt(p++);
  120. if(ch=='='){
  121. syn=24;//>=
  122. }
  123. else{
  124. syn=23;//>
  125. --p;
  126. }
  127. break;
  128. case':':
  129. token[m++]=ch;
  130. ch=prog.charAt(p++);
  131. if(ch=='='){
  132. syn=18;//:=
  133. token[m++]=ch;
  134. }
  135. else{
  136. syn=17;//:
  137. --p;
  138. }
  139. break;
  140. case'+':
  141. syn=13;token[0]=ch;token[1]='\0';break;
  142. case'-':
  143. syn=14;token[0]=ch;token[1]='\0';break;
  144. case'*':
  145. syn=15;token[0]=ch;token[1]='\0';break;
  146. case'/':
  147. syn=16;token[0]=ch;token[1]='\0';break;
  148. case'=':
  149. syn=25;token[0]=ch;token[1]='\0';break;
  150. case';':
  151. syn=26;token[0]=ch;token[1]='\0';break;
  152. case'(':
  153. syn=27;token[0]=ch;token[1]='\0';break;
  154. case')':
  155. syn=28;token[0]=ch;token[1]='\0';break;
  156. case'#':
  157. syn=0;token[0]=ch;token[1]='\0';break;
  158. default:
  159. syn=-1;
  160. }
  161. File txt=new File("src/nihao.txt");
  162. if(!txt.exists()){
  163. txt.createNewFile();
  164. }
  165. byte[] bytes=new byte[token.length];//定义一个长度与需要转换的char数组相同的byte数组
  166. for(int i=0;i<bytes.length ;i++){//循环将char的每个元素转换并存放在上面定义的byte数组中
  167. byte b=(byte)token[i];//将每个char转换成byte
  168. bytes[i]=b;//保存到数组中
  169. }
  170. FileOutputStream fos;
  171. try {
  172. fos = new FileOutputStream(txt,true);
  173. fos.write(syn);
  174. fos.write(bytes);
  175. fos.close();
  176. } catch (Exception e) {
  177. e.printStackTrace();
  178. }
  179. }
  180. }
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实现)相关推荐

  1. 从入门到入土:基于C语言采用UDP协议实现远程控制|详细说明|利用流套接字实现一个简单的远程控制系统|代码展示

    此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出.欢迎各位前来交流.(部分材料来源网络,若有侵权,立即删除) 本人博客所有文章纯属学习之用,不涉及商业利益.不合适引用,自当删除! 若 ...

  2. 一个简单的租车系统-----java

    一个简单的租车系统–java 1.创建一个Car父类 定义Car父类的三个属性并封装 package demo; public class Car {private int numbers;//编号p ...

  3. 搭建去中心化交易所——分享一个简单的DEX项目代码及文档

    分享一个简单的DEX项目代码及文档 Dex.top项目源码及文档分享 // DEx.top - Instant Trading on Chain // // Author: DEx.top Teamp ...

  4. 一个简单的winfrom整人代码

    @[TOC]` 安装包下载地址:https://download.csdn.net/download/qq_39883903/11228658 源码下载地址:https://download.csdn ...

  5. java制作一个简单的画板_【Java】Thymeleaf一个简单示例

    Thymeleaf简单介绍 Thymeleaf是用来开发Web和独立环境项目的服务器端的Java模版引擎 Spring官方支持的服务的渲染模板中,并不包含jsp.而是Thymeleaf和Freemar ...

  6. 一个简单音乐播放器的java实现(一)

    写在前面 这几天正在读head first系列的书籍,现在正好读的是java.这本书讲的深入浅出,环环相扣,非常精彩,不妨安利给大家,顺便把我学习过程中的一些心得体会已经实例分享出来. 1.一个最简单 ...

  7. JavaSE基础知识(五)--面向对象代码实现初步(实现一个简单的类类型代码)

    Java SE 是什么,包括哪些内容(五)? 本文内容参考自Java8标准 一.面向对象(代码实现): 首先,在这里我需要说明一个根本性的问题:实际上,面向对象编程包括了两部分,一个是你的编程思想,一 ...

  8. 一个简单的C语言代码段,逻辑题

    最近在练习写C代码,发觉自己真的很喜欢写代码,就分享下自己写的代码,我的代码也是在原有作者的基础上改成自己的代码. 程序猿有一种分享欲,自己一个人闷着,戴着耳机写代码,就想分享出来,希望有人可以看见可 ...

  9. RUN__IT # 一个简单的爬妹子代码送福利(正则表达式总结)

    先来个诱惑再看代码吧!再来复习下正则表达式吧! 代码很简单,若有建议请留言! 案例 import gevent from gevent import monkey import urllib.requ ...

最新文章

  1. calibrate_cameras算子说明
  2. Vue学习(常用实例、脚手架搭建)-学习笔记
  3. linux下Qt编写串口调试助手,如何在linux下用QT写一个简单的串口调试助手
  4. lamp mysql5.0_CentOS 5/6 LAMP(Apache MySQL PHP)一键安装脚本
  5. MySQL数据库的远程连接配置
  6. 优秀博客 --敏感词汇过滤
  7. Intel VMM-虚拟机监控器
  8. Codeforces Round #121 (Div. 1) A. Dynasty Puzzles DP
  9. Nginx负载均衡与反向代理——基础功能
  10. MySql中的count函数
  11. 如何在微博侧栏中加入自己的微博[js]
  12. ZOJ1109_Language of FatMouse(STL/map)
  13. 互联网周刊封面文章:全球网络广告三大趋势
  14. 走好职场每一步:关于求职技巧、跳槽迷思、职场困惑
  15. SDCC编译器 + VSCode开发 8位微控制器
  16. MySQL 英文格式日期转换
  17. Vanishing Point Constrained Lane DetectionWith a Stereo Camera (IEEE 2017)
  18. java加法处理器 图形界面,java作业设置加法器界面
  19. java 小数乘法,乐乐课堂四年级数学网课-四年级下册01-第08讲-四边形分类(1).mp4...
  20. 【进程间通信】Unix domain socket (进程间通信)

热门文章

  1. 【数据结构与算法】之深入解析“求根节点到叶节点数字之和”的求解思路与算法示例
  2. 传阿里旗下蚂蚁集团拟上市集资300亿美元,最快9月IPO
  3. 1037:计算2的幂
  4. 信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言—— 1114:白细胞计数
  5. 【Qt】 Qt中实时更新UI程序示例
  6. 【工业控制】OmniCal软件安装和使用详解
  7. java amqp_AMQP协议
  8. h5封装去底部_干货分享 | 一步一步教你在SpringBoot中集成微信支付H5支付
  9. select选择后生成html,Javascript - 从select中添加选择列表
  10. 专科 java转go 翱翔之路(二)基础语法:匿名组合,方法,接口,map,json,异常处理,channel管道,select用法