当前位置: 首页 > 知识库问答 >
问题:

Java中的词法分析器

陆子默
2023-03-14

我一直在尝试用java编写一个简单的词法分析器。

File Token.java如下:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public enum Token {

    TK_MINUS ("-"), 
    TK_PLUS ("\\+"), 
    TK_MUL ("\\*"), 
    TK_DIV ("/"), 
    TK_NOT ("~"), 
    TK_AND ("&"),  
    TK_OR ("\\|"),  
    TK_LESS ("<"),
    TK_LEG ("<="),
    TK_GT (">"),
    TK_GEQ (">="), 
    TK_EQ ("=="),
    TK_ASSIGN ("="),
    TK_OPEN ("\\("),
    TK_CLOSE ("\\)"), 
    TK_SEMI (";"), 
    TK_COMMA (","), 
    TK_KEY_DEFINE ("define"), 
    TK_KEY_AS ("as"),
    TK_KEY_IS ("is"),
    TK_KEY_IF ("if"), 
    TK_KEY_THEN ("then"), 
    TK_KEY_ELSE ("else"), 
    TK_KEY_ENDIF ("endif"),
    OPEN_BRACKET ("\\{"),
    CLOSE_BRACKET ("\\}"),
    DIFFERENT ("<>"),

    STRING ("\"[^\"]+\""),
    INTEGER ("\\d"), 
    IDENTIFIER ("\\w+");

    private final Pattern pattern;

    Token(String regex) {
        pattern = Pattern.compile("^" + regex);
    }

    int endOfMatch(String s) {
        Matcher m = pattern.matcher(s);

        if (m.find()) {
            return m.end();
        }
        return -1;
    }
}

Lexer如下:Lexer。JAVA

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;

public class Lexer {
    private StringBuilder input = new StringBuilder();
    private Token token;
    private String lexema;
    private boolean exausthed = false;
    private String errorMessage = "";
    private Set<Character> blankChars = new HashSet<Character>();

    public Lexer(String filePath) {
        try (Stream<String> st = Files.lines(Paths.get(filePath))) {
            st.forEach(input::append);
        } catch (IOException ex) {
            exausthed = true;
            errorMessage = "Could not read file: " + filePath;
            return;
        }

        blankChars.add('\r');
        blankChars.add('\n');
        blankChars.add((char) 8);
        blankChars.add((char) 9);
        blankChars.add((char) 11);
        blankChars.add((char) 12);
        blankChars.add((char) 32);

        moveAhead();
    }

    public void moveAhead() {
        if (exausthed) {
            return;
        }

        if (input.length() == 0) {
            exausthed = true;
            return;
        }

        ignoreWhiteSpaces();

        if (findNextToken()) {
            return;
        }

        exausthed = true;

        if (input.length() > 0) {
            errorMessage = "Unexpected symbol: '" + input.charAt(0) + "'";
        }
    }

    private void ignoreWhiteSpaces() {
        int charsToDelete = 0;

        while (blankChars.contains(input.charAt(charsToDelete))) {
            charsToDelete++;
        }

        if (charsToDelete > 0) {
            input.delete(0, charsToDelete);
        }
    }

    private boolean findNextToken() {
        for (Token t : Token.values()) {
            int end = t.endOfMatch(input.toString());

            if (end != -1) {
                token = t;
                lexema = input.substring(0, end);
                input.delete(0, end);
                return true;
            }
        }

        return false;
    }

    public Token currentToken() {
        return token;
    }

    public String currentLexema() {
        return lexema;
    }

    public boolean isSuccessful() {
        return errorMessage.isEmpty();
    }

    public String errorMessage() {
        return errorMessage;
    }

    public boolean isExausthed() {
        return exausthed;
    }
}

并且可以用Try.java测试如下:

public class Try {

    public static void main(String[] args) {

        Lexer lexer = new Lexer("C:/Users/Input.txt");

        System.out.println("Lexical Analysis");
        System.out.println("-----------------");
        while (!lexer.isExausthed()) {
            System.out.printf("%-18s :  %s \n",lexer.currentLexema() , lexer.currentToken());
            lexer.moveAhead();
        }

        if (lexer.isSuccessful()) {
            System.out.println("Ok! :D");
        } else {
            System.out.println(lexer.errorMessage());
        }
    }
}

说出输入。txt有

define mine 
a=1000;
b=23.5;

我期望的输出是

define : TK_KEYWORD
mine : IDENTIFIER
a : IDENTIFIER
= : TK_ASSIGN
1000 : INTEGER
; : TK_SEMI
b : IDENTIFIER
= : TK_ASSIGN
23.5 : REAL

但我面临的问题是:它把每个数字都当作

1 INTEGER
0 INTEGER
0 INTEGER
0 INTEGER

而且它不能识别实数。我得到:

意外符号:'.'

为了达到预期的效果,需要做哪些改变?

共有1个答案

陈高寒
2023-03-14

匹配整数的模式是:

INTEGER ("\\d"), 

正好匹配一个数字。

如果你想要一个以上,去

INTEGER ("\\d+"), 

例如

为了完成,浮点数缺失的另一个模式可能看起来像

REAL ("(\\d+)\\.\\d+")

正如评论指出的那样。或

REAL ("(\\d*)\\.\\d+")

使允许

.23

太-如果这是你正在寻找的!

 类似资料:
  • 一个高级语言程序在计算机中一般以文件形式存在,文件是一堆字节的集合,而它要表达的含义显然不是一堆字节,最小单位是一个个词,因此编译一个程序,一开始的工作就是词法分析 龙书的词法分析部分,掺杂了很多自动机相关的东西,其实这些在计算理论有更详细的描述,在编译原理里面讲大概是希望能让零基础的人看懂,可惜这样一来内容就比较臃肿,而且好像也讲的不是很系统反而让人看糊涂,就好像算法导论里面讲NP一样,虽然没有

  • 2. 词法分析 Python程序由解析器读取。输入到解析器中的是由词法分析器生成的词符流。本章讲述词法分析器如何把一个文件拆分成词符。 Python程序的文本使用7比特ASCII字符集。 2.3版中新增:可以使用编码声明指出字符串字面值和注释使用一种不同于ASCII的编码。 为了和旧的版本兼容,如果发现8比特字符,Python只会给出警告。修正这些警告的方法是声明显式的编码,或者对非字符的二进制数

  • 上一篇文章讲到了状态机和词法分析的基本知识,这一节我们来分析Jsoup是如何进行词法分析的。 代码结构 先介绍以下parser包里的主要类: Parser Jsoup parser的入口facade,封装了常用的parse静态方法。可以设置maxErrors,用于收集错误记录,默认是0,即不收集。与之相关的类有ParseError,ParseErrorList。基于这个功能,我写了一个PageEr

  • 因为词法规则可以使用递归,所以词法解析器在技术上和语法解析器一样强大。那意味着我们甚至可以在词法分析器中匹配语法结构。或者,在另一个极端,我们可以把字符当作记号,使用语法分析器去把语法结构应用到字符流(这种被称为无扫描语法分析器)。这导致什么在词法分析器中匹配和什么在语法分析器中匹配的界线在哪里并不是很明显。幸运的是,有几条经验法则可以让我们做出判断: 在词法分析器中匹配和丢弃任何语法分析器根本不

  • 本文向大家介绍什么是词法分析?请描述下js词法分析的过程?相关面试题,主要包含被问及什么是词法分析?请描述下js词法分析的过程?时的应答技巧和注意事项,需要的朋友参考一下 词法分析指的是js引擎在执行前的编译过程之一。 词法分析和分词其实都是对js代码分割的一个过程。 词法分析大概分为三步骤,分析参数,分析变量声明,分析函数声明。 首先如果存在函数,分析函数的参数分别是什么。 其次 分析每一个变量

  • 12.1. 概述 词法分析器用于读取各种格式的数据,这些数据可以具有灵活但可能非常复杂的结构。 关于"格式"的一个最好的例子就是 C++ 代码。 编译器的词法分析器必须理解 C++ 的各种可能的语言结构组合,以将它们翻译为某种二进制形式。 开发词法分析器的主要问题是所分析的数据的组成结构具有大量的规则。 例如,C++ 支持很多的语言结构,开发一个相应的词法分析器可能需要无数个 if 表达式来识别任