一个简单词法分析器的实现代码(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) 空格由空白、制表符和换行符组成。空格一般用来分隔IDNUM、运算符、界符和关键字,词法分析阶段通常被忽略。

 

 

                        各种单词符号对应的种别编码

单词符号

种别码

单词符号

种别码

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, tokensum)构成的序列。

  syn为单词种别码;

  token为存放的单词自身字符串;

  sum为整形常数。

  例如:对源程序begin x:=9;if x>0 then x:=2*x+1/3;end# 经词法分析后输出如下序列:(1begin(10,x) (18,:=) (11,9) (26,;) (2,if)……

 

 

 

程图:


一个简单词法分析器的实现代码(java实现)

 源码:


 

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

 

           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow