这一篇与前一篇的思路是一样的,只不过这个例子稍微能够处理多行注释的问题。

原来的思路是这样的:

使用Java的正则表达式功能,并对Tiny源程序代码做了一定的前提条件所完成的 Tiny 语言,其实就是模仿教材中的最终输出文件解析出每一个 Token。 

默认每个Token之间都以空格“ ”隔开,因此可用Java中的正则表达式将每一行依此规律拆分为一个个Token,然后再对每一个Token进行类别匹配(也用到正则表达式),最后按类别打印输出。以下实现但是不能够处理多行注释的问题。

对教材中的源程序样例代码修改如下(加了不少空格变成sample2.tny):

编译原理-词法分析(lexical analysis)初识(续)_第1张图片

扫描之后的输出结果:

编译原理-词法分析(lexical analysis)初识(续)_第2张图片

 

代码实现:

   
   
   
   
  1. package lexical_analysis; 
  2.  
  3. import java.io.BufferedReader; 
  4. import java.io.FileReader; 
  5. import java.util.regex.Pattern; 
  6.  
  7. public class OriginalLexicalAnalyser { 
  8.  
  9.     private static final int RESERVE_DWORD = 1
  10.     private static final int ARITHMETIC_SYMBOLS = 2
  11.     private static final int ID = 3
  12.     private static final int NUM = 4
  13.  
  14.     // 保留字 
  15.     private String[] reservedWords = new String[] { "read""if""then"
  16.                                                     "repeat""until""write",  
  17.                                                     "end" }; 
  18.     // 数学运算符 
  19.     private String[] arithmeticSymbols = new String[] { "+""-""*""/"
  20.                                                         "%"":=""=""<",  
  21.                                                         ">""<="">=" }; 
  22.     // 源程序文件输入流 
  23.     private BufferedReader sourceFile; 
  24.     // 代码行数 
  25.     private int lineCount = 0
  26.     boolean commentFlag = false
  27.  
  28.     public OriginalLexicalAnalyser(String sourceFilePath) throws Exception { 
  29.         // 创建并加载源程序文件输入流 
  30.         this.sourceFile = new BufferedReader(new FileReader(sourceFilePath)); 
  31.     } 
  32.  
  33.     public void scan() throws Exception { 
  34.         String eachLine = ""
  35.  
  36.         while ((eachLine = this.sourceFile.readLine()) != null) { 
  37.             ++lineCount; 
  38.             System.out.printf("%2d: %s\n", lineCount, eachLine); 
  39.              
  40.             int start = 0
  41.             int end = 0
  42.             int lineLen = eachLine.length(); 
  43.  
  44.             String nextChar; 
  45.             String token = ""
  46.              
  47.             if("}".equals(eachLine)) { 
  48.                 commentFlag = false
  49.                 printToken(eachLine); 
  50.                 continue
  51.             } 
  52.  
  53.             while (end < lineLen - 1) { 
  54.                 nextChar = eachLine.substring(end, end + 1); 
  55.                  
  56.                 // 上一行是多行注释开始,即 { 
  57.                 if (commentFlag == true) { 
  58.                     end = processComment(eachLine); 
  59.                     token = eachLine.substring(start, end); 
  60.                     printToken(token); 
  61.                      
  62.                 } else { 
  63.                     if (" ".equals(nextChar)) { 
  64.                         token = eachLine.substring(start, end); 
  65.                         printToken(token); 
  66.                         start = end + 1
  67.                         end = start; 
  68.                     } else if (";".equals(nextChar)) { 
  69.                         token = eachLine.substring(start, end); 
  70.                         printToken(token); 
  71.                         printToken(";"); 
  72.                         break
  73.                     } else if("{".equals(nextChar)){ 
  74.                         commentFlag = true
  75.                         start = end + 1
  76.                         end = start; 
  77.                     } else { 
  78.                         end++; 
  79.                     } 
  80.                 } 
  81.             } 
  82.         } 
  83.     } 
  84.  
  85.     private int processComment(String eachLine) { 
  86.         String ch; 
  87.         int start = 0
  88.         int lineLen = eachLine.length(); 
  89.         for (int i = 1; i < lineLen; ++i) { 
  90.             ch = eachLine.substring(start, i); 
  91.             start++; 
  92.             if ("}".equals(ch)) { 
  93.                 commentFlag = false
  94.                 return i; 
  95.             } 
  96.         } 
  97.         return lineLen - 1
  98.     } 
  99.      
  100.     private void printToken(String token) { 
  101.         if(isArithmeticSymbol(token)) {     // 数学运算符         
  102.             System.out.println("    " + lineCount + ": " + token); 
  103.         } else if(isReservedWord(token)) {  // 保留字 
  104.             if(lineCount == 7) { 
  105.                 System.out.println("==========" + token + "==="); 
  106.             } 
  107.             System.out.println("    " + lineCount + ": " + "reserved word: " + token); 
  108.             // 源程序文件结束符 
  109.             if("end".equals(token)) { 
  110.                 System.out.printf("%2d: %s\n", ++lineCount, "EOF"); 
  111.             } 
  112.         } else if(";".equals(token)) {      // 行结束符,即分号 
  113.             System.out.println("    " + lineCount + ": " + token); 
  114.         }  else if(isID(token)) {           // 自定义标识符ID 
  115.             System.out.println("    " + lineCount + ": " + "ID, name= " + token); 
  116.         } else if(isNum(token)) {           // 数值NUM 
  117.             System.out.println("    " + lineCount + ": " + "NUM, val= " + token); 
  118.         } 
  119.     } 
  120.  
  121.     /** 
  122.      * 判断是否为“保留字” 
  123.      * @param token 
  124.      * @return 
  125.      */ 
  126.     private boolean isReservedWord(String token) { 
  127.         int size = this.reservedWords.length; 
  128.         for(int i = 0; i < size; i++) { 
  129.             if(token.equals(reservedWords[i])) { 
  130.                 return true
  131.             } 
  132.         } 
  133.         return false
  134.     } 
  135.      
  136.     /** 
  137.      * 判断是否为“数学运算符” 
  138.      * @param token 
  139.      * @return 
  140.      */ 
  141.     private boolean isArithmeticSymbol(String token) { 
  142.         int size = this.arithmeticSymbols.length; 
  143.         for(int i = 0; i < size; i++) { 
  144.             if(token.equals(arithmeticSymbols[i])) { 
  145.                 return true
  146.             } 
  147.         } 
  148.         return false
  149.     } 
  150.      
  151.     /** 
  152.      * 判断是否为“数值NUM” 
  153.      * @param token 
  154.      * @return 
  155.      */ 
  156.     private boolean isNum(String token) { 
  157.         boolean flag = Pattern.matches("\\d+?", token); 
  158.         return flag; 
  159.     } 
  160.      
  161.     /** 
  162.      * 判断是否为“ID” 
  163.      * @param token 
  164.      * @return 
  165.      */ 
  166.     private boolean isID(String token) { 
  167.         boolean flag = Pattern.matches("[a-zA-Z]+?", token); 
  168.         return flag; 
  169.     } 
  170.      
  171.  
  172.     /** 
  173.      * “词法分析程序”的启动入口 
  174.      * @param args 
  175.      */ 
  176.     public static void main(String[] args) throws Exception { 
  177.         String sourceFilePath = "sample2.tny"
  178.         OriginalLexicalAnalyser lexicalAnalyser = new OriginalLexicalAnalyser(sourceFilePath); 
  179.         lexicalAnalyser.scan(); 
  180.     } 
  181.