java - 制作词法分析器

标签 java analyzer lexical

我现在正在使用词法分析器程序,并且使用 Java。我一直在研究这个问题的答案,但到目前为止我还没有找到任何答案。这是我的问题:

输入:

System.out.println ("Hello World");

期望的输出:

Lexeme----------------------Token

System [Key_Word]

.       [Object_Accessor]

out   [Key_Word]

. [Object_Accessor]

println  [Key_Word]

(  [left_Parenthesis]

"Hello World"    [String_Literal]

)   [right_Parenthesis]

;  [statement_separator]

我还是个初学者,希望大家能帮助我。谢谢。

最佳答案

你不需要 ANTLR 也不需要 Dragon 书来手动编写一个简单的词法分析器。即使是更完整的语言(如 Java)的词法分析器,手工编写也不是很复杂。显然,如果您有一项工业任务,您可能需要考虑工业强度工具,例如 ANTLR 或某些 lex 变体,但为了了解词法分析的工作原理,手动编写一个工具可能会被证明是一种有用的练习。我假设情况确实如此,因为您说您仍然是初学者。

这是一个简单的词法分析器,用 Java 编写,用于类方案语言的子集,是我在看到这个问题后编写的。我认为即使您以前从未见过词法分析器,代码也相对容易理解,因为将字符流(在本例中为 String )分解为标记流(在本例中为 List<Token> )并不难。如果您有疑问,我可以尝试更深入地解释。

import java.util.List;
import java.util.ArrayList;

/*
 * Lexical analyzer for Scheme-like minilanguage:
 * (define (foo x) (bar (baz x)))
 */
public class Lexer {
    public static enum Type {
        // This Scheme-like language has three token types:
        // open parens, close parens, and an "atom" type
        LPAREN, RPAREN, ATOM;
    }
    public static class Token {
        public final Type t;
        public final String c; // contents mainly for atom tokens
        // could have column and line number fields too, for reporting errors later
        public Token(Type t, String c) {
            this.t = t;
            this.c = c;
        }
        public String toString() {
            if(t == Type.ATOM) {
                return "ATOM<" + c + ">";
            }
            return t.toString();
        }
    }

    /*
     * Given a String, and an index, get the atom starting at that index
     */
    public static String getAtom(String s, int i) {
        int j = i;
        for( ; j < s.length(); ) {
            if(Character.isLetter(s.charAt(j))) {
                j++;
            } else {
                return s.substring(i, j);
            }
        }
        return s.substring(i, j);
    }

    public static List<Token> lex(String input) {
        List<Token> result = new ArrayList<Token>();
        for(int i = 0; i < input.length(); ) {
            switch(input.charAt(i)) {
            case '(':
                result.add(new Token(Type.LPAREN, "("));
                i++;
                break;
            case ')':
                result.add(new Token(Type.RPAREN, ")"));
                i++;
                break;
            default:
                if(Character.isWhitespace(input.charAt(i))) {
                    i++;
                } else {
                    String atom = getAtom(input, i);
                    i += atom.length();
                    result.add(new Token(Type.ATOM, atom));
                }
                break;
            }
        }
        return result;
    }

    public static void main(String[] args) {
        if(args.length < 1) {
            System.out.println("Usage: java Lexer \"((some Scheme) (code to) lex)\".");
            return;
        }
        List<Token> tokens = lex(args[0]);
        for(Token t : tokens) {
            System.out.println(t);
        }
    }
}

使用示例:

~/code/scratch $ java Lexer ""
~/code/scratch $ java Lexer "("
LPAREN
~/code/scratch $ java Lexer "()"
LPAREN
RPAREN
~/code/scratch $ java Lexer "(foo)"
LPAREN
ATOM<foo>
RPAREN
~/code/scratch $ java Lexer "(foo bar)"
LPAREN
ATOM<foo>
ATOM<bar>
RPAREN
~/code/scratch $ java Lexer "(foo (bar))"
LPAREN
ATOM<foo>
LPAREN
ATOM<bar>
RPAREN
RPAREN

一旦您编写了一两个像这样的简单词法分析器,您就会很好地了解这个问题是如何分解的。那么探索如何使用像 lex 这样的自动化工具将会很有趣。基于正则表达式的匹配器背后的理论并不太难,但确实需要一段时间才能完全理解。我认为手工编写词法分析器可以激发学习的动力,并且可以帮助你更好地解决问题,而不是深入研究将正则表达式转换为有限自动化(首先是 NFA,然后是 NFA 到 DFA)等背后的理论……一次性深入研究该理论可能会需要大量的知识,而且很容易不知所措。

就我个人而言,虽然《龙》这本书很好而且非常全面,但其内容可能不是最容易理解的,因为它的目标是完整,而不一定是易于理解。在打开 Dragon 书之前,您可能想尝试一些其他编译器文本。这里有一些免费书籍,其中有很好的介绍性内容,恕我直言:

http://www.ethoberon.ethz.ch/WirthPubl/CBEAll.pdf

http://www.diku.dk/~torbenm/Basics/

一些关于正则表达式实现的文章(自动词法分析通常使用正则表达式)

http://swtch.com/~rsc/regexp/

关于java - 制作词法分析器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35803989/

相关文章:

java - 为什么这段代码中有Unhandled Exception?

java - ceiling , floor 将如何在 TreeSet of String 上表现

perl - 需要一个可以正常终止的词法作用域的结束

关于 C 中的词法错误的说明

html - : "" 之后的词法错误 <EOF>

java - 异常实用程序类必须注意的事项

java - 包含不区分大小写的方法而无需进行重大代码更改?

indexing - Elasticsearch : How to list each analyzer used by a specific index

elasticsearch - 语言分析器无法找到单一结果

elasticsearch - 多语言Elasticsearch索引