Статьи

ZeptoN переводит программу на Java

1. Введение

Язык программирования Java или «Java» был введен в 1995 году. Тем не менее, почти за четверть века он добавил функции, изначально не входившие в основной язык. К таким функциям относятся перечисления, обобщения, множество улучшений базового оператора функционального переключения в стиле C, утверждения и так далее. Java — это язык программирования, который со временем эволюционировал, чтобы удовлетворить потребности разработчиков программного обеспечения Java. Обратите внимание, что среда Java, как и во время выполнения и поддерживающих библиотеках, пакетах, инструментах и ​​утилитах, также добавила и удалила элементы (такие как оболочка Java и апплеты Java соответственно). Но здесь акцент делается на Java, языке программирования.

Успех и популярность Java привели к тому, что он используется для обучения кодированию. Экзамен AP (Advanced Placement) для информатики использует Java. Проблема с Java — это парадокс. С успехом Java, и многие разработчики, пишущие код Java, те, кто плохо знаком с программированием, те, кто пытается изучать программирование, забыты.

2. Проблема не в программировании

Однажды начинающий разработчик в 1980-х и 1990-х начал учиться кодировать с помощью вездесущего BASIC, а затем перешел на Pascal (или FORTRAN, C) и затем на более мощные объектно-ориентированные языки, такие как Objective-C, C ++, Smalltalk, Java. , В этой последовательности переход от элементарных концепций программирования, таких как переменные к константе, ввод или вывод, если операторы и т. Д. К объектам, классам, а затем к объектно-ориентированным принципам и шаблонам проектирования, был осуществлен в виде нескольких вещей, путь разработчика программного обеспечения.

Но новичку или «новичку» в изучении кода на Java приходится сталкиваться с множеством функций, которые либо следует игнорировать, но использовать, не зная, для чего эта функция полезна. Это подход «Не обращай внимания на человека за занавесом» (из «Волшебника страны Оз»). Или инопланетная особенность Java — еще одна особенность, которая добавляет к познавательной перегрузке; то есть «… ситуация, когда учитель одновременно дает слишком много информации или слишком много заданий учащимся, что приводит к тому, что ученик не может обработать эту информацию». [Брит 2019] Это миф о том, как новичок выбрасывает свой компьютер из окна в отчаянии, а затем теряет интерес к обучению программированию.

3. Объект программы

Таким образом, программированию на Java не хватает программной сущности, чтобы просто написать приложение или программу. Старые, структурированные языки программирования, такие как BASIC и Pascal, были не чем иным, как программным объектом. Так что из-за сложности, элегантности и мощных возможностей Java в ней отсутствует самая простая из всех возможностей — программа. Рассмотрим следующую классическую программу, но простую программу от BASIC, чтобы прочитать имя пользователя, а затем распечатать приветствие. [Wiki 2019a] Исходный код BASIC:

1
2
3
4
5
10 PRINT "what is your name?"
20 INPUT "...(Enter Your Name)...", a$
30 PRINT
40 PRINT "hello, "; a$; ", I am your computer, nice to meet you."
60 END

Та же основная программа в исходном коде Java:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
import java.util.Scanner;
 
class WhatIsYourName {
 
  private WhatIsYourName(){}
 
  public static void main(String[] args){
    System.out.println("what is your name?");
    System.out.print("...(Enter Your Name)...");
    String name = System.console().readLine();
    System.out.printf("hello, %s, I am your computer, nice to meet you.%n", name);
    System.exit(0);
  }//end main;
 
}//end class WhatIsYourName

Для сравнения, оба языка программирования достигают того же конечного результата, что и программа, читая имя пользователя и затем печатая ему приветствие. Однако версия Java требует раскрытия некоторых деталей, которые либо требуют дополнительного понимания, либо игнорируются. Рассмотрим некоторые из возможных вопросов, которые задаст новичок в отношении кода Java:

  1. Что такое класс?
  2. Что такое конструктор?
  3. Что такое пустой метод?

4. Все объектно-ориентированное

Есть много объектно-ориентированных функций, необходимых для такого простого и простого программного приложения, использующего Java. Для другого примера рассмотрим простое и печально известное «Привет, мир !!!» в бейсике против Java.

4.1 Программирование на Java с Zepton

Этот иллюстративный пример демонстрирует необходимость создания программной сущности. Подобно классу, за исключением того, что программа является единицей выполнения или приложения, а не объектом для повторного использования. Примером является та же BASIC-программа, но выраженная в ZeptoN как программа, а не класс Java:

01
02
03
04
05
06
07
08
09
10
prog WhatIsYourName {
 
begin
 
  println("what is your name?");
  print("...(Enter Your Name)..."); String name = readLine();
  printf("hello, %s, I am your computer, nice to meet you.%n", name);
  exit(0);
 
}//end prog WhatIsYourName

Программа ZeptoN намного удобнее для чтения, проста и компактна. Транскомпилятор ZeptoN [Gilr 2019b], когда он переносит программу ZeptoN в класс Java, автоматически создаст необходимый метод main (String [] args), а также некоторый исходный код «шаблона», который обеспечивает среду по умолчанию в ZeptoN.

Исходный код шаблона — это просто вызовы методов, которые заключены в открытый статический метод. Таким образом, «System.out.println (…)» — это просто «println (…)» с той же сигнатурой типа параметра. Или «System.exit (…)» — это просто «выход (…)» с тем же типом параметра.

Требуемые операторы импорта генерируются автоматически. В целом в исходном коде шаблона содержится около семидесяти методов и атрибутов. Важным принципом является то, что в ZeptoN мало специфических методов и атрибутов, а также то, что имя метода совпадает с одной и той же сигнатурой типа параметра. Таким образом, разработчик ZeptoN может без проблем вернуться на Java или с Java на ZeptoN.

4.2 Нестандартные методы в ZeptoN

Один нестандартный статический метод — «String [] getArgs ()», который получает аргументы программы командной строки. Другой — «void nop ()» для отсутствия операции для метода-заглушки. В Java есть пустой оператор, но «nop ()» более явный. Некоторыми нестандартными константами являются EMPTY_STRING, EMPTY_CHAR и NULL_CHAR.

Опять же, нестандартные методы и атрибуты ограничены несколькими и призваны избежать запутанного исходного кода Java. Стандартный метод «String readLine ()», но не требует использования сканера Java, BufferedReader или других классов. ZeptoN делает акцент на простоте и минимальности. И, как создатель, разработчик и первый программист ZeptoN, меня всегда раздражало, что у класса String нет магической константы EMPTY_STRING, или класса символов EMPTY_CHAR или NULL_CHAR. Я пытаюсь быть логичным, но я все еще … измучен. Но многие языки программирования часто имеют свои особенности дизайнера из своего опыта.

4.3 Краткое изложение ZeptoN

ZeptoN — это Java, но он трансформирует объект программы в класс из объекта программы, передает метод main () и добавляет набор стандартных методов и атрибутов, которые похожи на методы и атрибуты в других классах. Таким образом, создается среда по умолчанию для использования разработчиком. Это достаточно просто реализовать с использованием транскомпилятора, избегая лишних затрат и сложности полной реализации компилятора Java. Транскомпилятор транскомпилирует ZeptoN в Java, а затем API компилятора Java используется для компиляции в байт-код.

Для конкретной версии JDK ZeptoN «автоматически» обладает этими функциями. Так, например, если используется JDK 13, тогда текстовые блоки являются частью функции в ZeptoN. ZeptoN как Java включает в себя функции Java. Таким образом, для следующей версии Java, JDK 14, записи потенциально являются функцией, которая в JDK 14 находится в ZeptoN.

Теперь, когда ZeptoN является базовым транскомпилятором, можно расширить ZeptoN, добавив дополнительные функции, которые затем будут скомпилированы в Java. Цель состоит в том, чтобы добавить такую ​​функцию последовательно, но также избежать полной реализации компилятора. К счастью, в Java имеется богатый набор пакетов и классов, которые делают это возможным с некоторой работой и творческим подходом.

5. Расширение ZeptoN

Примитивные типы иногда мешают написанию Java и расширению ZeptoN. Таким образом, особенность заключается в том, чтобы автоматически конвертировать примитивные типы в тип оболочки класса в ZeptoN. Эта функция автоматического преобразования из примитивного типа в объектную форму (которую я называю «продвижение в объект») легко реализуется с помощью транскомпилятора. Аргументы выступают как за [Moor 2014], так и против [Alpe 2000] с использованием примитивных типов. Тем не менее, лучший подход — предоставить разработчику этот выбор при написании исходного кода в ZeptoN.

5.1 Примитивные типы

Спецификация языка Java, Java SE 13 Edition [Orac 2019] определяет тип примитива как «Примитивный тип предопределен языком программирования Java и назван его зарезервированным ключевым словом». Более описательным определением является примитивный тип, который является предопределенным значением в языке программирования Java. Типы «null» и «void» не входят в число примитивных типов.

Нулевое значение является значением ссылки по умолчанию, или «Нулевой тип имеет одно значение: нулевая ссылка, представленная нулевым литералом null» [Orac 2019] Тип void указывает метод с невозвращаемым значением или «Используется при объявлении и определении метода чтобы указать, что метод не возвращает никакого типа, метод возвращает void. Это не тип и нет пустых ссылок / указателей, как в C / C ++ ». [Wiki 2019b]

Поскольку ZeptoN — это Java, отсюда следует, что примитивные типы в точности похожи.

5.2 Типы обертки объектов

Примитивные типы эффективны, но это единственная «морщина» в Java, которая не является объектом. На примитивные типы не ссылаются и они не имеют объекта или состояния. Но тип объекта иногда необходим и полезен. Таким образом, Java предоставляет типы обертки объектов для объективизации примитивов.

Экель [Ecke 2003] описывает оболочки типов объектов как: «Классы« оболочки »для примитивных типов данных позволяют вам создать непримитивный объект в куче для представления этого примитивного типа».

Например, чтобы использовать типы примитивов с любой из коллекций Java, требуется тип примитива в качестве типа объекта. В Java есть функция автоматического преобразования примитивного типа в оболочку типа объекта.

5.3 Автобокс производительности

Существует функция автобокса (начиная с Java 5, таким образом, в ZeptoN), но более простой подход заключается в простом продвижении всех примитивных типов в объект. Java использует автобокс между большинством примитивов (исключая null и void), но существует разрыв между примитивным типом, таким как int, который просто является датумом, и типом оболочки Integer, который является объектом.

Еще одним важным фактором является производительность, и неограниченное и непреднамеренное использование автобокса может привести к проблемам с производительностью [статья DZone] в байт-коде Java. Одним из самых больших преимуществ этой функции продвижения на объекте является меньший объем кода для написания, а исходный код чище.

Два примитивных типа, null и void, не являются датумом и, следовательно, не повышаются до объекта. Восемь примитивных типов boolean, byte, char, double, float, int, long, short повышаются до объекта. Но типы объектов по сравнению с примитивными типами будут использовать больше памяти.

5.4 Прозрачный источник ZeptoN с примитивными типами

Рассмотрим следующую простую программу ZeptoN «polyMathPrimitive1.zep», которая вычисляет число по индексу в цикле for (отсюда и многочлен), но использует для вычисления тип примитива int. Статический метод «polyMathLoop» используется как метод для вызова из программного блока.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
package javacodegeeks;
 
prog polyMathPrimitive1 {
 
  static void polyMathLoop(final int loopLimit){
 
    for (int index = 0; index < loopLimit; index++) {
      int number = index * index * index + index * index + index;
    }//end for
 
  }//end polyMathLoop
 
begin
 
  long timeStart = nanoTime();
  polyMathLoop(1000);
  long timeClose = nanoTime();
  printf("Total time: %d nanosec%n",(timeClose-timeStart)); println();
  exit(0);
}

Метод polyMathLoop() вызывается с целочисленным литералом 1000. Метод на самом деле ничего не делает, за исключением многократного вычисления одного и того же полинома.

После компиляции с помощью компилятора ZeptoN и запуска:

1
2
3
/Users/williamgilreath$java -cp . Zep polyMathPrimitive.zep
/Users/williamgilreath$java -cp . javacodegeeks.polyMathPrimitive1
Total time: 18484 nanosec

Эквивалентный ZeptoN при переносе иллюстрируется программой ZeptoN «polyMathObject.zep»:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
package javacodegeeks;
 
prog polyMathObject {
 
static void polyMathLoop(final Integer loopLimit){
 
  for (Integer index = 0; index < loopLimit; index++) {
    Integer number = index * index * index + index * index + index;  
  }//end for
 
}//end polyMathLoop
 
begin
 
  long timeStart = nanoTime();
  polyMathLoop(1000);
  long timeClose = nanoTime();
  printf("Total time: %d nanosec%n",(timeClose-timeStart)); println();
  exit(0);
 
}

После компиляции с помощью компилятора ZeptoN и запуска:

1
2
3
/Users/williamgilreath$java -cp . ZepC polyMathObject.zep
/Users/williamgilreath$java -cp . javacodegeeks.polyMathObject
Total time: 512084 nanosec

Соотношение двух времен исполнения демонстрирует общее соотношение 1: 27,7 разницы. Ясно, что полное продвижение каждого примитива к типу объекта может быть проблематичным для производительности.

Рассмотрим альтернативный подход, при котором не каждое целое число в программе ZeptoN является примитивом типа int или оберткой объектов Integer. Исходный код ZeptoN:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
package javacodegeeks;
 
prog polyMathPrimitive2 {
 
  static void polyMathLoop(final Integer loopLimit){
    for (int index = 0; index < loopLimit; index++) {
      int number = index * index * index + index * index + index; 
    }//end for
  }//end polyMathLoop
 
begin
 
  long timeStart = nanoTime();
  polyMathLoop(1000);
  long timeClose = nanoTime();
  printf("Total time: %d nanosec%n",(timeClose-timeStart));
  println();
  exit(0);
}

После компиляции с помощью компилятора ZeptoN и запуска:

1
2
/Users/williamgilreath$java -cp . Zep polyMathPrimitive2.zep
/Users/williamgilreath$java -cp . javacodegeeks.polyMathPrimitive2 Total time: 92350 nanosec

Соотношение времени исполнения демонстрирует общее соотношение 1: 5. Это улучшение производительности по сравнению с реализацией типа обертки. Смешанный подход более эффективен в производительности.

5.5 Синтаксис функции «Продвижение на объект»

Примеры до и после иллюстрируют переход от примитива int к объекту-обертке Integer — все или ничего. На производительность явно влияют радикально. Тем не менее, есть также случаи, когда разработчик хочет указать, что примитивный тип остается примитивным типом, особенно в показателях производительности. Это отражает вышеупомянутый подход в этой функции, предоставляя разработчику выбор примитива или типа объекта.

Синтаксис является одним из исключений из перехода от примитивного типа к типу объекта. Для синтаксиса нормальный примитив без какого-либо другого индикатора повышается до типа объекта. Таким образом, int становится Integer, double становится Double, и так далее и так далее.

Синтаксис исключения «заимствован» из синтаксиса JavaCC [ref] для выражения правила грамматики, как объясняет Коупленд [Cope 2009]: «… это? квантификатор, который соответствует нулю или одному вхождению указанного шаблона ».

Примитивный тип, который исключен из продвижения по типу объекта, имеет завершающий «крючок» или «вопросительный знак» символа «?» после идентификатора, чтобы указать транскомпилятору не преобразовывать тип примитива в тип объекта. С символом ‘?’ примитивный тип остается примитивным типом. Таким образом, «Int?» преобразуется в «int», а не в «Integer», так как никакого перехода к типу объекта не происходит.

Переписывая оригинальный смешанный синтаксис примитивного типа и типа объекта, этот синтаксис в исходном коде ZeptoN:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
package javacodegeeks;
 
prog polyMathSyntax {
 
  static void polyMathLoop(final int loopLimit){
 
    for (int? index = 0; index < loopLimit; index++) {
      int? number = index * index * index + index * index + index;
    }//end for
  }//end polyMathLoop
 
begin
  long? timeStart = nanoTime();
  polyMathLoop(1000);
  long? timeClose = nanoTime();
  printf("Total time: %d nanosec%n",(timeClose-timeStart)); println();
  exit(0);
}

ZeptoN-программа «polyMathSyntax.zep» эквивалентна ZeptoN-программе «polyMathPrimitive2.zep» — после преобразования из синтаксиса в общий исходный код Java.

Синтаксис позволяет разработчику выбирать, остается ли примитив типом примитива или превращается в оболочку типа объекта. Таким образом, контроль контролирует разработчик, а не транскомпилятор ZeptoN. Синтаксис несколько знаком, похож на производственное правило JavaCC, синтаксис Kotlin для допустимой пустоты или синтаксис Swift для nil. Таким образом, синтаксис несколько знаком, хотя смысловой смысл совершенно другой.

6. Транспортер для синтаксиса функций

Синтаксис прост и знаком для определения примитивного типа остается примитивным. Вопрос заключается в том, как реализовать эту функцию в транскомпиляторе, чтобы ZeptoN трансформировался в исходный код Java. Но транскомпилятор ZeptoN уже будет транслировать исходный код ZeptoN в исходный код Java, который затем компилируется с использованием API компилятора Java.

Реализация программного обеспечения для передачи синтаксиса функции имеет две проблемы:

  1. Реализация транспонирования синтаксиса функции
  2. Использовать существующий транскомпилятор ZeptoN

Это классическая задача инженера по разработке программного обеспечения — реализовать функцию в существующем устаревшем программном обеспечении. Короче говоря, создайте новый алгоритм, а затем внедрите его в унаследованный код транскомпилятора ZeptoN.

6.1 Алгоритм для функции

Алгоритм для функции примитивного типа к типу объекта прост, и это больше процесс поиска и замены с регулярным выражением, чем любая более сложная компиляция.

Есть три шага к алгоритму:

  1. Переименуйте примитивы, чтобы остаться примитивом к промежуточному идентификатору
  2. Переименование примитивных типов в обертку типов объектов
  3. Переименуйте промежуточные идентификаторы в примитивные типы

На каждом шаге алгоритма результирующая символьная строка затем обрабатывается на следующем шаге последовательно, пока исходный источник ZeptoN с функцией синтаксиса не преобразуется в исходный код ZeptoN с типами примитивов и объектов.

6.1.1. Переименование примитива в промежуточный идентификатор

Этот первый шаг алгоритма сохраняет примитивы, которые должны оставаться примитивными. Но переименование необходимо, чтобы избежать поиска и замены для типа обертки объекта. Можно использовать любую неидентичную подстановку, но использование верхнего регистра примитива с конкатенированной буквой ‘Q’ упрощает код, который будет написан, поскольку каждый идентификатор примитива может использоваться как при поиске, так и при замене на регулярное выражение.

6.1.2. Переименование Примитива как Обертки Типа Объекта

Промежуточным этапом является поиск и замена идентификатора типа примитива идентификатором типа объекта в исходном коде ZeptoN. Каждый примитивный идентификатор проверяется и подставляется. Таким образом, примитив остается примитивом и восстанавливается на последнем шаге алгоритма.

6.1.3. Переименование промежуточного идентификатора в тип примитива

Последний шаг в алгоритме восстанавливает примитивные типы, которые были переименованы. Используя уникальный, неидентичный идентификатор, идентификатор типа примитива заменяется без завершающего вопросительного знака, а примитив, указанный как оставшийся примитивом в синтаксисе, находится в исходном коде ZeptoN.

6.2 Реализация синтаксиса функций

Алгоритм может быть реализован с использованием трех циклов for над списком примитивных типов или, что еще проще, с печально известным «одним вкладышем», который больше похож на поток, использующий один цикл for. Таким образом, исходный код Java для переноса строки исходного кода ZeptoN с примитивными типами для продвижения и сохранения в базовом исходном коде ZeptoN является методом transpileCode ():

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public static String transpileCode(final String zepCode){
 
  String result = zepCode;
  final String[] primitiveList = new String[]{
    "boolean", "byte", "char", "double", "float", "int", "long", “short" };
 
  final String[] objectTypeList = new String[]{
    "Boolean", "Byte", "Character", "Double", "Float", "Integer", "Long", “Short" };
 
  for(int x=0;x<primitiveList.length;x++){
 
    //primitive type with '?' at end
    String prim = String.format("%s[?]", primitiveList[x]);
     
    if(result.contains(primitiveList[x])){
      //primitive type to uppercase
      String upper = String.format("%SQ", primitiveList[x]);
       
      //exact match of primitive type
      String result = result
                    . replaceAll(prim, upper)
                    . replaceAll(type, objectTypeList[x])
                    . replaceAll(upper, primitiveList[x]);
    }//end if
 
  }//end for
 
  return result;
 
}//end transpileCode

6.3 Транспилирование, затем экспорт в файл

После того, как метод transpileCode () перенесет синтаксис функции в исходный код ZeptoN, исходный код затем записывается во внешний файл. Исходный код для общего метода «transpile ()»:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
private static void transpile(String fileNameOrig) {
 
  String srcCode = "";
  try {
    srcCode = new String(Files.readAllBytes(Paths.get(fileNameOrig)));
  } catch (Exception ex) {
    System.out.printf("Failure reading source file: %s!%n", fileNameOrig);
    return;
  }//end try
   
  //transpile to ZeptoN source from extended feature syntax
  srcCode = transpileCode(srcCode);
  String path = fileNameOrig.replace(".orig", ".zep");
  try {
    Files.write(Paths.get(path),  srcCode.getBytes(Charset.defaultCharset()));
  } catch (Exception ex) {
    System.out.printf("Source code write failure!%n"); return;
  }//end try
 
}//end transpile

Метод «transpile ()» использует внешний файл, новый синтаксис функций из файла «.zep» в файл «.orig». Файл исходного кода читается в String и переносится в исходный код ZeptoN. Файлы исходного кода ZeptoN записываются в файл «.zep». Это сохраняет исходные переданные аргументы файла вместе с любыми аргументами параметров командной строки. Остальная часть компилятора реализована с использованием существующего транскомпилятора ZeptoN.

7. Реализация транскомпилятора с ZeptoN

Транскомпилятор ZeptoN используется в качестве унаследованного или уже существующего кода для транскомпилятора для интеграции синтаксиса новой функции. Подход такой:

  1. Внешний файл для промежуточного кода с предварительной обработкой транскомпилятора
  2. Существующий транскомпилятор ZeptoN является постпроцессорным транскомпилятором и компилятором

Таким образом, новый транскомпилятор с синтаксисом функций в ZeptoN будет использовать внешние файлы, поэтому не будет компилироваться внутри. Это имело преимущество в том, что промежуточный источник ZeptoN может быть сохранен как часть общего процесса компиляции после предварительной обработки исходного кода ZeptoN с новым синтаксисом.

Существующий транскомпилятор ZeptoN (использующий компилятор Java в памяти для компиляции транскомпилированного исходного кода ZeptoN в Java) используется в качестве пакета или библиотеки. Таким образом, существующий компилятор ZeptoN не модифицируется или не классифицируется, но используется на заключительном этапе компиляции.

7.1 Zep существующий ZeptoN Transcompiler

Существующий транскомпилятор ZeptoN, «Zep.java», является Java с открытым исходным кодом, выпущенным в репозитории Github. Транскомпилятор переносит исходный код ZeptoN из файла «source.zep» во внутренний код Java, а затем использует встроенный API Java Compiler для компиляции в файл байт-кода .class.

Два основных метода транскомпилятора класса Zep.java — это, конечно, «main (String [] args)» основной метод для вызова и метод «compile (String [] args)», который выполняет фактическую транскомпиляцию и затем компилируется в файл байт-кода Java .class. Вопрос в том, какой метод вызывать после переноса примитивных типов в типы-обертки объектов. Этими двумя методами являются метод «main ()» или «compile ()», оба являются статическими методами без сохранения состояния.

7.1.1 Метод main ()

В транскомпиляторе ZeptoN «Zep.java» есть метод «main ()», который можно использовать, поскольку все параметры сохраняются и используются внешние файлы. Исходный код метода main ():

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
public static void main(final String[] args) {
 
  try {
    if (args.length == 0) {
      System.out.printf("%s %s%n%s%n", RELEASE, VERSION, LICENSE);
    }//end if
    Zep.compile(args);
  } catch(Exception ex) {
    error("ZeptoN Compiler Exception: '%s' is '%s'.%n",
    ex.getClass().getName(), ex.getMessage()); ex.printStackTrace();
    System.exit(EXIT_CODE_FAILURE);
  }//end try
  System.exit(EXIT_CODE_SUCCESS);
 
}//end main

Вызов транскомпилятора ZeptoN через «main» имеет чрезмерную проблему, так как «System.exit ()» вызывается для успеха или неудачи. Таким образом, компиляция нескольких файлов с новой функцией синтаксиса невозможна, так как первый скомпилированный файл завершится в случае успеха или неудачи.

7.1.2 Метод compile ()

Метод транскомпилятора ZeptoN «compile ()» вызывается методом «main ()». Метод создает экземпляр компилятора ZeptoN, обрабатывает аргументы командной строки и настраивает параметры командной строки. Если аргументы не переданы или файлы не переданы транскомпилятору, возникает ошибка.

Исходный код для метода compile () транскомпилятора ZeptoN:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
public static void compile(final String[] args) {
 
  if (args.length == 0) {
    error(ERROR_NO_INPUT);
  }//end if
 
  final Zep comp = new Zep();
  comp.processCommandLineArgs(args);
  if (files.isEmpty()) {
    error(ERROR_NO_FILES);
  }//end if
  comp.configureParams();
  for (String sourceFile : files) {
    comp.compileZeptoN( Zep.transpile(sourceFile), sourceFile );
  }//end for
 
}//end compile

Фактический транскомпилятор ZeptoN использует метод «transpile ()», который возвращает объект исходного файла Java, который передается методу экземпляра компилятора «compileZeptoN ()» для создания файла байт-кода Java .class. Метод transpile () считывает внешний исходный файл ZeptoN в объект String и переносит его в исходный код Java, который затем компилируется.

7.1.3 Вызов метода compile ()

Метод «compile ()» используется для компиляции синтаксиса передаваемого объекта в файл байт-кода .class. Есть две возможные ошибки, так как используются внешние файлы:

  1. Ошибка файла невозможна, поскольку внешние файлы созданы примитивом для объекта методом транскомпиляции.
  2. Нулевые аргументы невозможны, так как метод транскомпиляции создает исходные файлы ZeptoN.
1
2
3
4
5
6
7
8
9
private static void compile(String[] args) {
 
  String[] fileList = getFileList(args);
  for(String fileName : fileList) {
    //rename, transpile fileList arguments
  }//end for
  Zep.compile(args);
 
}//end transpile

После переименования файлов и последующей трансляции новой синтаксической функции в исходный код ZeptoN вызывается транскомпилятор ZeptoN «compile ()», а транскомпилятор ZeptoN выполняет работу по переносу в файлы Java-байт-кода .class.

После этого исходные файлы исходного кода с новым синтаксисом функции в файле «.orig» переименовываются после удаления промежуточных файлов «.zep». Исходный код для этого шага в методе compile ():

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private static void compile(String[] args) {
 
  //...
  Zep.compile(args);
 
  for(String fileName : fileList) {
    Path path = Paths.get(fileName);
    try {
      Files.delete(path);
    } catch (Exception ex) {
      System.out.printf("Failure deleting file path:%s!%n", path);
    }//end try
 
    String fileNameOrig = fileName.replace(".zep", ".orig");
    Path oldFile = Paths.get(fileNameOrig);
    Path newFile = Paths.get(fileName);
    try {
      Files.move(oldFile, newFile, StandardCopyOption.REPLACE_EXISTING);
    } catch (Exception ex) {
      System.out.printf("Error: Unable to rename file %s!%n", oldFile);
    }//end try
     
  }//end for
 
}//end transpile

После того как промежуточные файлы успешно удалены и файлы исходного кода «.orig» переименованы в «.zep», процесс транскомпиляции завершается.

7.1.4 Сводка по расширенному синтаксису функции Transcompiler

Общий процесс транскомпиляции новых синтаксических функций в файлы Java-байт-кода .class использует внешние файлы, поэтому большая часть процесса заключается в переименовании, удалении, чтении и записи файлов исходного кода. Но все это перемещение данных позволяет запускать существующий транскомпилятор ZeptoN с помощью «compile ()» с параметрами для компилятора и именами файлов. Общий процесс:

  1. Переименуйте файл синтаксиса новой функции из «.zep» в «.orig»
  2. Прочитайте «.orig» в String, транскомпилируйте в исходный код ZeptoN как String.
  3. Записать строку в имя файла «.zep»
  4. Вызвать существующий метод компилятора () ZeptoN transcompiler с внешним файлом, аргументами
  5. Удалить промежуточные файлы .zep
  6. Переименуйте файлы «.orig» в «.zep»

7.2 Помещение нового синтаксиса в тест

Реализация новой функции синтаксиса завершена, но теперь для тестирования новой функции добавлен язык программирования ZeptoN.

При тестировании новой синтаксической функции используются четыре исходных файла ZeptoN. Тест прост, используя оригинальный транспортер ZeptoN: Zep; и модифицированный транспортер ZeptoN: ZepPTO. Файлы исходного кода ZeptoN, используемые в тесте:

  1. polyMathPrimitive1.zep: все типы являются примитивами
  2. polyMathPrimitive2.zep: смешанные типы — это примитивы и типы объектов
  3. polyMathObject.zep: все типы являются типами объектов
  4. polyMathSyntax.zep: типы используют синтаксис новой функции

Оригинальный транспортер исходного кода ZeptoN скомпилирует все исходные файлы ZeptoN, кроме ‘polyMathSyntax.zep’, который содержит синтаксис новых функций. ZepPTO — расширенный функциональный синтаксический транспортер, который скомпилирует все файлы.

Поскольку все файлы будут скомпилированы, за исключением ‘polyMathSyntax.zep’, который завершится неудачно с транскомпилятором Zep, но преуспеет с транскомпилятором ZepPTO, выходные данные, использующие этот файл, используются для сравнения, чтобы избежать ненужного дублирования и объяснения.

7.2.1. Транскомпилируйте новый синтаксис с ZeptoN

Когда скомпилировано с транскомпилятором ZeptoN, результат:

ZeptoN - Ошибки компилятора
Рисунок 1: Ошибки компилятора ZeptoN

Существует одиннадцать ошибок, в первую очередь связанных с новым синтаксисом, что неудивительно, поскольку существующий транскомпилятор ZeptoN пока не реализует новую функцию синтаксиса.

7.2.2. Транскомпилятор с ZepPTO

При компиляции с новым транскомпилятором ZepPTO (Promote To Object) результат:

1
2
3
/Users/williamgilreath$java javacodegeeks.zepton.ZepPTO -echo polyMathSyntax.zep
ZeptoN Compiler Options: [-d, /Users/williamgilreath, -g] Files: [polyMathSyntax.zep] Encoding: UTF-8
ZeptoN Compiler result for file: 'polyMathSyntax.zep' is: Success.

Теперь запустив сгенерированный Java-байт-код .class файл, результат:

1
/Users/williamgilreath$java -cp . javacodegeeks.polyMathSyntax Total time: 301515 nanosec

Преобразованный исходный код ZeptoN в файл байт-кода .class выполняется с использованием среды выполнения Java.

7.2.3. Компиляция других файлов с помощью Zep

Другие исходные файлы ZeptoN, которые имеют обычный синтаксис ZeptoN, компилируются с помощью расширенного транскомпилятора ZeptoN «Zep» с параметром «-echo» для отображения параметров Javac и общего успеха или неудачи компилятора.

1
2
3
/Users/williamgilreath$java io.github.wgilreath.ZeptoN.Zep -echo polyMathObject.zep
ZeptoN Compiler Options: [-d, /Users/williamgilreath, -g] Files: [polyMathObject.zep] Encoding: UTF-8
ZeptoN Compiler result for file: 'polyMathObject.zep' is: Success.

Обычный компилятор ZeptoN успешно скомпилировал исходный файл ZeptoN «polyMathObject.zep».

1
2
3
/Users/williamgilreath$java io.github.wgilreath.ZeptoN.Zep -echo polyMathPrimitive1.zep
ZeptoN Compiler Options: [-d, /Users/williamgilreath, -g] Files: [polyMathPrimitive1.zep] Encoding: UTF-8
ZeptoN Compiler result for file: 'polyMathPrimitive1.zep' is: Success.

Обычный компилятор ZeptoN успешно скомпилировал исходный файл ZeptoN «polyMathPrimitive1.zep».

1
2
3
/Users/williamgilreath$java io.github.wgilreath.ZeptoN.Zep -echo polyMathPrimitive2.zep
ZeptoN Compiler Options: [-d, /Users/williamgilreath, -g] Files: [polyMathPrimitive2.zep] Encoding: UTF-8
ZeptoN Compiler result for file: 'polyMathPrimitive2.zep' is: Success.

Обычный компилятор ZeptoN успешно скомпилировал исходный файл ZeptoN «polyMathPrimitive2.zep».

7.2.4 Компиляция других файлов с ZepPTO

Другие исходные файлы ZeptoN, которые имеют обычный синтаксис ZeptoN, компилируются с помощью расширенного транскомпилятора ZeptoN «ZepPTO» с параметром «-echo» для отображения параметров Javac и общего успеха или неудачи компилятора.

1
2
3
/Users/williamgilreath$java javacodegeeks.zepton.ZepPTO -echo polyMathObject.zep
ZeptoN Compiler Options: [-d, /Users/williamgilreath, -g] Files: [polyMathObject.zep] Encoding: UTF-8
ZeptoN Compiler result for file: 'polyMathObject.zep' is: Success.

Расширенный компилятор ZeptoN успешно скомпилировал исходный файл ZeptoN «polyMathObject.zep».

1
2
3
/Users/williamgilreath$java javacodegeeks.zepton.ZepPTO -echo polyMathPrimitive1.zep
ZeptoN Compiler Options: [-d, /Users/williamgilreath, -g] Files: [polyMathPrimitive1.zep] Encoding: UTF-8
ZeptoN Compiler result for file: 'polyMathPrimitive1.zep' is: Success.

Расширенный компилятор ZeptoN успешно скомпилировал исходный файл ZeptoN «polyMathPrimitive1.zep».

1
2
3
/Users/williamgilreath$java javacodegeeks.zepton.ZepPTO -echo polyMathPrimitive2.zep
ZeptoN Compiler Options: [-d, /Users/williamgilreath, -g] Files: [polyMathPrimitive2.zep] Encoding: UTF-8
ZeptoN Compiler result for file: 'polyMathPrimitive2.zep' is: Success.

Расширенный компилятор ZeptoN успешно скомпилировал исходный файл ZeptoN «polyMathPrimitive2.zep».

7.2.5 Сводка испытаний

Тестирование обычных исходных файлов ZeptoN и функции расширенного синтаксиса с обоими транскомпиляторами показывает, что расширенный транскомпилятор ZepPTO компилируется в файлы Java-байт-кода .class. Новый синтаксис функции работает для продвижения примитивных типов в обертки типов объектов и исключает примитивные типы с новым синтаксисом функции, чтобы оставаться примитивными типами.

8. Заключение

Языком программирования ZeptoN является Java, ориентированный только на программную сущность, особенность которой отсутствует в языке программирования Java. Это создает язык программирования с синтаксисом Java, похожим и совместимым; такой язык программирования легко трансформируется в исходный код Java, а затем компилируется в файл байт-кода .class с использованием API компилятора Java.

Язык программирования ZeptoN был расширен за счет добавления новой функции с новым синтаксисом. Эта функция заключалась в преобразовании примитивных типов (исключая null и void) в типы обертки объектов. Это общая тема с языками программирования, часто называемая «ползучий фуритурит» или «ползучесть». Но для новой функции в синтаксисе языка программирования она должна быть разработана и реализована.

Новый синтаксис функции был реализован с использованием транскомпилятора, который переносит исходный код ZeptoN с новым синтаксисом функции в обычный исходный код ZeptoN. Исходный код является транскомпилированным в байт-код Java с использованием существующего транскомпилятора ZeptoN. Преимущество этого заключается в использовании существующего транскомпилятора для ZeptoN, но в настройке и расширении языка новой функцией. Это позволяет избежать совершенно новой реализации новой функции синтаксиса, добавленной в ZeptoN.

Следовательно, акцент был сделан на реализации транспилятора для новой функции синтаксиса, а затем на реализации, используя существующий транскомпилятор и компилятор, поскольку транскомпилятор ZeptoN переносится в исходный код Java, а затем в файл .class байт-кода Java. Этот же подход можно использовать для расширения Java с помощью новой функции, использования компилятора WEJAC [Gilr 2019b] для компиляции преобразованного исходного кода Java в чистый исходный код Java, а затем в файл байт-кода .class.

9. Ссылки

[Alpe 2000] Альперт, Шерман Р. «Примитивные типы, считающиеся вредными». в More Java Gems , Cambridge University Press, Нью-Йорк, Нью-Йорк, 2000, стр. 435-454.

[Брит 2019] Британский Совет. «Когнитивная перегрузка», 20 мая 2015 г., https://www.teachingenglish.org.uk/article/cognitive-overload . Доступ 9 ноября 2019 г.

[Коуп 2009] Коупленд, Том. Генерация парсеров с помощью JavaCC , Centennial Books, Александрия, Вирджиния, 2009, стр. 29.

[Ecke 2003] Eckel, Брюс. Мышление на Яве , Прентис-Холл, Аппер-Седл-Ривер, Нью-Джерси, 2003, с. 90

[Gilr 2019a] Gilreath, репозиторий William F. GitHub «WEJAC: компилятор Java для Will’s Elided», https://wgilreath.github.io/WEJAC/ По состоянию на 31 декабря 2019 г.

[Gilr 2019b] Gilreath, репозиторий William F. GitHub «ZepC — эхо-транслятор ZeptoN», https://wgilreath.github.io/ZeptoN/ По состоянию на 31 декабря 2019 года.

[Moor 2014] Мур, Джон. «Случай для хранения примитивов в Java», JavaWorld, https://www.javaworld.com/article/2150208/a-case-for-keeping-primitives-in-java.html . Май 2014 года. Доступ 27 декабря 2019 года.

[Orac 2019] Oracle America, Inc., Спецификация языка Java, 13-е издание, https://docs.oracle.com/javase/specs/jls/se13/jls13.pdf . По состоянию на 27 декабря 2019 г.

[Wiki 2019a] Wikibooks, Программирование на Java. Издание WikiBooks, https://en.wikibooks.org/wiki/Java_Programming/Keywords/void . Доступ 30 декабря 2019 г.

[Wiki 2019b] Wikibooks. Основное программирование, 13 октября 2019 года. Https://en.wikibooks.org/wiki/BASIC_Programming/Beginning_BASIC/User_Input , Доступно 9 ноября 2019 года.

10. Загрузите исходный код

Скачать
Вы можете скачать полный исходный код этого примера здесь: ZeptoN переводит программу на Java