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

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

简易词法分析功能

要求及功能

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

{
  int a, b;
  a = 10;
  if(a>=1){
    b = a + 20;
  }
}

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

(3)输出结果:

(5,{)
(6,\n)
(1,int)
(2,a)
(5,,)
(2,b)
(5,;)
(6,\n)
(2,a)
(4,=)
(3,10)
(5,;)
(6,\n)
(2,if)
(5,()
(2,a)
(4,>=)
(3,1)
(5,))
(5,{)
(6,\n)
(2,b)
(4,=)
(2,a)
(4,+)
(3,20)
(5,;)
(6,\n)
(5,})
(6,\n)
(5,})
(6,\n)
(0,#)

并保存成新的 txt 文件

编程实现

(1)程序文件目录:

(2)Word.java 文件:

package com.java997.analyzer.lexical;

/**
 * <p>
 * 表示识别后的词实体类
 *
 * @author XiaoPengwei
 * @since 2019-06-13
 */
public class Word {

    /**
     * 种别码
     */
    private int typeNum;

    /**
     * 扫描得到的词
     */
    private String word;

    public int getTypeNum() {
        return typeNum;
    }

    public void setTypeNum(int typeNum) {
        this.typeNum = typeNum;
    }

    public String getWord() {
        return word;
    }

    public void setWord(String word) {
        this.word = word;
    }
}

(3)CodeScanner.java 文件:

package com.java997.analyzer.lexical;

/**
 * <p>
 * 字符扫描
 *
 * @author XiaoPengwei
 * @since 2019-06-13
 */
public class CodeScanner {

    private static String _KEY_WORD_END = "end string of string";
    private int charNum = 0;
    private Word word;

    private char[] input = new char[255];
    private char[] token = new char[255];
    private int p_input = 0;
    private int p_token = 0;

    private char ch;

    /**
     * 关键字数组
     */
    private String[] rwtab = {"int", "if", "while", "do", "return", "break", "continue", _KEY_WORD_END};

    /**
     * 逻辑运算数组
     */
    private String[] logicTab = {"==",">=","<=","!=", _KEY_WORD_END};

    public CodeScanner(char[] input) {
        this.input = input;
    }

    /**
     * 取下一个字符
     *
     * @return
     */
    public char m_getch() {
        if (p_input < input.length) {
            ch = input[p_input];
            p_input++;
        }
        return ch;
    }

    /**
     * 如果是标识符或者空白符就取下一个字符
     */
    public void getbc() {
        while ((ch == ' ' || ch == '\t') && p_input < input.length) {
            ch = input[p_input];
            p_input++;
        }
    }

    /**
     * 把当前字符和原有字符串连接
     */
    public void concat() {
        token[p_token] = ch;
        p_token++;
        token[p_token] = '\0';
    }

    /**
     * 回退一个字符
     */
    public void retract() {
        p_input--;
    }

    /**
     * 判断是否为字母
     *
     * @return boolean
     * @author XiaoPengwei
     */
    public boolean isLetter() {
        return ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z';
    }

    /**
     * 判断是否为数字
     *
     * @return boolean
     * @author XiaoPengwei
     */
    public boolean isDigit() {
        return ch >= '0' && ch <= '9';
    }

    /**
     * 查看 token 中的字符串是否是关键字,是的话返回关键字种别编码,否则返回 2
     *
     * @return
     */
    public int isKey() {
        int i = 0;
        while (rwtab[i].compareTo(_KEY_WORD_END) != 0) {
            if (rwtab[i].compareTo(new String(token).trim()) == 0) {
                return i + 1;
            }
            i++;
        }
        return 2;
    }

    /**
     * 可能是逻辑预算字符
     *
     * @return
     */
    public Boolean isLogicChar() {
        return ch == '>' || ch == '<'|| ch == '='|| ch == '!';
    }

    /**
     * 查看 token 中的字符串是否是逻辑运算符,是的话返回关键字种别编码,否则返回 2
     *
     * @return
     */
    public int isLogicTab() {
        int i = 0;
        while (logicTab[i].compareTo(_KEY_WORD_END) != 0) {
            if (logicTab[i].compareTo(new String(token).trim()) == 0) {
                return i + 1;
            }
            i++;
        }
        return 4;
    }

    /**
     * 能够识别换行,单行注释和多行注释的
     * 换行的种别码设置成30
     * 多行注释的种别码设置成31
     *
     * @return
     */
    public Word scan() {
        token = new char[255];
        Word myWord = new Word();
        myWord.setTypeNum(10);
        myWord.setWord("");

        p_token = 0;
        m_getch();
        getbc();
        if (isLetter()) {
            while (isLetter() || isDigit()) {
                concat();
                m_getch();
            }
            retract();
            myWord.setTypeNum(isKey());
            myWord.setWord(new String(token).trim());
            return myWord;
        } else if (isLogicChar()) {
            while (isLogicChar()) {
                concat();
                m_getch();
            }
            retract();
            myWord.setTypeNum(4);
            myWord.setWord(new String(token).trim());
            return myWord;
        } else if (isDigit()) {
            while (isDigit()) {
                concat();
                m_getch();
            }
            retract();
            myWord.setTypeNum(3);
            myWord.setWord(new String(token).trim());
            return myWord;
        } else {
            switch (ch) {
                //5
                case ',':
                    myWord.setTypeNum(5);
                    myWord.setWord(",");
                    return myWord;
                case ';':
                    myWord.setTypeNum(5);
                    myWord.setWord(";");
                    return myWord;
                case '{':
                    myWord.setTypeNum(5);
                    myWord.setWord("{");
                    return myWord;
                case '}':
                    myWord.setTypeNum(5);
                    myWord.setWord("}");
                    return myWord;
                case '(':
                    myWord.setTypeNum(5);
                    myWord.setWord("(");
                    return myWord;
                case ')':
                    myWord.setTypeNum(5);
                    myWord.setWord(")");
                    return myWord;
                //4
                case '=':
                    myWord.setTypeNum(4);
                    myWord.setWord("=");
                    return myWord;
                case '+':
                    myWord.setTypeNum(4);
                    myWord.setWord("+");
                    return myWord;
                case '-':
                    myWord.setTypeNum(4);
                    myWord.setWord("-");
                    return myWord;
                case '*':
                    myWord.setTypeNum(4);
                    myWord.setWord("*");
                    return myWord;
                case '/':
                    myWord.setTypeNum(4);
                    myWord.setWord("/");
                    return myWord;

                case '\n':
                    myWord.setTypeNum(6);
                    myWord.setWord("\\n");
                    return myWord;
                case '#':
                    myWord.setTypeNum(0);
                    myWord.setWord("#");
                    return myWord;
                default:
                    concat();
                    myWord.setTypeNum(-1);
                    myWord.setWord("ERROR INFO: WORD = \"" + new String(token).trim() + "\"");
                    return myWord;
            }
        }
    }
}

(4)MainAnalyzer.java 文件:

package com.java997.analyzer.lexical;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Scanner;

/**
 * <p>
 * 执行主程序
 *
 * @author XiaoPengwei
 * @since 2019-06-13
 */
public class MainAnalyzer {
    private File inputFile;
    private File outputFile;
    private String fileContent;
    private ArrayList<Word> list = new ArrayList<>();

    /**
     * 构造方法
     *
     * @param input
     * @param output
     * @author XiaoPengwei
     */
    public MainAnalyzer(String input, String output) {
        //实例化输入文件
        inputFile = new File(input);

        //实例化输出文件
        outputFile = new File(output);
    }

    /**
     * 从指定的 txt 文件中读取源程序文件内容
     *
     * @return java.lang.String
     */
    public String getContent() {
        StringBuilder stringBuilder = new StringBuilder();
        try (Scanner reader = new Scanner(inputFile)) {
            while (reader.hasNextLine()) {
                String line = reader.nextLine();
                stringBuilder.append(line + "\n");
                System.out.println(line);
            }
            System.out.println("Successful reading of files:" + inputFile.getName());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return fileContent = stringBuilder.toString();
    }

    /**
     * 然后扫描程序,在程序结束前将扫描到的词添加到 list 中
     * 最后把扫描结果保存到指定的文件中
     *
     * @param fileContent
     * @return void
     */
    public void analyze(String fileContent) {
        int over = 1;
        Word word = new Word();

        //调用扫描程序
        CodeScanner scanner = new CodeScanner(fileContent.toCharArray());
        System.out.println("The result:");
        while (over != 0) {
            word = scanner.scan();
            System.out.println("(" + word.getTypeNum() + "," + word.getWord() + ")");
            list.add(word);
            over = word.getTypeNum();
        }
        saveResult();
    }

    /**
     * 将结果写入到到指定文件中
     * 如果文件不存在,则创建一个新的文件
     * 用一个 foreach 循环将 list 中的项变成字符串写入到文件中
     */
    public void saveResult() {

        //创建文件
        if (!outputFile.exists()) {
            try {
                outputFile.createNewFile();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }

        //写入文件
        try (Writer writer = new FileWriter(outputFile)) {
            for (Word word : list) {
                writer.write("(" + word.getTypeNum() + " ," + word.getWord() + ")\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {

        //注意输入文件路径/名称必须对, 输出文件可以由程序创建
        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");

        analyzer.analyze(analyzer.getContent());
    }
}

(5)input.txt 文件:

{
  int a, b;
  a = 10;
  if(a>=1){
    b = a + 20;
  }
}
#

执行测试

原文地址:https://www.cnblogs.com/xpwi/p/11020366.html

时间: 2024-11-06 18:29:35

Java 实现《编译原理》简单词法分析功能的相关文章

编译原理简单介绍

编译原理学习导论 大学课程为什么要开设编译原理呢?这门课程关注的是编译器方面的产生原理和技术问题,似乎和计算机的基础领域不沾边,可是编译原理却一直作为大学本科的必修课程,同时也成为了研究生入学考试的必考内容.编译原理及技术从本质上来讲就是一个算法问题而已,当然由于这个问题十分复杂,其解决算法也相对复杂.我们学的数据结构与算法分析也是讲算法的,不过讲的基础算法,换句话说讲的是算法导论,而编译原理这门课程讲的就是比较专注解决一种的算法了.在20世纪50年代,编译器的编写一直被认为是十分困难的事情,第

[编译原理学习]词法分析

此前一直没能系统完整地学过编译原理,只有很粗浅的理解,虽然其实对工作里的任务也没啥影响,但总觉得缺了一大块知识,加上对所谓程序员三大浪漫(编译器,操作系统,图形学)的向往,所以最近跟着网易云课堂推出的计算机专业课程来学习编译原理.无奈生性懒惰,常常下班之后觉得累了,打打游戏啊看看视频啊,拖延症就犯了.......所以在这里打算将学习的过程,心得记录下来,也算是对自己的一个督促.课程传送门http://mooc.study.163.com/learn/USTC-1000002001#/learn/

深入分析Java的编译原理

在<Java代码的编译与反编译>中,有过关于Java语言的编译和反编译的介绍.我们可以通过javac命令将Java程序的源代码编译成Java字节码,即我们常说的class文件.这是我们通常意义上理解的编译. 但是,字节码并不是机器语言,要想让机器能够执行,还需要把字节码翻译成机器指令.这个过程是Java虚拟机做的,这个过程也叫编译.是更深层次的编译. 在编译原理中,把源代码翻译成机器指令,一般要经过以下几个重要步骤: 根据完成任务不同,可以将编译器的组成部分划分为前端(Front End)与后

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

编译原理(简单词法分析器下载) http://files.cnblogs.com/files/hujunzheng/%E7%AE%80%E5%8D%95%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90%E5%99%A8.zip

.Net编译原理简单介绍

名称解释: 1.CLR:公共语言远行时,是一个可由多种编程语言使用的"远行时".CLR的核心功能(比如内存管理.程序集加载.安全性.异常处理和线程同步)可由面向CLR的所有语言使用.CLR不关心开发人员使用哪种语言进行编程,只要编译器面向CLR就可以了,所有,开发人员应该使用自己最适合和熟悉的语言进行编程.所有的编程语言在面向CLR编译器的编译都生成了一个托管模块. 2.IL文件:IL(中间语言)代码 编译器编译源代码时生成的代码..net生成的exe文件是IL文件,是不能被CPU识别

编译原理学习--词法分析(2)

自动生成的词法分析器跟之前讲的图转移算法是类似的,因为是自动生成,为了把整个流程形式化,需要用另外一个数学工具--有限状态自动机. 从数学上讲,有限状态自动机是什么概念呢? 输入一个字符串,如果字符串能够接受,则输出Yes,否则输出No.有限状态自动机是一个五元组,M=(S, Σ, δ, q0, F),其中,Σ-输入字母表,S- 状态集,q0-初始状态,F-终结状态集,δ-转移函数. 举个例子,什么样的串可以被接受? 由图可知,Σ={a,b},S={0,1,2},q0=0,F={2},δ函数如下

编译原理学习--词法分析(1)

词法分析的任务: 首先,从阶段上来看,编译器可分为若干个中间阶段: 典型的,可以包含为一个前端,一个后端.前端接收源程序产生一个中间表示,后端接收表示继续生成一个目标程序.所以,前端处理的是跟源语言有关的属性,后端处理跟目标机器有关的属性. 更细节的,前端可以划分为若干个阶段: 下面我们看看词法分析器的任务: 词法分析器读入程序员写的程序,然后对字符流做切分成记号流.举个例子: 这是一个程序员看到的字符流 词法分析器将字符流读入,根据关键字.标识符.标点.字符串.整形数等进行划分,形成记号流(单

编译原理之词法分析程序的设计与实现

一.程序要求(以python为例). 1.词法分析程序(Lexical Analyzer)要求: - 从左至右扫描构成源程序的字符流 -  识别出有词法意义的单词(Lexemes) -  返回单词记录(单词类别,单词本身) -  滤掉空格 -  跳过注释 -  发现词法错误 2.程序结构: 输入:字符流(什么输入方式,什么数据结构保存) 处理: –遍历(什么遍历方式) –词法规则 输出:单词流(什么输出形式) –二元组 3.单词类别: 1.标识符(10) 2.无符号数(11) 3.保留字(一词一

javac编译原理(一)

我们都知道,计算机只能识别二进制语言,是不能直接识别java c c++等高级语言的.将高级语言转化成计算机可以是别的二进制语言,这个过程就叫编译. 有次面试,面试官问了一道“java的编译原理是什么”,当时给懵了,只知道是把java文件转换成class文件,然后由jvm执行,具体流程就不知道了.今天看了许令波编著的<深入分析java web技术内幕>一书,其中有一章讲的就是javac的编译原理,看了一遍,感觉有点云里雾里,不是很明白,接下还得多看看几遍,多上网查查资料深入透彻的学习一下. 今