JavaRush /Java блогу /Random-KY /Java тилиндеги кадимки туюнтмалар, 5-бөлүк

Java тилиндеги кадимки туюнтмалар, 5-бөлүк

Группада жарыяланган
Биз сиздердин назарыңыздарга javaworld веб-сайты үчүн Джефф Фризен тарабынан жазылган Java тorндеги туруктуу сөз айкаштары боюнча кыскача колдонмонун котормосун сунуштайбыз. Окууга ыңгайлуу болушу үчүн биз макаланы бир нече бөлүккө бөлдүк. Бул бөлүк акыркы болуп саналат. Java тorндеги кадимки туюнтмалар, 5-1-бөлүкJava тorндеги кадимки туюнтмалар, 1-бөлүк Java тorндеги кадимки туюнтмалар, 2-бөлүк Java тorндеги кадимки туюнтмалар, 3-бөлүк Java тorндеги кадимки туюнтмалар, 4-бөлүк

Лексикалык талдоо үчүн туруктуу сөз айкаштарын колдонуу

Регулярдуу туюнтмалардын андан да пайдалуу колдонмосу бул ар кандай компилятордун же ассемблердин негизги компоненти болгон лексикалык анализ жүргүзүү үчүн көп жолу колдонулуучу codeдун китепканасы. Мында символдордун кириш агымы белгилердин чыгыш агымына топтолот - жалпы мааниге ээ болгон символдордун ырааттуулугу үчүн аталыштар. Мисалы, киргизүү агымында c, o, u, n, t, e, , символдорунун ырааттуулугуна туш болуп , лексикалык анализатор лексиканы (идентификатор) чыгара алат. Токенге туура келген символдордун тизмеги лексема деп аталат. rID
Маркерлер жана лексемалар жөнүндө көбүрөөк
ID сыяктуу токендер көптөгөн символдордун ырааттуулугуна дал келиши мүмкүн. Мындай лексикалардын учурда, лексикалык анализди талап кылган компилятор, ассемблер же башка утorтага туура келген нукура токен да керек болот. Белгилердин бир белгилүү ырааттуулугун билдирген токендер үчүн, мисалы, PLUSбелгиге гана туура келген токен +, анык токен талап кылынbyte, анткени аны белгиден аныктоого болот.
Регулярдуу сөз айкаштары штаттык лексикалык анализаторлорго караганда алда канча эффективдүү, алар кол менен жазылууга тийиш жана жалпысынан кайра колдонууга болбойт. Кадимки сөз айкашына негизделген лексикалык анализатордун мисалы JLex , Java тor үчүн лексикалык генератор, ал киргизилген маалыматтар агымын токендерге бөлүү эрежелерин аныктоо үчүн кадимки туюнтмаларды колдонот. Дагы бир мисал Lexan болуп саналат.

Лексан менен таанышуу

Lexan - лексикалык анализ үчүн көп жолу колдонулуучу Java китепканасы. Бул Cogito Learning веб-сайтындагы Java тorнде талдоочу жазуу сериясынын codeуна негизделген . Китепкана бул макаланын жүктөлүп алынуучу codeуна камтылган пакетте турган төмөнкү класстардан турат :ca.javajeff.lexan
  • Lexan: лексикалык анализатор;
  • LexanException: класстын конструкторуна ыргытылган өзгөчөлүкLexan;
  • LexException: лексикалык анализ учурунда туура эмес синтаксис аныкталса, өзгөчөлүктү таштоо;
  • Token: регулярдуу туюнтма атрибуту менен ат;
  • TokLex: токен/токен жуп.
Конструктор Lexan(java.lang.Class tokensClass)жаңы лексикалык анализаторду түзөт. java.lang.ClassАл класстын түрүнө туура келген класс an objectисинин түрүндөгү бир аргументти талап кылат static Token. Reflection API колдонуп, конструктор бардык константаларды Tokenмаанилердин массивине окуйт Token[]. Эгерде Tokenэч кандай константалар жок болсо, анда өзгөчө жагдай ыргытылат LexanException. Java тorндеги кадимки туюнтмалар, 5-2-бөлүкКласс Lexanошондой эле төмөнкү эки ыкманы камсыз кылат:
  • Метод бул лексердин тизмесин кайтарат ;List getTokLexes() Token
  • Метод void lex(String str)түрүндөгү маанилердин тизмесине [натыйжа жайгаштырылган] кириш сабына лексикалык талдоо жүргүзөт TokLex. Эгерде массив үлгүлөрүнүн бирине да дал келбеген белги жолукса Token[], өзгөчө жагдай чыгарылат LexException.
Класста LexanExceptionэч кандай ыкма жок; ал өзгөчө билдирүүнү кайтаруу үчүн мурасталган ыкманы колдонот getMessage(). Ал эми, класс LexExceptionтөмөнкү ыкмаларды камсыз кылат:
  • Метод int getBadCharIndex()белгилердин эч бирине дал келбеген белгинин абалын кайтарат.
  • Метод String getText()өзгөчө жагдай түзүлгөндө талданган текстти кайтарат.
Класс маркердин атын кайтаруу Tokenыкмасын жокко чыгарат . Ал ошондой эле токендин регулярдуу туюнтма атрибутун кайтарган toString()ыкманы камсыз кылат . String getPattern()Класс өзүнүн энбелгисин кайтарган TokLexыкманы камсыз кылат . Ал ошондой эле анын белгисин кайтарган Token getToken()ыкманы камсыз кылат .String getLexeme()

Лексан китепканасынын демонстрациясы

Китепкана кантип иштээрин көрсөтүү үчүн Lexanмен арыз жаздым LexanDemo. Ал LexanDemo, BinTokensжана класстардан турат MathTokens. NoTokensКолдонмонун баштапкы codeу LexanDemo2-листингде көрсөтүлгөн. Листинг 2. Лексан китепканасынын иш-аракетинде демонстрациясы
import ca.javajeff.lexan.Lexan;
import ca.javajeff.lexan.LexanException;
import ca.javajeff.lexan.LexException;
import ca.javajeff.lexan.TokLex;

public final class LexanDemo
{
   public static void main(String[] args)
   {
      lex(MathTokens.class, " sin(x) * (1 + var_12) ");
      lex(BinTokens.class, " 1 0 1 0 1");
      lex(BinTokens.class, "110");
      lex(BinTokens.class, "1 20");
      lex(NoTokens.class, "");
   }

   private static void lex(Class tokensClass, String text)
   {
      try
      {
         Lexan lexan = new Lexan(tokensClass);
         lexan.lex(text);
         for (TokLex tokLex: lexan.getTokLexes())
            System.out.printf("%s: %s%n", tokLex.getToken(),
                              tokLex.getLexeme());
      }
      catch (LexanException le)
      {
         System.err.println(le.getMessage());
      }
      catch (LexException le)
      {
         System.err.println(le.getText());
         for (int i = 0; i < le.getBadCharIndex(); i++)
            System.err.print("-");
         System.err.println("^");
         System.err.println(le.getMessage());
      }
      System.out.println();
   }
}
main()2-Листингдеги метод lex()Lexan аркылуу лексикалык анализди көрсөтүү үчүн утorтаны чакырат. Бул ыкмага ар бир чалуу an objectтеги токендердин классына Classжана талдоо үчүн сапка өтөт. Метод алгач an objectти класстын конструкторуна өткөрүп берүү менен lex()класстын an objectисин түзөт . Анан ошол сапта класс ыкмасын чакырат . Эгерде лексикалык анализ ийгorктүү болсо, класстык метод an objectтердин тизмесин кайтаруу үчүн чакырылат . Бул an objectтердин ар бири үчүн анын класстык методу токенди кайтаруу үчүн жана анын класстык ыкмасы токенди кайтаруу үчүн чакырылат. Эки маани тең стандарттык чыгарууга басып чыгарылат. Эгерде лексикалык талдоо ийгorксиз болсо, өзгөчөлүктөрдүн бири же ыргытылат жана ошого жараша иштетилет . Кыскача бул колдонмону түзгөн классты гана карап көрөлү . Листинг 3 анын баштапкы codeун көрсөтөт. Листинг 3. Кичинекей математикалык тил үчүн белгилердин жыйындысынын сүрөттөлүшүLexanClassLexanlex()LexanTokLexgetTokLexes()LexangetToken()TokLexgetLexeme()LexanExceptionLexExceptionMathTokens
import ca.javajeff.lexan.Token;

public final class MathTokens
{
   public final static Token FUNC = new Token("FUNC", "sin|cos|exp|ln|sqrt");
   public final static Token LPAREN = new Token("LPAREN", "\\(");
   public final static Token RPAREN = new Token("RPAREN", "\\)");
   public final static Token PLUSMIN = new Token("PLUSMIN", "[+-]");
   public final static Token TIMESDIV = new Token("TIMESDIV", "[*/]");
   public final static Token CARET = new Token("CARET", "\\^");
   public final static Token INTEGER = new Token("INTEGER", "[0-9]+");
   public final static Token ID = new Token("ID", "[a-zA-Z][a-zA-Z0-9_]*");
}
Листинг 3 класс MathTokensтиптеги константалардын ырааттуулугун сүрөттөй турганын көрсөтүп турат Token. Алардын ар бирине an objectтин баасы ыйгарылган Token. Бул an objectтин конструктору ошол маркер менен байланышкан бардык символ саптарын сүрөттөгөн кадимки туюнтма менен бирге маркердин аты болгон сапты алат. Түшүнүктүү болушу үчүн, маркердин сап аталышы константа аты менен бирдей болушу керек, бирок бул талап кылынbyte. Маркерлердин тизмесиндеги Java тorндеги кадимки туюнтмалар, 5-3-бөлүкконстанталардын орду маанилүү. TokenТизмеде жогору турган туруктуулар Tokenтөмөндө жайгашкандардан артыкчылыкка ээ. Мисалы, жолукканда , Лександын ордуна sinбелги тандайт . Эгер маркер маркерден мурун болсо , ал тандалган болмок. FUNCIDIDFUNC

LexanDemo тиркемесин түзүү жана иштетүү

lexan.zipБул макаланын жүктөлүп алынуучу codeу Lexan бөлүштүрүүнүн бардык файлдарын камтыган архивди камтыйт . demosБул архивди ачып, түпкү каталогдун подкаталогуна өтүңүз lexan. Эгер сиз Windows колдонуп жатсаңыз, демо колдонмонун баштапкы code файлдарын компиляциялоо үчүн төмөнкү буйрукту аткарыңыз:
javac -cp ..\library\lexan.jar *.java
Эгерде компиляция ийгorктүү болсо, демо тиркемени иштетүү үчүн төмөнкү буйрукту аткарыңыз:
java -cp ..\library\lexan.jar;. LexanDemo
Сиз төмөнкү натыйжаларды көрүшүңүз керек:
FUNC: sin
LPAREN: (
ID: x
RPAREN: )
TIMESDIV: *
LPAREN: (
INTEGER: 1
PLUSMIN: +
ID: var_12
RPAREN: )
ONE: 1
ZERO: 0
ONE: 1
ZERO: 0
ONE: 1
ONE: 1
ONE: 1
ZERO: 0
1 20
--^
Неожиданный символ во входном тексте: 20
Билдирүү класстын туруктуу туюнтма катары мааниси менен константаны жарыялабагандыгына Неожиданный символ во входном тексте: 20байланыштуу ыргытылган өзгөчөлүктүн натыйжасында пайда болот . Эскертүү, өзгөчөлүктү иштетүүчү тексттин лексикалык анализинен алынган ылайыксыз символдун абалын чыгарат. Токендер жок билдирүү класста эч кандай константалар жарыяланбагандыктан, ыргытылган өзгөчөлүктүн натыйжасы болуп саналат . LexanExceptionBinTokensToken2LexExceptionNoTokensToken

Сахна артында

Lexanкыймылдаткычы катары Lexan классын колдонот. 4-тизмеде бул класстын ишке ашырылышын карап чыгыңыз жана кыймылдаткычты кайра колдонууга жарактуу кылуу үчүн туруктуу сөз айкаштарынын салымын белгилеңиз. Листинг 4. Туруктуу сөз айкаштарынын негизинде лексикалык анализатордун архитектурасын түзүү
package ca.javajeff.lexan;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;

/**
 *  Лексический анализатор. Этот класс можно использовать для
 *  преобразования входного потока символов в выходной поток маркеров.
 *
 *  @Author Джефф Фризен
 */

public final class Lexan
{
   private List tokLexes;

   private Token[] values;

   /**
    *  Инициализируем лексический анализатор набором an objectов Token.
    *
    *  @параметры tokensClass – an object Class класса, содержащего
    *       набор an objectов Token
    *
    *  @генерирует исключение LexanException в случае невозможности
    *       формирования an object Lexan, возможно, из-за отсутствия an objectов
    *       Token в классе
    */

   public Lexan(Class tokensClass) throws LexanException
   {
      try
      {
         tokLexes = new ArrayList<>();
         List _values = new ArrayList<>();
         Field[] fields = tokensClass.getDeclaredFields();
         for (Field field: fields)
            if (field.getType().getName().equals("ca.javajeff.lexan.Token"))
               _values.add((Token) field.get(null));
         values = _values.toArray(new Token[0]);
         if (values.length == 0)
            throw new LexanException("маркеры отсутствуют");
      }
      catch (IllegalAccessException iae)
      {
         throw new LexanException(iae.getMessage());
      }

   /**
    * Получаем список TokLex'ов этого лексического анализатора.
    *
    *  @возвращает список TokLex'ов
    */

   public List getTokLexes()
   {
      return tokLexes;
   }

   /** * Выполняет лексический анализ входной строки [с помещением * результата] в список TokLex'ов. * * @параметры str – строка, подвергаемая лексическому анализу * * @генерирует исключение LexException: во входных данных обнаружен * неожиданный символ */

   public void lex(String str) throws LexException
   {
      String s = new String(str).trim(); // удалить ведущие пробелы
      int index = (str.length() - s.length());
      tokLexes.clear();
      while (!s.equals(""))
      {
         boolean match = false;
         for (int i = 0; i < values.length; i++)
         {
            Token token = values[i];
            Matcher m = token.getPattern().matcher(s);
            if (m.find())
            {
               match = true;
               tokLexes.add(new TokLex(token, m.group().trim()));
               String t = s;
               s = m.replaceFirst("").trim(); // удалить ведущие пробелы
               index += (t.length() - s.length());
               break;
            }
         }
         if (!match)
            throw new LexException("Неожиданный символ во входном тексте: "
                                    + s, str, index);
      }
   }
}
Метод codeу Cogito Learning веб-сайтындагы "Javaда талдоочу жазуу: Токен генератору"lex() блогунда берилген codeго негизделген . Lexan codeду компиляциялоо үчүн Regex APIди кантип колдонсо жөнүндө көбүрөөк билүү үчүн бул постту окуңуз. Java тorндеги кадимки туюнтмалар, 5-4-бөлүк

Корутунду

Кадимки сөз айкаштары ар бир иштеп чыгуучуга пайдалуу боло турган пайдалуу курал. Java программалоо тorнин Regex API аларды тиркемелерде жана китепканаларда колдонууну жеңилдетет. java.util.regexЭми сизде кадимки туюнтмалар жана бул API жөнүндө негизги түшүнүк бар болгондуктан, кадимки туюнтмалар жана кошумча Regex API ыкмалары жөнүндө көбүрөөк билүү үчүн SDK documentтерин карап көрүңүз .
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION