В ANTLR 3, как я могу генерировать лексер (и парсер) во время выполнения, а не раньше времени? - PullRequest
5 голосов
/ 23 апреля 2011

Я хочу сгенерировать лексер antlr во время выполнения, то есть сгенерировать грамматику, а из грамматики сгенерировать класс лексера и его вспомогательные биты во время выполнения. Я рад передать его в компилятор Java, который доступен во время выполнения.

Ответы [ 3 ]

8 голосов
/ 27 апреля 2011

Вот быстрый и грязный способ:

  1. создает объединенный (!) Файл ANTLR грамматики .g, в котором в качестве источника грамматики указана строка,
  2. и создайте Parser & Lexer из этого .g файла,
  3. скомпилируйте эти файлы Parser & Lexer .java,
  4. создает экземпляры классов Parser & Lexer и вызывает точку входа синтаксического анализатора.

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);
    }
}

Который после компиляции и запуска так (на * nix):

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

или в Windows

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

, выдает следующий вывод:

ANY=a
ANY=b
ANY=c
3 голосов
/ 23 апреля 2011

Вам нужно будет использовать org.antlr.Tool() класс, чтобы он заработал.

Вы можете проверить ANTLRWorks исходный код на github, чтобы иметь представление о том, как его использовать, в частности, метод generate() здесь :

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;
2 голосов
/ 23 апреля 2011

Вы пытались вызвать org.antlr.Tool.main(String[]) с соответствующим аргументом String []?

Если это слишком громоздко, вы можете провести обратный инжиниринг класса Tool ( исходный код ), чтобы вычислитьо том, как это работает, и как делать конкретные задачи, которые вам нужно сделать.

...