Diqqətinizə Ceff Friesen tərəfindən javaworld veb-saytı üçün yazılmış Java-da müntəzəm ifadələrə dair qısa bələdçinin tərcüməsini təqdim edirik. Oxumaq asanlığı üçün məqaləni bir neçə hissəyə ayırdıq. Bu hissə son hissədir. Java-da müntəzəm ifadələr, 1-ci hissə Java-da müntəzəm ifadələr, 2-ci hissə Java-da müntəzəm ifadələr, 3-cü hissə Java-da müntəzəm ifadələr, 4-cü hissə
Daimi ifadələr dövlət əsaslı leksik analizatorlardan qat-qat səmərəlidir, əl ilə yazılmalı və ümumiyyətlə təkrar istifadə oluna bilməz. Müntəzəm ifadə əsaslı leksik analizatora misal JLex , Java dili üçün leksik generatordur və giriş məlumat axınını tokenlərə bölmək qaydalarını müəyyən etmək üçün müntəzəm ifadələrdən istifadə edir. Başqa bir nümunə Lexandır.
Leksik təhlil üçün müntəzəm ifadələrdən istifadə
Normal ifadələrin daha faydalı tətbiqi leksik təhlilin aparılması üçün təkrar istifadə edilə bilən kodlar kitabxanasıdır, hər hansı kompilyator və ya assemblerin əsas komponentidir. Bu halda, simvolların giriş axını tokenlərin çıxış axınında qruplaşdırılır - ümumi məna daşıyan simvol ardıcıllığının adları. Məsələn, giriş axınındac
, o
, u
, n
, t
, e
, , simvollarının ardıcıllığı ilə qarşılaşaraq leksik analizator işarəni (identifikator) çıxara bilər. Tokenə uyğun gələn simvolların ardıcıllığına leksemə deyilir. r
ID
Markerlər və leksemlər haqqında ətraflı |
---|
ID kimi tokenlər bir çox simvol ardıcıllığına uyğun gələ bilər. Belə tokenlər olduqda, tokenə uyğun gələn faktiki token həm də tərtibçi, assembler və ya leksik təhlil tələb edən digər köməkçi proqrama lazımdır. PLUS Yalnız simvola uyğun gələn token kimi bir xüsusi simvol ardıcıllığını təmsil edən tokenlər üçün + faktiki işarə tələb olunmur, çünki o, tokendən müəyyən edilə bilər. |
Lexanla tanış olmaq
Lexan leksik analiz üçün təkrar istifadə edilə bilən Java kitabxanasıdır. O , Cogito Learning veb-saytında Java-da Parser Yazmaq bloq yazısı seriyasındakı kodlara əsaslanır . Kitabxana bu məqalənin yüklənə bilən koduna daxil olan paketdə olan aşağıdakı siniflərdən ibarətdir :ca.javajeff.lexan
Lexan
: leksik analizator;LexException
: leksik təhlil zamanı səhv sintaksis aşkar edildikdə atılan istisna;Token
: müntəzəm ifadə atributlu ad;TokLex
: token/token cütü.
LexanException
: sinif konstruktorunda atılan istisnaLexan;
Lexan(java.lang.Class tokensClass)
yeni leksik analizator yaradır. java.lang.Class
Bu tip sabit sinifə uyğun olan sinif obyekti şəklində bir arqument tələb edir static Token
. Reflection API-dən istifadə edərək konstruktor bütün sabitləri Token
dəyərlər massivində oxuyur Token[]
. Sabitlər yoxdursa Token
, istisna atılır LexanException
. Sinif Lexan
həmçinin aşağıdakı iki metodu təqdim edir:
- Metod bu lekserin siyahısını qaytarır ;
List
getTokLexes() Token
Метод void lex(String str)
daxil sətirinin leksik təhlilini [nəticə yerləşdirilmiş] növ dəyərlərinin siyahısına aparırTokLex
. Massiv nümunələrindən heç birinə uyğun gəlməyən simvolla rastlaşsanızToken[]
, istisna atılırLexException
.
LexanException
heç bir metodu yoxdur; istisna mesajını qaytarmaq üçün irsi üsuldan istifadə edir getMessage()
. Bunun əksinə olaraq, sinif LexException
aşağıdakı üsulları təqdim edir:
- Metod
int getBadCharIndex()
marker nümunələrindən heç birinə uyğun gəlməyən simvolun mövqeyini qaytarır. - Metod
String getText()
istisna yaradılarkən təhlil edilmiş mətni qaytarır.
Token
metodu ləğv edir . O, həmçinin işarənin müntəzəm ifadə atributunu qaytaran toString()
bir metod təqdim edir . String getPattern()
Sinif öz işarəsini qaytaran TokLex
bir metod təqdim edir . O, həmçinin işarəsini qaytaran Token getToken()
bir metod təqdim edir .String getLexeme()
Lexan kitabxanasının nümayişi
Kitabxananın necə işlədiyini nümayiş etdirmək üçünLexan
ərizə yazdım LexanDemo
. LexanDemo
O , BinTokens
, MathTokens
və siniflərindən ibarətdir NoTokens
. Tətbiq üçün mənbə kodu LexanDemo
Siyahı 2-də göstərilir. Siyahı 2. Lexan kitabxanasının fəaliyyətdə nümayişi
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();
}
}
Siyahı 2-dəki metod Lexan-dan istifadə edərək leksik təhlili nümayiş etdirmək üçün main()
köməkçi proqramı çağırır lex()
. Bu metoda edilən hər bir çağırış obyektdəki işarələrin sinfindən Class
və təhlil ediləcək sətirdən ötürülür. Metod lex()
əvvəlcə obyekti sinif konstruktoruna Lexan
ötürərək sinif obyektini yaradır . Və sonra həmin sətirdə sinif metodunu çağırır . Leksik təhlil uğurlu olarsa, obyektlərin siyahısını qaytarmaq üçün sinif metodu çağırılır . Bu obyektlərin hər biri üçün işarəni qaytarmaq üçün onun sinif metodu və işarəni qaytarmaq üçün onun sinif metodu çağırılır. Hər iki dəyər standart çıxışa çap olunur. Əgər leksik təhlil uğursuz olarsa, istisnalardan biri və ya atılır və müvafiq olaraq idarə olunur . Qısalıq üçün gəlin yalnız bu tətbiqi təşkil edən sinfi nəzərdən keçirək . Siyahı 3 onun mənbə kodunu göstərir. Siyahı 3. Kiçik bir riyazi dil üçün işarələr toplusunun təsviriClass
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_]*");
}
Siyahı 3 göstərir ki, sinif MathTokens
tipli sabitlərin ardıcıllığını təsvir edir Token
. Onların hər birinə bir obyektin dəyəri təyin edilir Token
. Bu obyektin konstruktoru həmin markerlə əlaqəli bütün simvol sətirlərini təsvir edən müntəzəm ifadə ilə birlikdə markerin adı olan sətir alır. Aydınlıq üçün markerin sətir adının sabitin adı ilə eyni olması arzu edilir, lakin bu tələb olunmur. Markerlər siyahısında sabitin mövqeyi vacibdir. Token
Siyahıda yuxarıda yerləşən sabitlər Token
aşağıda yerləşənlərdən üstündür. Məsələn, qarşılaşdıqda , Lexan əvəzinə sin
nişanı seçir . Token tokendən əvvəl olsaydı , seçilərdi. FUNC
ID
ID
FUNC
LexanDemo proqramının tərtib edilməsi və işə salınması
lexan.zip
Bu məqalənin endirilə bilən koduna Lexan paylanmasının bütün fayllarını ehtiva edən arxiv daxildir . demos
Bu arxivi çıxarın və kök kataloqunun alt kataloquna keçin lexan
. Windows istifadə edirsinizsə, demo proqram mənbə kodu fayllarını tərtib etmək üçün aşağıdakı əmri işlədin:
javac -cp ..\library\lexan.jar *.java
Kompilyasiya uğurlu olarsa, demo tətbiqini işə salmaq üçün aşağıdakı əmri işlədin:
java -cp ..\library\lexan.jar;. LexanDemo
Aşağıdakı nəticələri görməlisiniz:
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
Mesaj, sinfin normal ifadə kimi dəyəri olan sabiti elan etməməsi Неожиданный символ во входном тексте: 20
səbəbindən bir istisnanın atılması nəticəsində baş verir . Qeyd edək ki, istisna işləyicisi mətnin leksik təhlilindən əldə edilən uyğun olmayan simvolun mövqeyini çıxarır. Çatışmayan token mesajı, sinifdə heç bir sabit elan edilmədiyi üçün atılan istisnanın nəticəsidir . LexanException
BinTokens
Token
2
LexException
NoTokens
Token
Pərdə arxasında
Lexan
mühərriki kimi Lexan sinfindən istifadə edir. Siyahı 4-də bu sinfin tətbiqinə nəzər salın və müntəzəm ifadələrin mühərriki təkrar istifadə edilə bilən hala gətirməsinə töhfəsini qeyd edin. Siyahı 4. Normal ifadələr əsasında leksik analizator arxitekturasının yaradılması
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);
}
}
}
Metod kodu Cogito Learning veb-saytında "Java-da Ayrışdırıcının Yazılması: Token Generatoru"lex()
bloq yazısında verilmiş koda əsaslanır . Lexan-ın kodu tərtib etmək üçün Regex API-dən necə istifadə etdiyini öyrənmək üçün bu yazını oxuyun.
Nəticə
Daimi ifadələr istənilən tərtibatçı üçün faydalı ola biləcək faydalı bir vasitədir. Java proqramlaşdırma dilinin Regex API onları proqramlarda və kitabxanalarda istifadəni asanlaşdırır.java.util.regex
Artıq müntəzəm ifadələr və bu API haqqında əsas anlayışınız olduğuna görə, müntəzəm ifadələr və əlavə Regex API metodları haqqında daha çox öyrənmək üçün SDK sənədlərinə nəzər salın .
GO TO FULL VERSION