|
Tiplarni dinamik tarzda aniqlash. Reja: Tiplarni dinamik tarzda aniqlash
|
bet | 75/143 | Sana | 20.07.2024 | Hajmi | 0,81 Mb. | | #268096 |
Bog'liq Tiplarni dinamik tarzda-fayllar.orgSintaktik analizatorni yaratish. Odatda, mashina tilidagi matn gaplar, gap- gaplar ostidan, gap osti esa, o‘z navbatida, gaplar ostidan va shu kabi belgilardan hosil bo‘ladi. Masalan, XML hujjatda boshlanish tegi, qiymat, yopish teglari mavjud. Boshlanish tegi [<] belgisi, teg nomi va qanday atribut va qiymatlari, [>] belgisidan iborat. Yopish tegi esa, []belgisi bilan tugaydi. Atribut esa nomi, [=], [“], belgilar to‘plami va yana [“] belgisidan iborat va takrorlanishi mumkin. Qiymat esa qandaydir belgilar to‘plami yoki qandaydir elementlardan (gap, gap osti, ifoda) iborat. Tahlil natijasida tahlil daraxtini hosil qilish mumkin.
Bunday tillarni har bir terminal bo‘lmagan tilning maʻlum bir jumlasiga mos keladigan Backus-Naur shakli (BNSh) yordamida tasvirlash qulay. Dasturlarni yozganda, odatda ularni funksiyalarga va funksiya ostilarga ajratamiz va sietatik tahlillovchi yozmoqchi bo‘lganimiz uchun, har bir BNSh terminal bo‘lmagan sintatik tahlillovchimizning bitta funksiyasiga mos kelsin va har bir bunday funksiya:
ushbu jumlani berilgan pozitsiyadan ajratishga harakat qilish;
bu ishni bajardimi yo‘qmi natijasini qaytarish;
tahlil tugagani yoki xato sodir bo‘lgan pozitsiyani qaytarish;
tahlil natijasida olish kerak bo‘lgan baʻzi qo‘shimcha maʻlumotlarni qaytarish;
Masalan, BNSh ko‘rinishida expr ::= expr1 expr2 expr3 funksiyani yozamiz:
bool read_expr(char *& p, ){
if(!read_expr1(p, ))
return false;
// read_expr1() fuksiyasi expr1 tahlil tugaga pozitsiyada p qoʻyadi
// bu pozitsiyada p bilan hech qanday amal bajarilmaydi. if(!read_expr2(p, ))
return false; if(!read_expr3(p, ))
return false; return true;
}
|
Davomi sifatida, BNSh ko‘rinishida expr ::= expr1|expr2|expr3 funksiyani yozamiz:
bool read_expr(const char *& p, ){
const char * l = p; if(read_expr1(p, ))
return true;
// expr1 tahlil jarayonida p xato boʻlgan joyni koʻrsatadi p = l;
if(read_expr2(p, ))
return true;
p = l;
if(read_expr3(p, ))
return true; return false;}
|
Bu sintatik tahlillash qiymat qaytarish asosidagi rekursiv kamayish usuliga asoslangan.
Ixtiyoriy matnni BNSh ko‘rinishida keltirish mumkin. Masalan, XML tilidagi quyidagicha yozish mumkin:
element ::= '<'identifier'>'some_data''
Agar identifikatorlari mos kelsa bu haqiqattan ham to‘g‘ri keladi. Bunday amallarni sintaktik tahlillovchiga qo‘shish muammo emas. Masalan, terminal funksiyalar quyidagicha bo‘lishi mumkin:
bool read_fix_char(const char *& it, char c){ if(!*it) return false; // satr oxiri
if(*it!=c) return false;// boshqa simvol
// xato boʻlganda joyiga qolish bajariladi
it++; // keyingisiga oʻtish return true;
}
bool read_fix_str(const char * & it, const ch_t * s){ while(*it)// satr tugamagancha
if(!*s)
return true; else if(*it!=*s)
return false;
// xato boʻlganda joyiga qolish bajariladi
else
it++, C++;
if(!*s) return true; return false;
}
|
Satrni sintaktik tahlil qilganimizda yuqoridagi funksiyalarning barcha tiplari uchun forward iteratorlar yetarli ekanligini biling.
forward iteratorlarni taqdim etadigan va faylni butunlay emas, fayl o‘rniga kichik qismlarga xotirada saqlaydigan sinf oqimni yaratishni qaraymiz. Agar shablonlar asosida tahlillovchi funksiyani yaratishni xoxlasak, ularni satrlar va/yoki oqimlardan foydalanish mumkin (base_parse.h kutubxonasi terminal funksiyalari uchun, bu sinfni diskdagi mavzuga oid papkaga qarang). Birinchi navbatda unix «barcha fayllar bor»: ideyalogiyasiga baʻzi aniqliklarni kiritib olamiz: Shunday fayllar bo‘ladiki, ular disk bo‘yicha joylashgan va ularni ixtiyoriy pozitsiyasidan bir necha marta o‘qish mumkin(ularni random-access fayllar deb aytiladi), shunday oqimlar bo‘ladiki, tarmoqdan, klaviaturadan, boshqa ilovalardan yo‘naltirilgan (bularni forward oqimlar deb aytiladi). Bunday oqimlarni bir martaga o‘qish kerak. Shuning uchun, unisi va bunisi bilan ishlash uchun bir yondashuvda faylni o‘qiydigan, forward iteratorlarni qo‘llab quvvatlaydigan, xotirada faylni to‘liq emas, balki maʻlum bir bo‘lagini saqlaydigan sinf-oqimni yaratish maqsadga muvofiq.
Bunday oqimlar Input iteratorlar uchun ancha oldin yaratilgan, maqsadi faqat ularda Input iteratorlar, bu iterator harakatlanishi uchun bitta bufer bo‘ladi. Qachonki, bufer oxiriga kelganda buferga faylning keyingi bo‘lagi yuklanadi hamda iterator bo‘shatilgan bufer boshidan harakatlanishni boshlaydi (7.1-rasmga qarang).
|
| |