In ANTLR 3, how do I generate a lexer (and parser) at runtime instead of ahead of time?

前端 未结 3 2065
小鲜肉
小鲜肉 2021-02-06 13:56

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 fe

相关标签:
3条回答
  • 2021-02-06 14:25

    Have you tried calling org.antlr.Tool.main(String[]) with an appropriate String[] argument?

    If that's too cumbersome, you could reverse engineer the Tool class (source code) to figure out how it works, and how to do the specific tasks you need to do.

    0 讨论(0)
  • 2021-02-06 14:31

    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
    
    0 讨论(0)
  • 2021-02-06 14:33

    You'll have to use org.antlr.Tool() class to get it working.

    You can check ANTLRWorks source code on github to have an idea how to use it, specifically the generate() method here:

    ErrorListener el = ErrorListener.getThreadInstance();
    ErrorManager.setErrorListener(el);
    
    String[] params;
    if(debug)
        params = new String[] { "-debug", "-o", getOutputPath(), "-lib", window.getFileFolder(), window.getFilePath() };
    else
        params = new String[] { "-o", getOutputPath(), "-lib", window.getFileFolder(), window.getFilePath() };
    
    new File(getOutputPath()).mkdirs();
    
    Tool antlr = new Tool(Utils.concat(params, AWPrefs.getANTLR3Options()));
    antlr.process();
    
    boolean success = !el.hasErrors();
    if(success) {
        dateOfModificationOnDisk = window.getDocument().getDateOfModificationOnDisk();
    }
    lastError = el.getFirstErrorMessage();
    el.clear();
    ErrorManager.removeErrorListener();
    return success;
    
    0 讨论(0)
提交回复
热议问题