JavaCC создание пользовательского класса токенов

#java #compiler-construction #interpreter #javacc

#java #компилятор-построение #интерпретатор #javacc

Вопрос:

Я работаю над школьным заданием для моего курса компилятора и интерпретаторов, и наша текущая задача — создать сканер и набор токенов с использованием JavaCC. У меня есть довольно четкое представление о том, как работает JavaCC, но моя проблема заключается в поиске ресурсов в Интернете, которые помогут мне, когда я застряну. Я работаю над созданием пользовательского класса токенов, назовем его NewToken.Java . Я знаю, что базовый класс токенов имеет переменную image и переменную kind, но я хочу реализовать свою собственную переменную «value». Кроме того, я хочу выяснить, как я могу присвоить это значение. Я хочу, чтобы переменная value содержала буквальное значение того, что я сканирую, например, мой NewToken сопоставляется со следующим

 < IDENTIFIER:(< LETTER >)  ( < LETTER > | < DIGIT >)* >
< #LETTER:["a" - "z"] >
< #DIGIT: ["0" - "9"] >
  

итак, что-то вроде Name123Name будет поймано, и когда это произойдет, я хочу сохранить строку «Name123Name» в переменной ‘value’ моего объекта NewToken. Я надеюсь, что это имеет смысл, я все еще новичок в JavaCC и, возможно, называю вещи неправильным именем здесь.

  public NewToken(){}
  public NewToken(int kind){
    this(kind,null);
  }
  public NewToken(int kind, String image){
    this.kind=kind;
    this.image=image;
    this.value=image;
  }
  public String toString(){
    return image;
  }
  public static Token newToken(int ofKind, String image){
    switch(ofKind){
      default : return new Token(ofKind, image);
    }
  }
  public static Token newToken(int ofKind){
    return newToken(ofKind, null);
  }
}
  

Выше приведена часть моего кода для класса NewToken, он расширяет токен и реализует java.io.serializable. Я создал, используя код, сгенерированный для Token.java . У меня также есть объявления переменных и функция GetValue(), которые здесь не перечислены для экономии места. Я не ищу никого, кто мог бы выполнять мою работу за меня, мне просто нужны некоторые рекомендации о том, как я мог бы заставить это работать, заранее благодарю вас.

Ответ №1:

Во-первых, я думаю newToken , что процедура должна возвращать объекты типа NewToken , а не Token .

   public static Token newToken(int ofKind, String image){
    return new NewToken(ofKind, image);
  }
  public static Token newToken(int ofKind){
    return new NewToken(ofKind, null);
  } 
  

(Я не думаю, что вам нужен этот второй метод. Но я не совсем уверен, поэтому я оставлю это.)

Мне немного непонятно, чем вы хотите value отличаться от image , но я собираюсь предположить, что вы можете вычислить желаемое значение для value из image и kind . И я далее предполагаю, что вы реализовали эту функцию как статический метод.

 private static String computeValue(int kind, String image) {...}
  

Удалите первые два конструктора, а оставшийся должен быть:

   private NewToken(int kind, String image){
    this.kind = kind;
    this.image = image;
    this.value = computeValue( kind, image );
  }
  

Комментарии:

1. Прежде всего, спасибо, что указали на тот факт, что я все еще возвращал токены, а не новый токен, я скопировал вставленный класс токенов и забыл их полностью изменить. Во-вторых, моя проблема в том, что поле изображения в моем токене всегда равно «null», у меня проблема с получением переменной image для хранения значения того, что было только что прочитано и помечено. Я пробовал matchedToken.image = image.toString(); но это не сработало, однако я считаю, что это было из-за ошибки, на которую вы указали.

2. Я не уверен, почему параметр изображения будет равен null. Я рассмотрю это, когда у меня будет возможность.

3. Обратите внимание, что if image является ссылкой на строку, тогда image.toString() будет просто вычисляться значение image , если это значение не равно null . В последнем случае image.toString() вызовет NullPointerException .

4. Итак, я понял, что происходит, но пока не смог ее решить. Это не изображено выше, но я переопределяю метод GetValue() из класса Token . По умолчанию в токене возвращается значение null, но я пытаюсь вернуть значение этого токена. По какой-то причине мое переопределение не работает, я протестировал это, изменив возвращаемое значение GetValue в Token на мою собственную строку, и это значение выводится всеми токенами при вызове GetValue() .

Ответ №2:

Ответ, который дает вам профессор Норвелл, основан на использовании очень старой, устаревшей версии JavaCC. То, как он предлагает вам действовать, вероятно, является лучшим способом сделать это, если вы собираетесь использовать устаревший JavaCC.

Однако самой продвинутой версией JavaCC является JavaCC 21, и она обрабатывает такого рода варианты использования прямо из коробки в очень чистой и элегантной манере. Смотрите Здесь для получения дополнительной информации об этом.

Как вы можете видеть, вы можете поместить аннотации в свой файл грамматики, которые вызывают создание и использование различных подклассов токенов.

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

 INJECT NewToken :
{
   private static String computeValue(int kind, String image) {...}
}
  

Вы помещаете это в свою грамматику, и computeValue метод просто вставляется в сгенерированный NewToken .java-файл.

Кстати, есть статья о JavaCC 21, которая недавно появилась на dzone.com .