Сіздердің назарларыңызға Джефф Фризеннің javaworld веб-сайты үшін жазған Java тіліндегі тұрақты тіркестерге арналған қысқаша нұсқаулықтың аудармасын ұсынамыз. Оқуға ыңғайлы болу үшін мақаланы бірнеше бөлікке бөлдік. Бұл бөлім соңғы. Java тіліндегі тұрақты өрнектер, 1 бөлім Java тіліндегі тұрақты өрнектер, 2 бөлім Java тіліндегі тұрақты өрнектер, 3 бөлім Java тіліндегі тұрақты өрнектер, 4 бөлім
Тұрақты тіркестер қолмен жазылуы керек және әдетте қайта пайдалануға болмайтын күйге негізделген лексикалық анализаторларға қарағанда әлдеқайда тиімді. Тұрақты өрнекке негізделген лексикалық анализатордың мысалы JLex , кіріс деректер ағынын таңбалауыштарға бөлу ережелерін анықтау үшін тұрақты өрнектерді пайдаланатын Java тіліне арналған лексикалық генератор. Тағы бір мысал - Лексан.
Лексикалық талдау үшін тұрақты тіркестерді қолдану
Тұрақты өрнектердің одан да пайдалы қолданбасы кез келген компилятордың немесе ассемблердің негізгі құрамдас бөлігі болып табылатын лексикалық талдауды орындауға арналған қайта пайдалануға болатын codeтардың кітапханасы болып табылады. Бұл жағдайда таңбалардың кіріс ағыны таңбалауыштардың шығыс ағынына топтастырылады - жалпы мағынасы бар таңбалар тізбегінің атаулары. Мысалы, кіріс ағынындаc
, o
, u
, n
, t
, e
, , таңбаларының тізбегін кездестіріп , лексикалық анализатор таңбалауышты (идентификатор) шығара алады. Желтоқсанға сәйкес келетін таңбалар тізбегі лексема деп аталады. r
ID
Маркерлер мен лексемалар туралы толығырақ |
---|
Идентификатор сияқты токендер көптеген таңбалар тізбегіне сәйкес келуі мүмкін. Мұндай таңбалауыштар жағдайында таңбалауышқа сәйкес келетін нақты таңбалауыш компиляторға, ассемблерге немесе лексикалық талдауды қажет ететін басқа утorтаға да қажет. Таңбалардың бір нақты тізбегін көрсететін таңбалауыштар үшін, мысалы PLUS тек таңбаға сәйкес келетін таңбалауыш + , нақты таңбалауыш талап етілмейді, себебі оны таңбалауыштан анықтауға болады. |
Лексанмен танысу
Lexan - лексикалық талдау үшін қайта пайдалануға болатын Java кітапханасы. Ол Cogito Learning веб-сайтындағы Java тілінде талдаушы жазу блог жазбалар сериясының codeына негізделген . Кітапхана осы мақаланың жүктеп алынатын codeында қамтылған бумадағы келесі сыныптардан тұрады :ca.javajeff.lexan
Lexan
: лексикалық анализатор;LexException
: лексикалық талдау кезінде қате синтаксис анықталса, ерекшелік тасталады;Token
: тұрақты өрнек атрибуты бар атау;TokLex
: таңбалауыш/токен жұбы.
LexanException
: сынып конструкторында шығарылған ерекшелікLexan;
Lexan(java.lang.Class tokensClass)
жаңа лексикалық анализатор жасайды. java.lang.Class
Ол тұрақты класс түріне сәйкес келетін класс нысаны түріндегі бір аргументті талап етеді 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. Lexan кітапханасының әрекеттегі көрсетілімі
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 көмегімен лексикалық талдауды көрсету үшін қызметтік бағдарламаны шақырады. Бұл әдіске әрбір шақыру нысандағы таңбалауыштар класын Class
және талданатын жолды береді. Әдіс алдымен an objectіні класс конструкторына беру арқылы lex()
сынып an objectісін жасайды . Содан кейін ол осы жолда сынып әдісін шақырады. Егер лексикалық талдау сәтті болса, нысандар тізімін қайтару үшін класс әдісі шақырылады . Осы нысандардың әрқайсысы үшін таңбалауышты қайтару үшін оның класс әдісі және таңбалауышты қайтару үшін оның класс әдісі шақырылады. Екі мән де стандартты шығысқа басып шығарылады. Егер лексикалық талдау сәтсіз болса, ерекше жағдайлардың бірі немесе лақтырылады және сәйкесінше өңделеді . Қысқалық үшін осы қолданбаны құрайтын сыныпты ғана қарастырайық . Листинг 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
. Осы нысанның конструкторы осы маркермен байланыстырылған барлық таңбалар жолдарын сипаттайтын тұрақты өрнекпен бірге маркердің аты болып табылатын жолды алады. Түсінікті болу үшін маркердің жол атауы тұрақтының атымен бірдей болғаны жөн, бірақ бұл талап етілмейді. Маркерлер тізіміндегі тұрақтының орны маңызды. Token
Тізімде жоғары орналасқан тұрақтылар Token
төменде орналасқандардан басым болады. Мысалы, кездескен кезде Лексан орнына sin
таңбалауышты таңдайды . Егер таңбалауыш таңбалауыштан бұрын болса , ол таңдалған болар еді. FUNC
ID
ID
FUNC
LexanDemo қолданбасын құрастыру және іске қосу
lexan.zip
Осы мақаланың жүктеп алынатын codeы Lexan таратуының барлық файлдарын қамтитын мұрағатты қамтиды . demos
Бұл мұрағатты қаптамадан шығарып, түбірлік каталогтың ішкі каталогына өтіңіз lexan
. Егер сіз Windows жүйесін пайдаланып жатсаңыз, демонстрациялық қолданбаның бастапқы code файлдарын құрастыру үшін келесі пәрменді орындаңыз:
javac -cp ..\library\lexan.jar *.java
Компиляция сәтті болса, демонстрациялық қолданбаны іске қосу үшін келесі пәрменді орындаңыз:
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 бағдарламалау тілінің Regex API интерфейсі оларды қолданбалар мен кітапханаларда пайдалануды жеңілдетеді.java.util.regex
Енді сізде тұрақты өрнектер және осы API туралы негізгі түсінік бар, тұрақты өрнектер және қосымша Regex API әдістері туралы көбірек білу үшін SDK құжаттамасын қараңыз .
GO TO FULL VERSION