Как программно генерировать файлы .class?

Я хотел бы написать компилятор для игрушечного языка для Java. Я хотел бы создать исполняемые файлы .class. Мне было интересно, какая лучшая библиотека или инструмент доступны для этого? Я знаю, что я мог бы изучить двоичный формат для всех инструкций и построить собственный собственный пул и т.д., Но это похоже на работу, которая должна была быть уже выполнена: нет смысла изобретать колесо, правильно?

Поиск в Интернете Я нашел два разных языка Java-ассемблера, Jasmin и Jamaica, однако только Jasmin выглядит несколько поддерживаемым.

Есть ли библиотека Java для записи байтовых кодов в поток? Это то, что Apache BCEL?

Является ли их инструментом для этого, который является "стандартным" для генерации байтового кода, например Antlr для разбора?


PS- Язык игрушек Brainf ***, я хотел что-то, где у меня могла бы быть простая "грамматика", чтобы я мог сосредоточиться на а не парсинг-части..., который будет представлен позже на следующем шаге.

Ответ 1

ASM и BCEL в основном подобные вещи. Я бы рекомендовал ASM, поскольку он намного более поддерживается, намного меньше и обновлен JDK-мудрый.

Ответ 2

Похоже, вы ищете Apache BCEL:

Библиотека разработки байтового кода (Apache Commons BCEL ™) предназначена для предоставления пользователям удобного способа анализа, создания и обработки (двоичных) файлов классов Java (те, которые заканчиваются на .class).

Ответ 3

JDK 1.6 имеет возможность динамически компилировать классы Java (см. getSystemJavaCompiler). Это можно использовать для компиляции Java из исходного кода без манипулирования байтовым кодом или временных файлов. Мы делаем это как способ улучшить производительность некоторого кода API отражения, но он также будет легко служить вашей цели.

Создайте исходный файл Java из строки, содержащей код:

   public class JavaSourceFromString extends SimpleJavaFileObject {
       final String code;

       JavaSourceFromString(String name, String code) {
           super(URI.create("string:///"
                            + name.replace('.','/')
                            + Kind.SOURCE.extension),
                 Kind.SOURCE);
           this.code = code;
       }

       @Override
       public CharSequence getCharContent(boolean ignoreEncodingErrors) {
           return code;
       }
   }

// Use your favorite template language here, like FreeMarker
static final String sourceCode = ""
        + "import org.example.MySomethingObject;"
        // DynamicStringGetter would define getString as a standard way to get
        // a String from an object
        + "public class GetStringDynamic implements DynamicStringGetter {\n" 
        + "    public String getString(Object o) {\n"
        + "        MySomethingObject obj = (MySomethingObject) o;\n"
        + "        return o.getSomething();\n"
        + "    }\n"
        + "}\n";

   JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
   StandardJavaFileManager fileManager = 
       compiler.getStandardFileManager(null, null, null);

   List<JavaFileObject> files = new ArrayList<JavaFileObject>();
   files.add(new JavaSourceFromString("org.example.DynamicClass", sourceCode));

   compiler.getTask(null, fileManager, null, null, null, files).call();

Затем вы загружаете вновь созданные файлы классов динамически.

В качестве альтернативы, используйте манипуляции с байтовым кодом (например, ASM), чтобы создавать классы "на лету".

В качестве другой альтернативы существует Scala библиотека компиляции байт-кода CAFEBABE. Я не использовал его лично, но он больше ориентирован на создание нового языка JVM.

Что касается части синтаксического анализа, то должен служить Antlr.

Ответ 4

Проще всего было бы перевести ваш игрушечный язык в действительный исходный код .java, используя препроцессор, а затем просто скомпилировать его с помощью javac. Это также работает Processing.