Java 实现《编译原理》简单词法分析功能 - 程序解析

简易词法分析功能

要求及功能

(1)读取一个 txt 程序文件(最后的 # 作为结束标志,不可省去)

  1. {
  2. int a, b;
  3. a = 10;
  4. if(a>=1){
  5. b = a + 20;
  6. }
  7. }
  8. #

(2)词法识别分析表

单词类别 单词自身值 内部编码
关键字 int、for、while、do、return、break、continue 1
标识符 除关键字外的以字母开头,后跟字母、数字的字符序列 2
常数 无符号整型数 3
运算符 +、-、*、/、>、<、=、>=、<=、!= 4
界限符 ,、;、{、}、(、) 5
换行符 \n 6

(3)输出结果:

  1. (5,{)
  2. (6,\n)
  3. (1,int)
  4. (2,a)
  5. (5,,)
  6. (2,b)
  7. (5,;)
  8. (6,\n)
  9. (2,a)
  10. (4,=)
  11. (3,10)
  12. (5,;)
  13. (6,\n)
  14. (2,if)
  15. (5,()
  16. (2,a)
  17. (4,>=)
  18. (3,1)
  19. (5,))
  20. (5,{)
  21. (6,\n)
  22. (2,b)
  23. (4,=)
  24. (2,a)
  25. (4,+)
  26. (3,20)
  27. (5,;)
  28. (6,\n)
  29. (5,})
  30. (6,\n)
  31. (5,})
  32. (6,\n)
  33. (0,#)

并保存成新的 txt 文件

编程实现

(1)程序文件目录:

(2)Word.java 文件:

  1. package com.java997.analyzer.lexical;
  2. /**
  3. * <p>
  4. * 表示识别后的词实体类
  5. *
  6. * @author XiaoPengwei
  7. * @since 2019-06-13
  8. */
  9. public class Word {
  10. /**
  11. * 种别码
  12. */
  13. private int typeNum;
  14. /**
  15. * 扫描得到的词
  16. */
  17. private String word;
  18. public int getTypeNum() {
  19. return typeNum;
  20. }
  21. public void setTypeNum(int typeNum) {
  22. this.typeNum = typeNum;
  23. }
  24. public String getWord() {
  25. return word;
  26. }
  27. public void setWord(String word) {
  28. this.word = word;
  29. }
  30. }

(3)CodeScanner.java 文件:

  1. package com.java997.analyzer.lexical;
  2. /**
  3. * <p>
  4. * 字符扫描
  5. *
  6. * @author XiaoPengwei
  7. * @since 2019-06-13
  8. */
  9. public class CodeScanner {
  10. private static String _KEY_WORD_END = "end string of string";
  11. private int charNum = 0;
  12. private Word word;
  13. private char[] input = new char[255];
  14. private char[] token = new char[255];
  15. private int p_input = 0;
  16. private int p_token = 0;
  17. private char ch;
  18. /**
  19. * 关键字数组
  20. */
  21. private String[] rwtab = {"int", "if", "while", "do", "return", "break", "continue", _KEY_WORD_END};
  22. /**
  23. * 逻辑运算数组
  24. */
  25. private String[] logicTab = {"==",">=","<=","!=", _KEY_WORD_END};
  26. public CodeScanner(char[] input) {
  27. this.input = input;
  28. }
  29. /**
  30. * 取下一个字符
  31. *
  32. * @return
  33. */
  34. public char m_getch() {
  35. if (p_input < input.length) {
  36. ch = input[p_input];
  37. p_input++;
  38. }
  39. return ch;
  40. }
  41. /**
  42. * 如果是标识符或者空白符就取下一个字符
  43. */
  44. public void getbc() {
  45. while ((ch == ' ' || ch == '\t') && p_input < input.length) {
  46. ch = input[p_input];
  47. p_input++;
  48. }
  49. }
  50. /**
  51. * 把当前字符和原有字符串连接
  52. */
  53. public void concat() {
  54. token[p_token] = ch;
  55. p_token++;
  56. token[p_token] = '\0';
  57. }
  58. /**
  59. * 回退一个字符
  60. */
  61. public void retract() {
  62. p_input--;
  63. }
  64. /**
  65. * 判断是否为字母
  66. *
  67. * @return boolean
  68. * @author XiaoPengwei
  69. */
  70. public boolean isLetter() {
  71. return ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z';
  72. }
  73. /**
  74. * 判断是否为数字
  75. *
  76. * @return boolean
  77. * @author XiaoPengwei
  78. */
  79. public boolean isDigit() {
  80. return ch >= '0' && ch <= '9';
  81. }
  82. /**
  83. * 查看 token 中的字符串是否是关键字,是的话返回关键字种别编码,否则返回 2
  84. *
  85. * @return
  86. */
  87. public int isKey() {
  88. int i = 0;
  89. while (rwtab[i].compareTo(_KEY_WORD_END) != 0) {
  90. if (rwtab[i].compareTo(new String(token).trim()) == 0) {
  91. return i + 1;
  92. }
  93. i++;
  94. }
  95. return 2;
  96. }
  97. /**
  98. * 可能是逻辑预算字符
  99. *
  100. * @return
  101. */
  102. public Boolean isLogicChar() {
  103. return ch == '>' || ch == '<'|| ch == '='|| ch == '!';
  104. }
  105. /**
  106. * 查看 token 中的字符串是否是逻辑运算符,是的话返回关键字种别编码,否则返回 2
  107. *
  108. * @return
  109. */
  110. public int isLogicTab() {
  111. int i = 0;
  112. while (logicTab[i].compareTo(_KEY_WORD_END) != 0) {
  113. if (logicTab[i].compareTo(new String(token).trim()) == 0) {
  114. return i + 1;
  115. }
  116. i++;
  117. }
  118. return 4;
  119. }
  120. /**
  121. * 能够识别换行,单行注释和多行注释的
  122. * 换行的种别码设置成30
  123. * 多行注释的种别码设置成31
  124. *
  125. * @return
  126. */
  127. public Word scan() {
  128. token = new char[255];
  129. Word myWord = new Word();
  130. myWord.setTypeNum(10);
  131. myWord.setWord("");
  132. p_token = 0;
  133. m_getch();
  134. getbc();
  135. if (isLetter()) {
  136. while (isLetter() || isDigit()) {
  137. concat();
  138. m_getch();
  139. }
  140. retract();
  141. myWord.setTypeNum(isKey());
  142. myWord.setWord(new String(token).trim());
  143. return myWord;
  144. } else if (isLogicChar()) {
  145. while (isLogicChar()) {
  146. concat();
  147. m_getch();
  148. }
  149. retract();
  150. myWord.setTypeNum(4);
  151. myWord.setWord(new String(token).trim());
  152. return myWord;
  153. } else if (isDigit()) {
  154. while (isDigit()) {
  155. concat();
  156. m_getch();
  157. }
  158. retract();
  159. myWord.setTypeNum(3);
  160. myWord.setWord(new String(token).trim());
  161. return myWord;
  162. } else {
  163. switch (ch) {
  164. //5
  165. case ',':
  166. myWord.setTypeNum(5);
  167. myWord.setWord(",");
  168. return myWord;
  169. case ';':
  170. myWord.setTypeNum(5);
  171. myWord.setWord(";");
  172. return myWord;
  173. case '{':
  174. myWord.setTypeNum(5);
  175. myWord.setWord("{");
  176. return myWord;
  177. case '}':
  178. myWord.setTypeNum(5);
  179. myWord.setWord("}");
  180. return myWord;
  181. case '(':
  182. myWord.setTypeNum(5);
  183. myWord.setWord("(");
  184. return myWord;
  185. case ')':
  186. myWord.setTypeNum(5);
  187. myWord.setWord(")");
  188. return myWord;
  189. //4
  190. case '=':
  191. myWord.setTypeNum(4);
  192. myWord.setWord("=");
  193. return myWord;
  194. case '+':
  195. myWord.setTypeNum(4);
  196. myWord.setWord("+");
  197. return myWord;
  198. case '-':
  199. myWord.setTypeNum(4);
  200. myWord.setWord("-");
  201. return myWord;
  202. case '*':
  203. myWord.setTypeNum(4);
  204. myWord.setWord("*");
  205. return myWord;
  206. case '/':
  207. myWord.setTypeNum(4);
  208. myWord.setWord("/");
  209. return myWord;
  210. case '\n':
  211. myWord.setTypeNum(6);
  212. myWord.setWord("\\n");
  213. return myWord;
  214. case '#':
  215. myWord.setTypeNum(0);
  216. myWord.setWord("#");
  217. return myWord;
  218. default:
  219. concat();
  220. myWord.setTypeNum(-1);
  221. myWord.setWord("ERROR INFO: WORD = \"" + new String(token).trim() + "\"");
  222. return myWord;
  223. }
  224. }
  225. }
  226. }

(4)MainAnalyzer.java 文件:

  1. package com.java997.analyzer.lexical;
  2. import java.io.File;
  3. import java.io.FileNotFoundException;
  4. import java.io.FileWriter;
  5. import java.io.IOException;
  6. import java.io.Writer;
  7. import java.util.ArrayList;
  8. import java.util.Scanner;
  9. /**
  10. * <p>
  11. * 执行主程序
  12. *
  13. * @author XiaoPengwei
  14. * @since 2019-06-13
  15. */
  16. public class MainAnalyzer {
  17. private File inputFile;
  18. private File outputFile;
  19. private String fileContent;
  20. private ArrayList<Word> list = new ArrayList<>();
  21. /**
  22. * 构造方法
  23. *
  24. * @param input
  25. * @param output
  26. * @author XiaoPengwei
  27. */
  28. public MainAnalyzer(String input, String output) {
  29. //实例化输入文件
  30. inputFile = new File(input);
  31. //实例化输出文件
  32. outputFile = new File(output);
  33. }
  34. /**
  35. * 从指定的 txt 文件中读取源程序文件内容
  36. *
  37. * @return java.lang.String
  38. */
  39. public String getContent() {
  40. StringBuilder stringBuilder = new StringBuilder();
  41. try (Scanner reader = new Scanner(inputFile)) {
  42. while (reader.hasNextLine()) {
  43. String line = reader.nextLine();
  44. stringBuilder.append(line + "\n");
  45. System.out.println(line);
  46. }
  47. System.out.println("Successful reading of files:" + inputFile.getName());
  48. } catch (FileNotFoundException e) {
  49. e.printStackTrace();
  50. }
  51. return fileContent = stringBuilder.toString();
  52. }
  53. /**
  54. * 然后扫描程序,在程序结束前将扫描到的词添加到 list 中
  55. * 最后把扫描结果保存到指定的文件中
  56. *
  57. * @param fileContent
  58. * @return void
  59. */
  60. public void analyze(String fileContent) {
  61. int over = 1;
  62. Word word = new Word();
  63. //调用扫描程序
  64. CodeScanner scanner = new CodeScanner(fileContent.toCharArray());
  65. System.out.println("The result:");
  66. while (over != 0) {
  67. word = scanner.scan();
  68. System.out.println("(" + word.getTypeNum() + "," + word.getWord() + ")");
  69. list.add(word);
  70. over = word.getTypeNum();
  71. }
  72. saveResult();
  73. }
  74. /**
  75. * 将结果写入到到指定文件中
  76. * 如果文件不存在,则创建一个新的文件
  77. * 用一个 foreach 循环将 list 中的项变成字符串写入到文件中
  78. */
  79. public void saveResult() {
  80. //创建文件
  81. if (!outputFile.exists()) {
  82. try {
  83. outputFile.createNewFile();
  84. } catch (IOException e1) {
  85. e1.printStackTrace();
  86. }
  87. }
  88. //写入文件
  89. try (Writer writer = new FileWriter(outputFile)) {
  90. for (Word word : list) {
  91. writer.write("(" + word.getTypeNum() + " ," + word.getWord() + ")\n");
  92. }
  93. } catch (IOException e) {
  94. e.printStackTrace();
  95. }
  96. }
  97. public static void main(String[] args) {
  98. //注意输入文件路径/名称必须对, 输出文件可以由程序创建
  99. MainAnalyzer analyzer = new MainAnalyzer("D:\\analyzer\\src\\main\\java\\com\\java997\\analyzer\\lexical\\input.txt", "D:\\analyzer\\src\\main\\java\\com\\java997\\analyzer\\lexical\\output.txt");
  100. analyzer.analyze(analyzer.getContent());
  101. }
  102. }

(5)input.txt 文件:

  1. {
  2. int a, b;
  3. a = 10;
  4. if(a>=1){
  5. b = a + 20;
  6. }
  7. }
  8. #

执行测试

Java 实现《编译原理》简单词法分析功能 - 程序解析的更多相关文章

  1. Java的编译原理

    概述 java语言的"编译期"分为前端编译和后端编译两个阶段.前端编译是指把*.java文件转变成*.class文件的过程; 后端编译(JIT, Just In Time Comp ...

  2. 深入分析Java的编译原理

    在<Java代码的编译与反编译>中,有过关于Java语言的编译和反编译的介绍.我们可以通过javac命令将Java程序的源代码编译成Java字节码,即我们常说的class文件.这是我们通常 ...

  3. 编译原理简单语法分析器(first,follow,分析表)源码下载

    编译原理(简单语法分析器下载) http://files.cnblogs.com/files/hujunzheng/%E5%8A%A0%E5%85%A5%E5%90%8C%E6%AD%A5%E7%AC ...

  4. .Net编译原理简单介绍

    首先简单说一下计算机软件运行.所谓软件运行,就是一步一步做一些事情.计算机只认识0和1.给计算机下命令,只能是0与1的方式,确切的说,其实是CPU只认识0和1,因为软件运行是CPU控制的.人直接操作0 ...

  5. Java网络编程以及简单的聊天程序

    网络编程技术是互联网技术中的主流编程技术之一,懂的一些基本的操作是非常必要的.这章主要讲解网络编程,UDP和Socket编程,以及使用Socket做一个简单的聊天软件. 全部代码下载:链接 1.网络编 ...

  6. Net编译原理简单

    转载:http://blog.csdn.net/sundacheng1989/article/details/20941893 首先简单说一下计算机软件运行.所谓软件运行,就是一步一步做一些事情.计算 ...

  7. Java continue break 制作简单聊天室程序,屏蔽不文明语言,显示每句话聊天时间 for(;;) SimpleDateFormat("yyyy-MM-dd hh:mm:ss") equalsIgnoreCase

    package com.swift; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Scanne ...

  8. Java注解及其原理以及分析spring注解解析源码

    注解的定义 注解是那些插入到源代码中,使用其他工具可以对其进行处理的标签. 注解不会改变程序的编译方式:Java编译器对于包含注解和不包含注解的代码会生成相同的虚拟机指令. 在Java中,注解是被当做 ...

  9. Java中JSON的简单使用与前端解析

    http://www.blogjava.net/qileilove/archive/2014/06/13/414694.html 一.JSON JSON(JavaScript Object Notat ...

随机推荐

  1. debain安装文泉驿字体

    sudo apt-get install ttf-wqy-microhei sudo apt-get install ttf-wqy-zenhei

  2. python爬虫前提技术

    1.BeautifulSoup 解析html如何使用 转自:http://blog.csdn.net/u013372487/article/details/51734047 #!/usr/bin/py ...

  3. 联想H430怎么清除cmos密码?

    联想H430怎么清除cmos密码? 方法一:长时间对cmos放电 首先断掉主机电源,然后找到主板上的纽扣电池,将电池小心取出,然后使用一金属导体,短接电池座中的正负极,这样也可达到快速放电的目的. 有 ...

  4. python基础之元祖tuple

    元祖是只读列表,不可哈希,可循环查询,可切片*儿子不能改,孙子可更改--元祖里面单个元素不能更改---元祖内列表可更改增:tu1+tu2查:tu1[index] tu1[start_index:end ...

  5. Kali Linux 2019.2安装谷歌输入法

    前言 Linux下常用的中文输入法平台有IBus.fcitx和scim.scim现在维护滞后,不推荐使用. IBus ("Intelligent Input Bus") 是一个 输 ...

  6. 3 基于梯度的攻击——MIM

    MIM攻击原论文地址——https://arxiv.org/pdf/1710.06081.pdf 1.MIM攻击的原理 MIM攻击全称是 Momentum Iterative Method,其实这也是 ...

  7. Python 输入IP地址及掩码告诉你该网段包含的全部地址(IPy模块练习)

    IPy模块原本使用时需要输入正确的网络位和掩码,我利用处理报错的机制实现了输入任意IP地址和掩码均可正确输出结果的小程序. #!/usr/bin/env python # -*- coding: ut ...

  8. python打印带颜色的字体

    在python开发的过程中,经常会遇到需要打印各种信息.海量的信息堆砌在控制台中,就会导致信息都混在一起,降低了重要信息的可读性.这时候,如果能给重要的信息加上字体颜色,那么就会更加方便用户阅读了. ...

  9. 怎么快速写好看的手机menu菜单

    要达到这样的效果: <div class="menu"> <div class="menu-1"> <img alt=" ...

  10. 福建工程学院第十四届ACM校赛B题题解

    第二集,未来的我发量这么捉急的吗 题意: 有n个数,请问有多少对数字(i,j)(1<=i<j<=n),满足(a[i]^a[j])+((a[i]&a[j])<<1) ...