在 ANTLR 3 中,如何在运行时而不是提前生成词法分析器(和解析器)? [英] In ANTLR 3, how do I generate a lexer (and parser) at runtime instead of ahead of time?

查看:26
本文介绍了在 ANTLR 3 中,如何在运行时而不是提前生成词法分析器(和解析器)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在运行时生成一个 antlr 词法分析器——也就是说,生成语法并在运行时从语法生成词法分析器类及其支持位.我很高兴将它提供给 java 编译器,它可以在运行时访问.

解决方案

这是一种快速而肮脏的方法:

  1. 生成一个组合(!)ANTLR语法.g文件,给定一个字符串作为语法源,
  2. 并创建一个解析器 &来自这个 .g 文件的词法分析器,
  3. 编译这些 Parser &词法分析器 .java 文件,
  4. 创建解析器的实例 &词法分析器类并调用解析器的入口点.

Main.java

import java.io.*;导入 javax.tools.*;导入 java.lang.reflect.*;导入 org.antlr.runtime.*;导入 org.antlr.Tool;公共课主要{public static void main(String[] args) 抛出异常 {//将解析的字符回显到控制台的语法,//跳过任何空白字符.最终字符串语法 ="语法 T;\n" +" \n" +"解析\n" +" : (ANY {System.out.println(\"ANY=\" + $ANY.text);})* EOF \n" +" ; \n" +" \n" +"空格\n" +" : (' ' | '\\t' | '\\r' | '\\n') {skip();} \n" +" ; \n" +" \n" +"任何\n" +" : . \n" +" ; ";最终字符串语法名称 = "T";final String entryPoint = "解析";//1 - 将 `.g` 语法文件写入磁盘.Writer out = new BufferedWriter(new FileWriter(new File(grammarName + ".g")));out.write(语法);关闭();//2 - 生成词法分析器和解析器.Tool tool = new Tool(new String[]{grammarName + ".g"});工具进程();//3 - 编译词法分析器和解析器.JavaCompiler 编译器 = ToolProvider.getSystemJavaCompiler();compiler.run(null, System.out, System.err, "-sourcepath", "",grammarName + "Lexer.java");compiler.run(null, System.out, System.err, "-sourcepath", "",grammarName + "Parser.java");//4 - 使用动态创建的词法分析器解析命令行参数并//带有一点反射 Voodoo 的解析器 :)词法分析器 lexer = (Lexer)Class.forName(grammarName + "Lexer").newInstance();lexer.setCharStream(new ANTLRStringStream(args[0]));CommonTokenStream 令牌 = new CommonTokenStream(lexer);类parserClass = Class.forName(grammarName + "Parser");构造函数 parserCTor = parserClass.getConstructor(TokenStream.class);解析器 parser = (Parser)parserCtor.newInstance(tokens);方法 entryPointMethod = parserClass.getMethod(entryPoint);entryPointMethod.invoke(解析器);}}

在像这样(在 *nix 上)编译和运行之后:

java -cp .:antlr-3.2.jar Main "a b c"

或在 Windows 上

java -cp .;antlr-3.2.jar Main "a b c"

,产生以下输出:

<前>任何=一个任何=b任何=c

I want to generate an antlr lexer at runtime -- that is, generate the grammar and from the grammar generate the lexer class, and its supporting bits at runtime. I am happy to feed it into the the java compiler, which is accessible at runtime.

解决方案

Here's a quick and dirty way to:

  1. generate a combined (!) ANTLR grammar .g file given a String as grammar-source,
  2. and create a Parser & Lexer from this .g file,
  3. compile the these Parser & Lexer .java files,
  4. create instances of the Parser & Lexer classes and invoke the entry point of the parser.

Main.java

import java.io.*;
import javax.tools.*;
import java.lang.reflect.*;
import org.antlr.runtime.*;
import org.antlr.Tool;

public class Main {

    public static void main(String[] args) throws Exception {

        // The grammar which echos the parsed characters to theconsole,
        // skipping any white space chars.
        final String grammar =
                "grammar T;                                                  \n" +
                "                                                            \n" +
                "parse                                                       \n" +
                "  :  (ANY {System.out.println(\"ANY=\" + $ANY.text);})* EOF \n" +
                "  ;                                                         \n" +
                "                                                            \n" +
                "SPACE                                                       \n" +
                "  :  (' ' | '\\t' | '\\r' | '\\n') {skip();}                \n" +
                "  ;                                                         \n" +
                "                                                            \n" +
                "ANY                                                         \n" +
                "  :  .                                                      \n" +
                "  ;                                                           ";
        final String grammarName = "T";
        final String entryPoint = "parse";

        // 1 - Write the `.g` grammar file to disk.
        Writer out = new BufferedWriter(new FileWriter(new File(grammarName + ".g")));
        out.write(grammar);
        out.close();

        // 2 - Generate the lexer and parser.
        Tool tool = new Tool(new String[]{grammarName + ".g"});
        tool.process();

        // 3 - Compile the lexer and parser.
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        compiler.run(null, System.out, System.err, "-sourcepath", "", grammarName + "Lexer.java");
        compiler.run(null, System.out, System.err, "-sourcepath", "", grammarName + "Parser.java");

        // 4 - Parse the command line parameter using the dynamically created lexer and 
        //     parser with a bit of reflection Voodoo :)
        Lexer lexer = (Lexer)Class.forName(grammarName + "Lexer").newInstance();
        lexer.setCharStream(new ANTLRStringStream(args[0]));
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        Class<?> parserClass = Class.forName(grammarName + "Parser");
        Constructor parserCTor = parserClass.getConstructor(TokenStream.class);
        Parser parser = (Parser)parserCTor.newInstance(tokens);
        Method entryPointMethod = parserClass.getMethod(entryPoint);
        entryPointMethod.invoke(parser);
    }
}

Which, after compiling and running it like this (on *nix):

java -cp .:antlr-3.2.jar Main "a b    c"

or on Windows

java -cp .;antlr-3.2.jar Main "a b    c"

, produces the following output:

ANY=a
ANY=b
ANY=c

这篇关于在 ANTLR 3 中,如何在运行时而不是提前生成词法分析器(和解析器)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆