用Java语言实现简单的词法分析器
编译原理中的词法分析算是很重要的一个部分,原理比较简单,不过网上大部分都是用C语言或者C++来编写,笔者近期在学习Java,故用Java语言实现了简单的词法分析器。
要分析的代码段如下:

输出结果如下:



括号里是一个二元式:(单词类别编码,单词位置编号)
代码如下:
package Yue.LexicalAnalyzer;
import java.io.*;
/*
 * 主程序
 */
public class Main {
    public static void main(String[] args) throws IOException {
        Lexer lexer = new Lexer();
        lexer.printToken();
        lexer.printSymbolsTable();
    }
}
package Yue.LexicalAnalyzer;
import java.io.*;
import java.util.*;
/*
 * 词法分析并输出
 */
public class Lexer {
    /*记录行号*/
    public static int line = 1;
    /*存放最新读入的字符*/
    char character = ' ';
    /*保留字*/
    Hashtable<String, KeyWord> keywords = new Hashtable<String, KeyWord>();
    /*token序列*/
    private ArrayList<Token> tokens = new ArrayList<Token>();
    /*符号表*/
    private ArrayList<Symbol> symtable = new ArrayList<Symbol>();
    /*读取文件变量*/
    BufferedReader reader = null;
    /*保存当前是否读取到了文件的结尾*/
    private Boolean isEnd = false;
    /* 是否读取到文件的结尾 */
    public Boolean getReaderState() {
        return this.isEnd;
    }
    /*打印tokens序列*/
    public void printToken() throws IOException {
        FileWriter writer = new FileWriter("E:\\lex.txt");
        System.out.println("词法分析结果如下:");
        System.out.print("杜悦-2015220201031\r\n\n");
        writer.write("杜悦-2015220201031\r\n\r\n");
        while (getReaderState() == false) {
            Token tok = scan();
            String str = "line " + tok.line + "\t(" + tok.tag + "," + tok.pos + ")\t\t"
                    + tok.name + ": " + tok.toString() + "\r\n";
            writer.write(str);
            System.out.print(str);
        }
        writer.flush();
    }
    /*打印符号表*/
    public void printSymbolsTable() throws IOException {
        FileWriter writer = new FileWriter("E:\\symtab1.txt");
        System.out.print("\r\n\r\n符号表\r\n");
        System.out.print("编号\t行号\t名称\r\n");
        writer.write("符号表\r\n");
        writer.write("编号 " + "\t行号 " + "\t名称 \r\n");
        Iterator<Symbol> e = symtable.iterator();
        while (e.hasNext()) {
            Symbol symbol = e.next();
            String desc = symbol.pos + "\t" + symbol.line + "\t" + symbol.toString();
            System.out.print(desc + "\r\n");
            writer.write(desc + "\r\n");
        }
        writer.flush();
    }
    /*打印错误*/
    public void printError(Token tok) throws IOException{
        FileWriter writer = new FileWriter("E:\\error.txt");
        System.out.print("\r\n\r\n错误词法如下:\r\n");
        writer.write("错误词法如下:\r\n");
        String str = "line " + tok.line + "\t(" + tok.tag + "," + tok.pos + ")\t\t"
                + tok.name + ": " + tok.toString() + "\r\n";
        writer.write(str);
    }
    /*添加保留字*/
    void reserve(KeyWord w) {
        keywords.put(w.lexme, w);
    }
    public Lexer() {
        /*初始化读取文件变量*/
        try {
            reader = new BufferedReader(new FileReader("E:\\输入.txt"));
        } catch (IOException e) {
            System.out.print(e);
        }
        /*添加保留字*/
        this.reserve(KeyWord.begin);
        this.reserve(KeyWord.end);
        this.reserve(KeyWord.integer);
        this.reserve(KeyWord.function);
        this.reserve(KeyWord.read);
        this.reserve(KeyWord.write);
        this.reserve(KeyWord.aIf);
        this.reserve(KeyWord.aThen);
        this.reserve(KeyWord.aElse);
    }
    /*按字符读*/
    public void readch() throws IOException {
        character = (char) reader.read();
        if ((int) character == 0xffff) {
            this.isEnd = true;
        }
    }
    /*判断是否匹配*/
    public Boolean readch(char ch) throws IOException {
        readch();
        if (this.character != ch) {
            return false;
        }
        this.character = ' ';
        return true;
    }
    /*数字的识别*/
    public Boolean isDigit() throws IOException {
        if (Character.isDigit(character)) {
            int value = 0;
            while (Character.isDigit(character)) {
                value = 10 * value + Character.digit(character, 10);
                readch();
            }
            Num n = new Num(value);
            n.line = line;
            tokens.add(n);
            return true;
        } else
            return false;
    }
    /*保留字、标识符的识别*/
    public Boolean isLetter() throws IOException {
        if (Character.isLetter(character)) {
            StringBuffer sb = new StringBuffer();
            /*首先得到整个的一个分割*/
            while (Character.isLetterOrDigit(character)) {
                sb.append(character);
                readch();
            }
            /*判断是保留字还是标识符*/
            String s = sb.toString();
            KeyWord w = keywords.get(s);
            /*如果是保留字的话,w不应该是空的*/
            if (w != null) {
                w.line = line;
                tokens.add(w);
            } else {
                /*否则就是标识符,此处多出记录标识符编号的语句*/
                Symbol sy = new Symbol(s);
                Symbol mark = sy;           //用于标记已存在标识符
                Boolean isRepeat = false;
                sy.line = line;
                for (Symbol i : symtable) {
                    if (sy.toString().equals(i.toString())) {
                        mark = i;
                        isRepeat = true;
                    }
                }
                if (!isRepeat) {
                    sy.pos = symtable.size() + 1;
                    symtable.add(sy);
                } else if (isRepeat) {
                    sy.pos = mark.pos;
                }
                tokens.add(sy);
            }
            return true;
        } else
            return false;
    }
    /*符号的识别*/
    public Boolean isSign() throws IOException {
        switch (character) {
            case '#':
                readch();
                AllEnd.allEnd.line = line;
                tokens.add(AllEnd.allEnd);
                return true;
            case '\r':
                if (readch('\n')) {
                    readch();
                    LineEnd.lineEnd.line = line;
                    tokens.add(LineEnd.lineEnd);
                    line++;
                    return true;
                }
            case '(':
                readch();
                Delimiter.lpar.line = line;
                tokens.add(Delimiter.lpar);
                return true;
            case ')':
                readch();
                Delimiter.rpar.line = line;
                tokens.add(Delimiter.rpar);
                return true;
            case ';':
                readch();
                Delimiter.sem.line = line;
                tokens.add(Delimiter.sem);
                return true;
            case '+':
                readch();
                CalcWord.add.line = line;
                tokens.add(CalcWord.add);
                return true;
            case '-':
                readch();
                CalcWord.sub.line = line;
                tokens.add(CalcWord.sub);
                return true;
            case '*':
                readch();
                CalcWord.mul.line = line;
                tokens.add(CalcWord.mul);
                return true;
            case '/':
                readch();
                CalcWord.div.line = line;
                tokens.add(CalcWord.div);
                return true;
            case ':':
                if (readch('=')) {
                    readch();
                    CalcWord.assign.line = line;
                    tokens.add(CalcWord.assign);
                    return true;
                }
                break;
            case '>':
                if (readch('=')) {
                    readch();
                    CalcWord.ge.line = line;
                    tokens.add(CalcWord.ge);
                    return true;
                }
                break;
            case '<':
                if (readch('=')) {
                    readch();
                    CalcWord.le.line = line;
                    tokens.add(CalcWord.le);
                    return true;
                }
                break;
            case '!':
                if (readch('=')) {
                    readch();
                    CalcWord.ne.line = line;
                    tokens.add(CalcWord.ne);
                    return true;
                }
                break;
        }
        return false;
    }
    /*下面开始分割关键字,标识符等信息*/
    public Token scan() throws IOException {
        Token tok;
        while (character == ' ')
            readch();
        if (isDigit() || isSign() || isLetter()) {
            tok = tokens.get(tokens.size() - 1);
        } else {
            tok = new Token(character);
            printError(tok);
        }
        return tok;
    }
}
package Yue.LexicalAnalyzer;
/*
 * Token父类
 */
public class Token {
    public final int tag;
    public int line = 1;
    public String name = "";
    public int pos = 0;
    public Token(int t) {
        this.tag = t;
    }
    public String toString() {
        return "" + (char) tag;
    }
}
package Yue.LexicalAnalyzer;
/*
 * 单词类别赋值
 */
public class Tag {
    public final static int
            BEGIN = 1,          //保留字
            END = 2,            //保留字
            INTEGER = 3,        //保留字
            FUNCTION = 4,       //保留字
            READ = 5,           //保留字
            WRITE = 6,          //保留字
            IF = 7,             //保留字
            THEN = 8,           //保留字
            ELSE = 9,           //保留字
            SYMBOL = 11,        //标识符
            CONSTANT = 12,      //常数
            ADD = 13,           //运算符 "+"
            SUB = 14,           //运算符 "-"
            MUL = 15,           //运算符 "*"
            DIV = 16,           //运算符 "/"
            LE = 18,            //运算符 "<="
            GE = 19,            //运算符 ">="
            NE = 20,            //运算符 "!="
            ASSIGN = 23,        //运算符 ":="
            LPAR = 24,          //界符 "("
            RPAR = 25,          //界符 ")"
            SEM = 26,           //界符 ";"
            LINE_END = 27,      //行尾符
            ALL_END = 28;       //结尾符 "#"
}
package Yue.LexicalAnalyzer;
/**
 * 保留字
 */
public class KeyWord extends Token {
    public String lexme = "";
    public KeyWord(String s, int t) {
        super(t);
        this.lexme = s;
        this.name = "保留字";
    }
    public String toString() {
        return this.lexme;
    }
    public static final KeyWord
            begin = new KeyWord("begin", Tag.BEGIN),
            end = new KeyWord("end", Tag.END),
            integer = new KeyWord("integer", Tag.INTEGER),
            function = new KeyWord("function", Tag.FUNCTION),
            read = new KeyWord("read", Tag.READ),
            write = new KeyWord("write", Tag.WRITE),
            aIf = new KeyWord("if", Tag.IF),
            aThen = new KeyWord("then", Tag.THEN),
            aElse = new KeyWord("else", Tag.ELSE);
}
package Yue.LexicalAnalyzer;
/*
 * 标识符
 */
public class Symbol extends Token {
    public String lexme = "";
    public Symbol(String s) {
        super(Tag.SYMBOL);
        this.lexme = s;
        this.name = "标识符";
    }
    public String toString() {
        return this.lexme;
    }
}
package Yue.LexicalAnalyzer;
/**
 * 运算符
 */
public class CalcWord extends Token {
    public String lexme = "";
    public CalcWord(String s, int t) {
        super(t);
        this.lexme = s;
        this.name = "运算符";
    }
    public String toString() {
        return this.lexme;
    }
    public static final CalcWord
            add = new CalcWord("+", Tag.ADD),
            sub = new CalcWord("-", Tag.SUB),
            mul = new CalcWord("*", Tag.MUL),
            div = new CalcWord("/", Tag.DIV),
            le = new CalcWord("<=", Tag.LE),
            ge = new CalcWord(">=", Tag.GE),
            ne = new CalcWord("!=", Tag.NE),
            assign = new CalcWord(":=", Tag.ASSIGN);
}
package Yue.LexicalAnalyzer;
/**
 * 界符
 */
public class Delimiter extends Token {
    public String lexme = "";
    public Delimiter(String s, int t) {
        super(t);
        this.lexme = s;
        this.name = "界符";
    }
    public String toString() {
        return this.lexme;
    }
    public static final Delimiter
            lpar = new Delimiter("(", Tag.LPAR),
            rpar = new Delimiter(")", Tag.RPAR),
            sem = new Delimiter(";", Tag.SEM);
}
package Yue.LexicalAnalyzer;
/*
 * 常数
 */
public class Num extends Token {
    public final int value;
    public Num(int v) {
        super(Tag.CONSTANT);
        this.value = v;
        this.name = "常数";
    }
    public String toString() {
        return "" + value;
    }
}
package Yue.LexicalAnalyzer;
/**
 * 行尾符
 */
public class LineEnd extends Token {
    public String lexme = "";
    public LineEnd(String s) {
        super(Tag.LINE_END);
        this.lexme = s;
        this.name = "行尾符";
    }
    public String toString() {
        return this.lexme;
    }
    public static final LineEnd lineEnd = new LineEnd("\r\n");
}
package Yue.LexicalAnalyzer;
/**
 * 结尾符
 */
public class AllEnd extends Token {
    public String lexme = "";
    public AllEnd(String s) {
        super(Tag.ALL_END);
        this.lexme = s;
        this.name = "结尾符";
    }
    public String toString() {
        return this.lexme;
    }
    public static final AllEnd allEnd = new AllEnd("#");
}
用Java语言实现简单的词法分析器的更多相关文章
- Java语言实现简单FTP软件------>FTP软件主界面的实现(四)
		首先看一下该软件的整体代码框架 1.首先介绍程序的主入口FTPMain.java,采用了一个漂亮的外观风格 package com.oyp.ftp; im ... 
- Java语言实现简单FTP软件------>源码放送(十三)
		Java语言实现简单FTP软件------>FTP协议分析(一) Java语言实现简单FTP软件------>FTP软件效果图预览之下载功能(二) Java语言实现简单FTP软件----- ... 
- Java语言实现简单FTP软件------>上传下载管理模块的实现(十一)
		1.上传本地文件或文件夹到远程FTP服务器端的功能. 当用户在本地文件列表中选择想要上传的文件后,点击上传按钮,将本机上指定的文件上传到FTP服务器当前展现的目录,下图为上传子模块流程图 选择好要上传 ... 
- Java语言的简单基础
		1.Java 是一种高级程序设计语言. 2.Java 是大小敏感的程序语言. 3.Java 中的 public 修饰的类名一般要与文件名相同,但也有特列:内部类. 4.Java 程序能在任何操作系统中 ... 
- 设计模式(Java语言)- 简单工厂模式
		简单工厂模式有称为静态工厂模式,属于设计模式中的创建型模式.简单工厂模式通过对外提供一个静态方法来统一为类创建实例.简单工厂模式的目的是实现类与类之间解耦,其次是客户端不需要知道这个对象是如何被穿创建 ... 
- java语言实现简单接口工具--粗简版
		2016注定是变化的一年,忙碌.网红.项目融资失败,现在有点时间整整帖子~~ 目标: 提高工作效率与质量,能支持平台全量接口回归测试与迭代测试也要满足单一接口联调测试. 使用人员: 测试,开发 工具包 ... 
- Java语言实现简单FTP软件------>FTP软件本地窗口的实现(五)
		1.首先看一下本地窗口的布局效果 2.看一下本地窗口实现的代码框架 2.本地窗口的具体实现代码LocalPanel.java package com.oyp.ftp.panel.local; impo ... 
- Java语言实现简单FTP软件------>FTP软件远程窗口的实现(六)
		1.首先看一下远程窗口的布局效果 2.看一下本地窗口实现的代码框架 3.远程窗口主要实现代码FtpPanel.java package com.oyp.ftp.panel.ftp; import ja ... 
- Java语言实现简单FTP软件------>上传下载队列窗口的实现(七)
		1.首先看一下队列窗口的界面 2.看一下上传队列窗口的界面 3.看一下下载队列窗口的界面 4.队列窗口的实现 package com.oyp.ftp.panel.queue; import stati ... 
随机推荐
- springboot如何测试打包部署
			有很多网友会时不时的问我,spring boot项目如何测试,如何部署,在生产中有什么好的部署方案吗?这篇文章就来介绍一下spring boot 如何开发.调试.打包到最后的投产上线. 开发阶段 单元 ... 
- Python标准库概览
			Python标准库通常被称为"自带的电池",自然地提供了广泛的功能,涵盖了大概200个左右的包与模块.不断有高质量的包或模块被开发出来,极大的丰富了标准库.但有些模块放在标准库中很 ... 
- Android KeyCode 列表
			基本按键 KEYCODE_0 按键'0' 7 KEYCODE_1 按键'1' 8 KEYCODE_2 按键'2' 9 KEYCODE_3 按键'3' 10 KEYCODE_4 按键'4' 11 KEY ... 
- fitnesse - 用例创建编辑、管理、执行和日志
			fitnesse - 用例创建编辑.管理.执行和日志 2017-10-09 目录 1 用例创建编辑 1.1 用例创建 1.2 用例编辑2 用例管理3 用例测试执行和日志 3.1 用例测试执行 ... 
- java--Object类接受任意引用数据类型对象
			java学习进展到类,首先就对万类之父Object类进行举例练习,这里我是对一维数组和接口用Object接受数组和接口. package test1; public class enum1 { pub ... 
- Handsontable添加超链接
			本文在上文的基础上,返回的数据中多了一个link超链接跳转的字段,,需要在Handsontable中显示超链接. <!DOCTYPE html> <html> <head ... 
- Firefox取消“订阅实时书签”功能
			如果你勾选了Firefox“总是用实时书签订阅收取”, 一打开RSS页面就直接弹出添订阅实时书签对话,而当你想在火狐中直接查看RSS页面时,发现不知如何取消“订阅实时书签”功能了.就怨这个关闭功能藏的 ... 
- cxGrid_Q31584 cxgrid 拖放移动记录
			cxgrid 拖放移动记录,cxgrid 拖放,cxgrid 拖动记录,cxgrid 鼠标拖动记录 这是cxgrid开发公司回复客户时所发送的源码项目,用于实现鼠标拖动记录,改变记录在表格中的位置,所 ... 
- Filecoin:募资详情和Token分发详情
			基本情况 总数:20亿枚 参与资格:美国合格投资人身份认证(采用与IPO相同的流程,以确保合法性) 爱西欧占比:10%(2亿枚) 爱西欧总金额:2.57亿美元 私募 时间:2017.7.21~2017 ... 
- 戴尔R720xd服务器系统安装
			型号:R720xd 开启服务器,Ctrl+R进入raid配置 配置完raid后F2对硬盘进行格式化 保存并重启 F11进入BIOS选项设置U盘启动 选择U盘启动 开始进行系统安装! 
