Биз сиздердин назарыңыздарга javaworld веб-сайты үчүн Джефф Фризен тарабынан жазылган Java тorндеги туруктуу сөз айкаштары боюнча кыскача колдонмонун котормосун сунуштайбыз. Окууга ыңгайлуу болушу үчүн биз макаланы бир нече бөлүккө бөлдүк. Бул бөлүк акыркы болуп саналат. Java тorндеги кадимки туюнтмалар, 1-бөлүк Java тorндеги кадимки туюнтмалар, 2-бөлүк Java тorндеги кадимки туюнтмалар, 3-бөлүк Java тorндеги кадимки туюнтмалар, 4-бөлүк
Регулярдуу сөз айкаштары штаттык лексикалык анализаторлорго караганда алда канча эффективдүү, алар кол менен жазылууга тийиш жана жалпысынан кайра колдонууга болбойт. Кадимки сөз айкашына негизделген лексикалык анализатордун мисалы JLex , Java тor үчүн лексикалык генератор, ал киргизилген маалыматтар агымын токендерге бөлүү эрежелерин аныктоо үчүн кадимки туюнтмаларды колдонот. Дагы бир мисал Lexan болуп саналат.
Лексикалык талдоо үчүн туруктуу сөз айкаштарын колдонуу
Регулярдуу туюнтмалардын андан да пайдалуу колдонмосу бул ар кандай компилятордун же ассемблердин негизги компоненти болгон лексикалык анализ жүргүзүү үчүн көп жолу колдонулуучу codeдун китепканасы. Мында символдордун кириш агымы белгилердин чыгыш агымына топтолот - жалпы мааниге ээ болгон символдордун ырааттуулугу үчүн аталыштар. Мисалы, киргизүү агымындаc
, o
, u
, n
, t
, e
, , символдорунун ырааттуулугуна туш болуп , лексикалык анализатор лексиканы (идентификатор) чыгара алат. Токенге туура келген символдордун тизмеги лексема деп аталат. r
ID
Маркерлер жана лексемалар жөнүндө көбүрөөк |
---|
ID сыяктуу токендер көптөгөн символдордун ырааттуулугуна дал келиши мүмкүн. Мындай лексикалардын учурда, лексикалык анализди талап кылган компилятор, ассемблер же башка утorтага туура келген нукура токен да керек болот. Белгилердин бир белгилүү ырааттуулугун билдирген токендер үчүн, мисалы, PLUS белгиге гана туура келген токен + , анык токен талап кылынbyte, анткени аны белгиден аныктоого болот. |
Лексан менен таанышуу
Lexan - лексикалык анализ үчүн көп жолу колдонулуучу Java китепканасы. Бул Cogito Learning веб-сайтындагы Java тorнде талдоочу жазуу сериясынын codeуна негизделген . Китепкана бул макаланын жүктөлүп алынуучу codeуна камтылган пакетте турган төмөнкү класстардан турат :ca.javajeff.lexan
Lexan
: лексикалык анализатор;LexException
: лексикалык анализ учурунда туура эмес синтаксис аныкталса, өзгөчөлүктү таштоо;Token
: регулярдуу туюнтма атрибуту менен ат;TokLex
: токен/токен жуп.
LexanException
: класстын конструкторуна ыргытылган өзгөчөлүкLexan;
Lexan(java.lang.Class tokensClass)
жаңы лексикалык анализаторду түзөт. java.lang.Class
Ал класстын түрүнө туура келген класс an objectисинин түрүндөгү бир аргументти талап кылат static Token
. Reflection API колдонуп, конструктор бардык константаларды Token
маанилердин массивине окуйт Token[]
. Эгерде Token
эч кандай константалар жок болсо, анда өзгөчө жагдай ыргытылат LexanException
. Класс 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у LexanDemo
2-листингде көрсөтүлгөн. Листинг 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. Кичинекей математикалык тил үчүн белгилердин жыйындысынын сүрөттөлүшүLexan
Class
Lexan
lex()
Lexan
TokLex
getTokLexes()
Lexan
getToken()
TokLex
getLexeme()
LexanException
LexException
MathTokens
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. Маркерлердин тизмесиндеги константалардын орду маанилүү. Token
Тизмеде жогору турган туруктуулар Token
төмөндө жайгашкандардан артыкчылыкка ээ. Мисалы, жолукканда , Лександын ордуна sin
белги тандайт . Эгер маркер маркерден мурун болсо , ал тандалган болмок. FUNC
ID
ID
FUNC
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
байланыштуу ыргытылган өзгөчөлүктүн натыйжасында пайда болот . Эскертүү, өзгөчөлүктү иштетүүчү тексттин лексикалык анализинен алынган ылайыксыз символдун абалын чыгарат. Токендер жок билдирүү класста эч кандай константалар жарыяланбагандыктан, ыргытылган өзгөчөлүктүн натыйжасы болуп саналат . LexanException
BinTokens
Token
2
LexException
NoTokens
Token
Сахна артында
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нин Regex API аларды тиркемелерде жана китепканаларда колдонууну жеңилдетет.java.util.regex
Эми сизде кадимки туюнтмалар жана бул API жөнүндө негизги түшүнүк бар болгондуктан, кадимки туюнтмалар жана кошумча Regex API ыкмалары жөнүндө көбүрөөк билүү үчүн SDK documentтерин карап көрүңүз .
GO TO FULL VERSION