词法分析器——java实现

2018java面试题100道
2017年4月27日
语法分析器——java实现
2017年5月20日

本人博客内编译原理文章的配套资源jar包,包括词法分析,语法分析,中间代码生成,静态语义检查,代码解释执行以及抽象语法树的手动生成:https://download.csdn.net/download/as1072966956/10448935

转载请注明出处。

 

Token.java

[java] view plain copy

  1. package sch.cauc.edu.token;  
  2.   
     
  3. /** 
  4.  *  
  5.  *  
  6.  * Token 
  7.  * 创建人:xrzhang  
  8.  * 时间:2018510上午9:11:26  
  9.  * @version 1.0.0 
  10.  * 
  11.  */  
  12.   
     
  13. public class Token {  
  14.     private TokenType type;  
  15.     private String token;  
  16.     private int line;  
  17.     private int column;  
  18.     /** 
  19.      *  
  20.      * 词法记号的构造器 
  21.      * @param type  词法记号的类型 
  22.      * @param token  词法记号的串值 
  23.      * @param line   词法记号所在的行号,用于调试和检查输出 
  24.      * @param column 词法记号所在的列号,用于调试和检查输出 
  25.      */  
  26.     public Token(TokenType type,String token,int line,int column) {  
  27.           
     
  28.         this.line = line;  
  29.         this.type = type;  
  30.         this.token = token;  
  31.         this.column = column;  
  32.     }  
  33.     public TokenType getType(){  
  34.         return type;  
  35.     }  
  36.     public int getLine(){  
  37.         return line;  
  38.     }  
  39.     public int getColumn(){  
  40.         return column;  
  41.     }  
  42.     public String getLexeme(){  
  43.         return token;  
  44.     }  
  45.     /** 
  46.      *  
  47.      * 输出当前词法记号的信息,包括类型、串值、行号和列号 
  48.      * 方法名:toStrong 
  49.      * 创建人:xrzhang  
  50.      * 时间:2018510上午9:16:13  
  51.      * 邮件:jmzhang_15_cauc@163.com 
  52.      * @return String  字符串标识的词法记号信息 
  53.      * @exception  
  54.      * @since  1.0.0 
  55.      */  
  56.     public String toString() {  
  57.         return type+” “+token+” (“+line+“,”+column+“)”;  
  58.     }  
  59. }  
  60.   
     
  61. enum TokenType{  
  62.     /**忽略的词法单位**/  
  63.       
     
  64.     IGNORE,  
  65.     /**变量**/  
  66.     IDENTIFIER,      //标识符  
  67.       
     
  68.     /**常量**/  
  69.     INTEGER_LITERAL,  //整型常量  
  70.     BOOL_TRUE,          //true  
  71.     BOOL_FALSE,         //false  
  72.       
     
  73.     /**保留字**/  
  74.     KEY_INT,   //int  
  75.     KEY_BOOLEAN,//boolean  
  76.     KEY_WHILE,  //while  
  77.     KEY_IF,     //if  
  78.     KEY_ELSE,   //else  
  79.       
     
  80.     /**算术运算符**/  
  81.     PLUS,  //+  
  82.     MINUS,  //-  
  83.     TIMES,  //*  
  84.     DIVIDE, ///  
  85.     REMAINDER,//%取模  
  86.       
     
  87.     /**关系运算符**/  
  88.     LESS,     //<  
  89.     GREATER,    //>  
  90.     LESS_EQUAL,  //<=  
  91.     GREATER_EQUAL, //>=  
  92.     NOT_EQUAL,   //!=  
  93.     EQUAL,   ///==  
  94.       
     
  95.     /**逻辑运算符**/  
  96.     LOGICAL_NOT,  //  
  97.     LOGICAL_AND,  //&&  
  98.     LOGICAL_OR,  //||  
  99.       
     
  100.     /**赋值符号**/  
  101.     ASSIGN,    //=  
  102.       
     
  103.     /**括号**/  
  104.     LPAREN,   //(  
  105.     RPAREN,   //)  
  106.     LBRACKET, //{  
  107.     RBRACKET, //}  
  108.       
     
  109.     /**界符**/  
  110.     COMMA,   //逗号,  
  111.     SEMICOLON,  //分号;  
  112.       
     
  113.     /**文件结尾符**/  
  114.     EOF,  
  115.       
     
  116.     /**注释*/  
  117.     NOTE  
  118. }  

BlockLexer.java

[java] view plain copy

  1. package sch.cauc.edu.token;  
  2.   
     
  3. import java.io.FileReader;  
  4. import java.io.IOException;  
  5. import java.io.PushbackReader;  
  6.   
     
  7. /** 
  8.  * Block 语言的词法分析器类 
  9.  * <p>你需要在实验中扩张nextToken方法,是该词法分析器真正能识别Block语言中的各 
  10.  * 种词法几号并跳过注释和空白符 
  11.  * </p> 
  12.  * BlockLexer 
  13.  * 创建人:xrzhang  
  14.  * 时间:2018510上午8:43:55  
  15.  * @version 1.0.0 
  16.  * 
  17.  */  
  18. public class BlockLexer {  
  19.     /**一个可回退的读取器*/  
  20. private PushbackReader in=null;  
  21.       
     
  22.     /**词法分析的当前状态*/  
  23.     private int state =0;  
  24.       
     
  25.     /**词法分析的初始状态*/  
  26.     private int  start=0;  
  27.       
     
  28.     /**当前记号对应的串值*/  
  29.     private  StringBuffer lexeme=new StringBuffer();  
  30.       
     
  31.     /**当前面临的输入字符*/  
  32.     private char c;  
  33.       
     
  34.     /**当前在输入文件中的行号*/  
  35.     private int line=0;  
  36.       
     
  37.     /**当前在输入文件中的列号*/  
  38.     private int column=0;  
  39.       
     
  40.     /** 
  41.      * 词法分析器的构造器 
  42.      * 创建一个新的实例 BlockLexer. 
  43.      * @param infile   输入文件名 
  44.      */  
  45.     public BlockLexer(String infile) {  
  46.         PushbackReader reader=null;  
  47.          try {  
  48.             reader=new PushbackReader(new FileReader(infile));  
  49.         } catch (IOException e) {  
  50.             e.printStackTrace();  
  51.             System.exit(-1);  
  52.         }  
  53.         in=reader;  
  54.     }  
  55.     /** 
  56.      *  
  57.      * 取得下一个字符 
  58.      * 方法名:nextChar 
  59.      * 创建人:xrzhang  
  60.      * 时间:2018516上午8:28:00  
  61.      * 邮件:jmzhang_15_cauc@163.com void 
  62.      * @exception  
  63.      * @since  1.0.0 
  64.      */  
  65.     private void nextChar() {  
  66.         try {  
  67.             c=(char)in.read();  
  68.             lexeme.append(c);  
  69.             column++;  
  70.         } catch (IOException e) {  
  71.             e.printStackTrace();  
  72.             System.exit(-1);  
  73.         }  
  74.           
     
  75.         }  
  76.     /** 
  77.      *  
  78.      * 回退一个字符 
  79.      * 方法名:pushbackChar 
  80.      * 创建人:xrzhang  
  81.      * 时间:2018516上午8:28:16  
  82.      * 邮件:jmzhang_15_cauc@163.com void 
  83.      * @exception  
  84.      * @since  1.0.0 
  85.      */  
  86.     private void pushbackChar() {  
  87.         try {  
  88.             in.unread(lexeme.charAt(lexeme.length()-1));  
  89.             lexeme.deleteCharAt(lexeme.length()-1);  
  90.             column–;  
  91.               
     
  92.         } catch (IOException e) {  
  93.             e.printStackTrace();  
  94.             System.exit(-1);  
  95.         }  
  96.     }  
  97.     /** 
  98.      *  
  99.      * 取得记号,并重置状态变量 
  100.      * 方法名:getToken 
  101.      * 创建人:xrzhang  
  102.      * 时间:2018516上午8:28:40  
  103.      * 邮件:jmzhang_15_cauc@163.com 
  104.      * @param type 
  105.      * @return Token 
  106.      * @exception  
  107.      * @since  1.0.0 
  108.      */  
  109.    private Token getToken(TokenType type) {  
  110.     state=0;  
  111.     start=0;  
  112.     String t=lexeme.toString();  
  113.     lexeme.setLength(0);  
  114.       
     
  115.     return new Token(type,t,line+1,column-t.length()+1);  
  116. }  
  117.  /** 
  118.   *    
  119.   * 扔掉一个字符 
  120.   * 方法名:dropChar 
  121.   * 创建人:xrzhang  
  122.   * 时间:2018516上午8:29:11  
  123.   * 邮件:jmzhang_15_cauc@163.com void 
  124.   * @exception  
  125.   * @since  1.0.0 
  126.   */  
  127.    private void dropChar() {  
  128.     lexeme.setLength(0);  
  129. }  
  130.       
     
  131.     public Token nextToken(){  
  132.         while(true){  
  133.             switch(state){  
  134.             case 0:  
  135.                 //获取下一个字符  
  136.                 nextChar();  
  137.                 //判断是否空白  
  138.                 if(Character.isWhitespace(c)){  
  139.                     if(c==‘\n’)  
  140.                     {  
  141.                         line++;  
  142.                         column = 0;  
  143.                     }  
  144.                     dropChar();  
  145.                 }else if (Character.isDigit(c)) //数字  
  146.                 {  
  147.                     state=1;      
  148.                 }else if(Character.isLetter(c))  //字母  
  149.                 {  
  150.                     state =3;  
  151.                 }else if (c==‘+’) {  
  152.                     return getToken(TokenType.PLUS);  
  153.                 }else if (c==‘-‘) {  
  154.                     return getToken(TokenType.MINUS);  
  155.                 }else if (c==‘*’) {  
  156.                     return getToken(TokenType.TIMES);  
  157.                 }else if (c==‘/’) {  
  158.                     nextChar();  
  159.                     if(c==‘*’)  
  160.                     {  
  161.                         while(true)  
  162.                         {  
  163.                             nextChar();  
  164.                             if(c==‘*’)  
  165.                             {  
  166.                                 nextChar();  
  167.                                 if(c==‘/’)  
  168.                                 {  
  169.                                     //return getToken(TokenType.NOTE);可选择输出注释  
  170.                                     //line–;  
  171.                                     break;  
  172.                                 }  
  173.                             }  
  174.                         }  
  175.                     }else if (c==‘/’) {  
  176.                         while(true){  
  177.                             nextChar();  
  178.                             if(c==‘\n’)  
  179.                             {  
  180.                                 break;  
  181.                             }  
  182.                         }  
  183.                           
     
  184.                     }  
  185.                     else{  
  186.                     pushbackChar();  
  187.                     return getToken(TokenType.DIVIDE);  
  188.                     }  
  189.                 }else if (c==‘%’) {  
  190.                     return getToken(TokenType.REMAINDER);  
  191.                 }else if (c==‘(‘) {  
  192.                     return getToken(TokenType.LPAREN);  
  193.                 }else if (c==‘)’) {  
  194.                     return getToken(TokenType.RPAREN);  
  195.                 }else if (c==‘{‘) {  
  196.                     return getToken(TokenType.LBRACKET);  
  197.                 }else if (c==‘}’) {  
  198.                     return getToken(TokenType.RBRACKET);  
  199.                 }else if (c==‘;’) {  
  200.                     return getToken(TokenType.SEMICOLON);  
  201.                 }else if (c==‘>’) {  
  202.                     nextChar();  
  203.                     if(c==‘=’){  
  204.                         return getToken(TokenType.GREATER_EQUAL);  
  205.                     }else {  
  206.                         pushbackChar();  
  207.                         return getToken(TokenType.GREATER);  
  208.                     }  
  209.                 }else if (c==‘<‘) {  
  210.                     nextChar();  
  211.                     if(c==‘=’){  
  212.                         return getToken(TokenType.LESS_EQUAL);  
  213.                     }else {  
  214.                         pushbackChar();  
  215.                         return getToken(TokenType.LESS);  
  216.                     }  
  217.                 }  
  218.                 else if (c==‘!’) {  
  219.                     nextChar();  
  220.                     if(c==‘=’){  
  221.                         return getToken(TokenType.NOT_EQUAL);  
  222.                     }else {  
  223.                         pushbackChar();  
  224.                         return getToken(TokenType.LOGICAL_NOT);  
  225.                     }  
  226.                 }else if (c==‘&’) {  
  227.                     nextChar();  
  228.                     if(c==‘&’){  
  229.                         return getToken(TokenType.LOGICAL_AND);  
  230.                     }  
  231.                 }  
  232.                 else if (c==‘|’) {  
  233.                     nextChar();  
  234.                     if(c==‘|’){  
  235.                         return getToken(TokenType.LOGICAL_OR);  
  236.                     }  
  237.                 }  
  238.                 else if (c==‘=’) {  
  239.                     nextChar();  
  240.                     if(c==‘=’){  
  241.                         return getToken(TokenType.EQUAL);  
  242.                     }else {  
  243.                         pushbackChar();  
  244.                         return getToken(TokenType.ASSIGN);  
  245.                     }  
  246.                       
     
  247.                 }else if (c==‘,’) {  
  248.                     return getToken(TokenType.COMMA);  
  249.                 }else if ((c&0xff)==0xff) {//文件结尾,返回EOF  
  250.                     return getToken(TokenType.EOF);  
  251.                 }else {  
  252.                     System.out.println(“get nextToken error!”);  
  253.                     System.out.println(“find illegal character”+c);  
  254.                     System.out.println(“at line “+line+“,column “+column);  
  255.                     System.exit(1);  
  256.                 }  
  257.                 break;  
  258.             case 1:  
  259.                 nextChar();  
  260.                 if(Character.isDigit(c))  
  261.                 {  
  262.                     state=1;  
  263.                 }else {  
  264.                     state=2;  
  265.                 }  
  266.                 break;  
  267.             case 2:  
  268.                 pushbackChar();  
  269.                 return getToken(TokenType.INTEGER_LITERAL);  
  270.             case 3:  
  271.                 nextChar();  
  272.                 if(Character.isLetterOrDigit(c)){  
  273.                     state =3;  
  274.                 }else {  
  275.                     state=4;  
  276.                 }  
  277.                 break;  
  278.             case 4:  
  279.                 pushbackChar();  
  280.                 String t=lexeme.toString();  
  281.                 if(t.equalsIgnoreCase(“int”)){  
  282.                     return getToken(TokenType.KEY_INT);  
  283.                 }else if (t.equalsIgnoreCase(“boolean”)) {  
  284.                     return getToken(TokenType.KEY_BOOLEAN);  
  285.                 }else if (t.equalsIgnoreCase(“while”)) {  
  286.                     return getToken(TokenType.KEY_WHILE);  
  287.                 }  
  288.                 else if (t.equalsIgnoreCase(“if”)) {  
  289.                     return getToken(TokenType.KEY_IF);  
  290.                 }else if (t.equalsIgnoreCase(“else”)) {  
  291.                     return getToken(TokenType.KEY_ELSE);  
  292.                 }  
  293.                 else {  
  294.                     return getToken(TokenType.IDENTIFIER);  
  295.                 }  
  296.             default:  
  297.                 System.out.println(“get nextToken error!”);  
  298.                 System.out.println(“find illegal state:”+state);  
  299.                 System.exit(1);  
  300.               
     
  301.             }  
  302.         }  
  303.     }  
  304. }  

[java] view plain copy

  1.   
     

Lab1Main.java

[java] view plain copy

  1. package sch.cauc.edu.token;  
  2. /** 
  3.  *  
  4.  * 测试词法分析程序 
  5.  * Lab1Main 
  6.  * 创建人:xrzhang  
  7.  * 时间:2018510上午9:20:24  
  8.  * @version 1.0.0 
  9.  * 
  10.  */   
  11. public class Lab1Main {  
  12. /** 
  13.  *  
  14.  * 方法名:main 
  15.  * 创建人:xrzhang  
  16.  * 时间:2018510上午9:22:54  
  17.  * 邮件:jmzhang_15_cauc@163.com 
  18.  * @param args void 
  19.  * @exception  
  20.  * @since  1.0.0 
  21.  */  
  22.     public static void main(String[] args) {  
  23.         BlockLexer l =new BlockLexer(“test/expr.txt”);  
  24.         //BlockLexer l =new BlockLexer(“test/expr2.txt”);  
  25.         Token s=l.nextToken();  
  26.         while(s.getType()!=TokenType.EOF){  
  27.             System.out.println(s);  
  28.             s=l.nextToken();  
  29.         }  
  30.   
     
  31.     }  
  32.   
     
  33. }  

[java] view plain copy

  1. 测试文件:expr.txt  

/*comment lines
*until here*/
{
    int i1,i2,i3;
    i1=14;
    i2=i1+2*3;
    i3=i1-5*(i2%2)+5;
    if(i1==i4&&i2>=20){
        i3=i3+1;}
    else{
    i3=i3+2;}
}

[java] view plain copy

  1. 测试文件:expr2.txt  

{
    //define two variables
    int m,n;
    m=12;n=21;
    if(m<n){
        int t;
        t=m;m=n;n=t;
        }
    int r;
    r=m%n;
    while(r!=0){m=n;n=r;r=m%n;}

}

发表评论

邮箱地址不会被公开。