Sizning e'tiboringizga Jeff Friesen tomonidan javaworld veb-sayti uchun yozilgan Java tilidagi muntazam iboralar bo'yicha qisqacha qo'llanmaning tarjimasini taqdim etamiz. O'qish qulayligi uchun biz maqolani bir necha qismga ajratdik. Bu qism oxirgi qismdir. Java tilidagi oddiy ifodalar, 1-qism Java tilidagi oddiy iboralar, 2-qism Java tilidagi oddiy iboralar, 3-qism Java tilidagi oddiy ifodalar, 4-qism
Muntazam iboralar qo'lda yozilishi kerak bo'lgan va odatda qayta ishlatib bo'lmaydigan holatga asoslangan leksik analizatorlarga qaraganda ancha samaralidir. Muntazam ifodalarga asoslangan leksik analizatorga misol JLex , Java tili uchun leksik generator bo'lib, u kirish ma'lumotlar oqimini tokenlarga ajratish qoidalarini aniqlash uchun muntazam iboralardan foydalanadi. Yana bir misol Lexan.
Leksik tahlil uchun muntazam iboralardan foydalanish
Muntazam iboralarning yanada foydali qo'llanilishi har qanday kompilyator yoki assemblerning asosiy komponenti bo'lgan leksik tahlilni amalga oshirish uchun qayta foydalanish mumkin bo'lgan kodlar kutubxonasidir. Bunday holda, belgilarning kirish oqimi tokenlarning chiqish oqimiga guruhlanadi - umumiy ma'noga ega bo'lgan belgilar ketma-ketligi nomlari. Masalan, kirish oqimida ,,,,,,,, belgilar ketma-ketligiga duch kelgan holda, leksik analizator tokenc
( identifikator o
) chiqarishi mumkin . Tokenga mos keladigan belgilar ketma-ketligi leksema deyiladi. u
n
t
e
r
ID
Belgilar va leksemalar haqida batafsil |
---|
ID kabi tokenlar ko'plab belgilar ketma-ketligiga mos kelishi mumkin. Bunday tokenlarda tokenga mos keladigan haqiqiy token kompilyator, assembler yoki leksik tahlilni talab qiluvchi boshqa yordamchi dasturga ham kerak bo‘ladi. Bitta belgi ketma-ketligini ifodalovchi tokenlar uchun, masalan, PLUS faqat belgiga mos keladigan token + , haqiqiy token talab qilinmaydi, chunki uni tokendan aniqlash mumkin. |
Lexan bilan tanishish
Lexan - bu leksik tahlil uchun qayta foydalanish mumkin bo'lgan Java kutubxonasi. U Cogito Learning veb- saytidagi Java-da Parser yozish blog postlari seriyasidagi kodga asoslangan . Kutubxona ushbu maqola uchun yuklab olinadigan kodga kiritilgan paketdagi quyidagi sinflardan iborat :ca.javajeff.lexan
Lexan
: leksik analizator;LexException
: leksik tahlil paytida noto'g'ri sintaksis aniqlansa, istisno tashlanadi;Token
: muntazam ifoda atributiga ega nom;TokLex
: token/token juftligi.
LexanException
: sinf konstruktorida chiqarilgan istisnoLexan;
Lexan(java.lang.Class tokensClass)
yangi leksik analizator yaratadi. java.lang.Class
Turi doimiy sinfga mos keladigan sinf ob'ekti ko'rinishidagi bitta argumentni talab qiladi static Token
. Reflection API-dan foydalanib, konstruktor barcha konstantalarni Token
qiymatlar qatoriga o'qiydi Token[]
. Agar Token
doimiylar bo'lmasa, istisno chiqariladi LexanException
. Sinf Lexan
shuningdek quyidagi ikkita usulni taqdim etadi:
- Usul ushbu lekserning ro'yxatini qaytaradi ;
List
getTokLexes() Token
Метод void lex(String str)
turdagi qiymatlar ro'yxatiga [natija joylashtirilgan] kirish qatorining leksik tahlilini amalga oshiradiTokLex
. Agar massiv naqshlaridan birortasiga mos kelmaydigan belgi topilsaToken[]
, istisno tashlanadiLexException
.
LexanException
usullar yo'q; u istisno xabarini qaytarish uchun meros qilib olingan usuldan foydalanadi getMessage()
. Bundan farqli o'laroq, sinf LexException
quyidagi usullarni taqdim etadi:
- Usul
int getBadCharIndex()
marker naqshlarining birortasiga mos kelmaydigan belgi o'rnini qaytaradi. - Usul
String getText()
istisno yaratilganda tahlil qilingan matnni qaytaradi.
Token
usulini bekor qiladi . Shuningdek, u tokenning muntazam ifoda atributini qaytaradigan toString()
usulni taqdim etadi . String getPattern()
Sinf o'z tokenini qaytaradigan TokLex
usulni taqdim etadi . Shuningdek, u o'z tokenini qaytaradigan Token getToken()
usulni taqdim etadi .String getLexeme()
Lexan kutubxonasi namoyishi
Kutubxona qanday ishlashini ko'rsatish uchunLexan
men ariza yozdim LexanDemo
. U LexanDemo
, BinTokens
va sinflaridan iborat . Ilovaning manba kodi 2-listingda ko'rsatilgan. Listing 2. Lexan kutubxonasining amaldagi namoyishiMathTokens
NoTokens
LexanDemo
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()
Listing 2dagi usul lex()
Lexan yordamida leksik tahlilni namoyish qilish uchun yordamchi dasturni chaqiradi. Ushbu usulga har bir qo'ng'iroq ob'ektdagi tokenlar sinfidan Class
va tahlil qilinadigan satrdan o'tadi. Usul birinchi navbatda ob'ektni sinf konstruktoriga o'tkazish orqali lex()
sinf ob'ektini yaratadi . Va keyin u ushbu satrda sinf usulini chaqiradi . Agar leksik tahlil muvaffaqiyatli bo'lsa, ob'ektlar ro'yxatini qaytarish uchun sinf usuli chaqiriladi . Ushbu ob'ektlarning har biri uchun tokenni qaytarish uchun uning sinf usuli va tokenni qaytarish uchun uning sinf usuli chaqiriladi. Ikkala qiymat ham standart chiqishga chop etiladi. Agar leksik tahlil muvaffaqiyatsiz bo'lsa, istisnolardan biri yoki tashlanadi va shunga mos ravishda ishlov beriladi . Qisqartirish uchun keling, faqat ushbu ilovani tashkil etuvchi sinfni ko'rib chiqaylik . Ro'yxat 3 uning manba kodini ko'rsatadi. Listing 3. Kichik matematik til uchun tokenlar to'plamining tavsifiLexan
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_]*");
}
Ro'yxat 3 sinf turi MathTokens
doimiylar ketma-ketligini tasvirlaydi, deb ko'rsatadi Token
. Ularning har biriga ob'ektning qiymati beriladi Token
. Ushbu ob'ektning konstruktori ushbu marker bilan bog'langan barcha belgilar qatorlarini tavsiflovchi muntazam ifoda bilan birga marker nomi bo'lgan qatorni oladi. Aniqlik uchun markerning satr nomi doimiy nomi bilan bir xil bo'lishi ma'qul, ammo bu shart emas. Konstantaning Token
markerlar ro'yxatidagi o'rni muhim ahamiyatga ega. Ro'yxatda yuqorida joylashgan doimiylar quyida Token
joylashganlarga nisbatan ustunlik qiladi. Masalan, ga duch kelganda , Lexan o'rniga sin
tokenni tanlaydi . Agar token tokendan oldin bo'lsa , u tanlangan bo'lardi. FUNC
ID
ID
FUNC
LexanDemo ilovasini kompilyatsiya qilish va ishga tushirish
lexan.zip
Ushbu maqolaning yuklab olinadigan kodi Lexan tarqatishning barcha fayllarini o'z ichiga olgan arxivni o'z ichiga oladi . demos
Ushbu arxivni oching va ildiz katalogining pastki katalogiga o'ting lexan
. Agar siz Windows dan foydalanayotgan bo'lsangiz, demo dastur manba kodlari fayllarini kompilyatsiya qilish uchun quyidagi buyruqni bajaring:
javac -cp ..\library\lexan.jar *.java
Agar kompilyatsiya muvaffaqiyatli bo'lsa, demo ilovasini ishga tushirish uchun quyidagi buyruqni bajaring:
java -cp ..\library\lexan.jar;. LexanDemo
Siz quyidagi natijalarni ko'rishingiz kerak:
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
Xabar sinf doimiy ifoda sifatida qiymatga ega bo'lgan doimiyni e'lon qilmaganligi sababli Неожиданный символ во входном тексте: 20
istisno qilinganligi natijasida yuzaga keladi . E'tibor bering, istisno ishlov beruvchisi matnning leksik tahlilidan olingan nomaqbul belgining pozitsiyasini chiqaradi. Tokens etishmayotgan xabar, sinfda hech qanday konstanta e'lon qilinmagani uchun istisno qilinganligining natijasidir . LexanException
BinTokens
Token
2
LexException
NoTokens
Token
Sahna ortida
Lexan
dvigateli sifatida Lexan sinfidan foydalanadi. 4-listda ushbu sinfning amalga oshirilishini ko'rib chiqing va muntazam iboralarning dvigatelni qayta ishlatishga qo'shgan hissasiga e'tibor bering. Listing 4. Muntazam iboralar asosida leksik analizator arxitekturasini yaratish
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);
}
}
}
Usul kodi Cogito Learning veb-saytidagi "Java'da tahlil qiluvchini yozish: Token generatori"lex()
blog postida keltirilgan kodga asoslangan . Lexan kodni kompilyatsiya qilish uchun Regex API-dan qanday foydalanishi haqida ko'proq bilish uchun ushbu postni o'qing.
Xulosa
Muntazam ifodalar har qanday ishlab chiquvchi uchun foydali bo'lishi mumkin bo'lgan foydali vositadir. Java dasturlash tilining Regex API ularni ilovalar va kutubxonalarda ishlatishni osonlashtiradi.java.util.regex
Endi siz oddiy iboralar va ushbu API haqida asosiy tushunchaga ega bo'lganingizdan so'ng, oddiy iboralar va qo'shimcha Regex API usullari haqida ko'proq ma'lumot olish uchun SDK hujjatlarini ko'rib chiqing .
GO TO FULL VERSION