Tiplarni dinamik tarzda aniqlash. Reja: Tiplarni dinamik tarzda aniqlash - bet 76

|
Tiplarni dinamik tarzda aniqlash. Reja: Tiplarni dinamik tarzda aniqlash
|
bet | 76/143 | Sana | 20.07.2024 | Hajmi | 0,81 Mb. | | #268096 |
Bog'liq Tiplarni dinamik tarzda-fayllar.org7.1-rasm. Input iteratorlardan foydalanish.
Forward iteratorlarning input iteratrlardan farqi ularni nusxalash mumkinligidir. Bunday masalada oqimlarda forward iteratorlardan foydalanish uchun buferlar ro‘yxatini hosil qilish orqali echiladi. Qandaydir iterator birinchi buferga murojaati bilan ro‘yxatga yangi bufer qo‘shiladi va fayldagi blok maʻlumotlar bilan to‘ldiriladi. Ammo bu usulda fayl to‘liq xotiraga yuklanadi,bu holat kerakmas. Shunday qilamizki, buferning chap tomonidagi joylashgan oxirgi chap iterator joylangan barcha buferlari o‘chirilsin. Lekin, unga joylashgan buffer ro‘yxati bilan har bir iterator mos bo‘lmaydi, lekin faqat ularning sonini mos bo‘ladi (hisoblovchi iteratorlari). Biror bir bufer 0 iterator qolganini va u eng chap ekanligini bilsa, u barcha undan o‘ng buferdagi barcha qo‘shnilari o‘chiriladi. Chunki ular ham 0 iteratorga ega bo‘ladi(7.2-rasmga qarang).
7.2-rasm. Forward iteratorlardan foydalanish.
Bunday kelib chiqadiki, har bir iterator quyidagilarni o‘z ichiga olishi kerak:
belgiga ko‘rsatkich(qayta nomlanishda qaytariladigan qiymat);
bufergadagi belgilar massivning oxiriga ko‘rsatkich iterator harakatlanganda taqqoslash amalga oshiriladi);
bufer ro‘yxati bo‘yicha iteratorlar (bufer maʻlumotlariga murojjat uchun va ular orqali butun oqim maʻlumotlariga murojjat).
Iterator bufer chegarasiga etganda, u keyingi buferlar ro‘yxatda borligini tekshiradi, bo‘lmasa - uni yuklaydi, oldingi bufer iteratorlar sonini kamaytiradi va keyingisini sonini oshiradi. Agar oldingi buferda 0 ta iterator qolgan bo‘lsa, u o‘chiriladi. Agar iterator faylning oxirigacha kelgan bo‘lsa, u faqat oldingi buferdan chaqiriladi va "faylning oxiri" holatiga o‘tadi. Bir iteratorning nusxasini olganda – joriy buferda iteratorlarning soni bittaga ko‘payadi, iteratorning destruktori ishlaganda bittaga kammayadi, va, yana 0 bufer bor bo‘lsa qolgan iteratorlar, u va o‘ngda undan keyingi buferlar, shuningdek 0 iteratori borlari o‘chiriladi. Amalga oshirish uchun diskdagi mavzuga oid papkadagi forward_stream.h ga qarang.
Bunday iteratorlar anʻanaviy iteratorlardan ularni ajratib turadigan baʻzi xususiyatlarga ega. Masalan, bir oqimni (buferlar va baʻzi qo‘shimcha maʻlumotlar ro‘yxatini saqlaydigan) o‘chirish oldin (destruktor tomonidan), barcha iteratorlar o‘chirilgan bo‘lishi kerak, ularni o‘chirish vaqtida o‘zlariga bog‘liq bo‘lmagan holda buferlarga o‘z navbatida o‘chirilganligini aniqlash murojaat qiladi. Agar begin() usulini chaqirish (birinchi buferni yaratish) natijasida birinchi iteratorni bir marta olsak va u shu paytgacha birinchi bufer allaqachon o‘chirib tashlangan bo‘lsa, yana begin() usuli yordamida iteratorni ololmaymiz. Bundan tashqari oqimning end() usuli yo‘q. Natijada, oqimda ichki iterator yaratish kerak bo‘ladi, yaʻni barcha oqimlar yaratilayotganda yaratiladigan va mos yozuvlar iter() usuli yordamida olinishi mumkin. Bundan tashqari, algoritmlarni ishlatganda, iteratorlaran tez-tez nusxalash kerak emas, chunki xotira chapdan o‘nggacha bo‘lgan iteratorda buferlarni saqlaydi. Katta fayllar uchun bu katta xotira talab qilishiga olib keladi.
Yordam sifatida har xil turdagi buferlar mavjud: oddiy (basic_simple_buffer), qator-ustunli iteratorni (basic_adressed_buffer). Bular yordamida hisoblash uchun turli kodlashlar orasida qayta kodlashni bajaruvchi bufer qilish mumkin. Shu munosabat bilan oqim buferning tipi bilan parametrlashtiriladi.
Buyruqlar satrining oxiri null belgi bilan belgilanadi. Bu shuni anglatadiki, uning oxirini topish uchun satr orqali harakat qilsak, ko‘rsatgichni boshqa ko‘rsatgich bilan solishtirishimiz shart emas (STLda anʻanaviy tarzda amalga oshiriladi), aksincha, ko‘rsatgichimiz tomonidan ko‘rsatilgan qiymatni tekshirish kerak. Fayllar bilan bog‘liq vaziyat ham shunday. Belgili kiritishda belgilar asosida sonlarni olamiz va ular katta qiymatlar satriga ega bo‘lgani uchun yana har bir belgini EOF() funksiya bilan taqqoslanadi. Real vaqtda keladigan forward oqimlar uchun faylning oxiri holati oldindan nomaʻlum.
Bu muammoni satrli ko‘rsatgichlar uchun atend(it) funksiyasini tuzish orqali umumlashtirish mumkin:
bool atend(const char * p)
{ return !*p; }
|
Agar iterator faylning oxirini ko‘rsatsa, oqim bo‘yicha iteratorlarga true qiymat qaytaradi.
Foydalanuvchi bilan interaktiv hamkorlik qilish uchun (stdin orqali) blokli buferlash amalga oshirilmaydi, chunki blokda odatda bir nechta satr joylashtiriladi va bitta satr kiritilgandan so‘ng, dastur foydalanuvchidan kirishni kutishni davom etadi, chunki blok hali to‘lmagan. Satrning oxirigacha bo‘lgan belgilar buferni to‘ldiradi va buning uchun satrli buferlash kerak. Ushbu kutubxonada oqim ishga tushirilganda fayl tipini tanlab buferlash turini tanlashingiz mumkin (basic_block_file_on_FILE yoki string_file_on_FILE).
strin – stdin orqali satrli buferlash uchun buferning ichki iteratoridir. Interaktiv bo‘lmagan fayllar uchun oqim yaratishda birinchi belgiga ishora qiluvchi iterator yaratiladi, yaʻni birinchi bufer yuklanadi. Bunga strin uchun ruxsat berilmaydi, chunki dasturchi satr rejimidan kiritishni kutishdan oldin biror bir narsa amalga oshirish yoki ekranga chiqarigi mumkin.
Shu sababli birinchi buferni to‘ldirishda satrli fayllari ishlatilganda belgili buyruq ‘\nʻ dan foydalaniladi. Uni o‘qish uchun, start_read_line (it) funksiyasi mavjud, shundan so‘ng satrni tahlil qilish uchun dastur satrni kiritishni kutish rejimiga keladi va keyingi belgi ‘\nʻ tashqarida chiqishda iterator bu satrni ajratib oladi.
Agar bundan keyin yana foydalanuvchidan maʻlumotlar kerak bo‘lsa, dasturchi yana ekranda biror narsani chiqarishni xohlashi mumkin va uni olishdan oldin yana start_read_line(strin) dfn foydalanish mumkin. Bunda quyidagicha takrorlanish hosil qilinadi:
Albatta, bu fragment faqat qayta nomlash vaqtida buferni yuklashda iterator talab qilish mumkin, lekin bu qayta nomlash qachon qo‘shimcha tekshirishlar olib kelishi va butun tizimini murakkablashtirishi mumkin.Sintatik tahlillovchilarning bazaviy funksiyalari. Har safar terminal funksiyalarni yozish dasturchilarga noqulaylik keltirmasligi uchun
«base_parse.h» sinfida tayyorlab qo‘yilgan. Hozirda u umumiy ko‘rinishda (xaqiqiy sonlardan tashqari) tayyorlangan va kelajakda satr bo‘yicha ko‘rsatkichlar va oqim bo‘yicha iteratorlar uchun satrli fuknsiyalar (strcmp, strstr, strchr, strspn, strcspn kabi) ishlaydigan qismini tuzish rejalashtirilgan. Shuningdek bu faylning oxiri haqida o‘ylashi kerak emas, faqat fragmentni to‘g‘ri yozsa bo‘ladi.
Quyida parsingning bazaviy funksiyalari qisqacha keltirilgan va ikki test parserni amalga oshirish paytida ularning foydalanish statistikasi va natijaviy qiymatlari faytaradigan dastur keltirilgan.
size_t n
ch_t c
ch_t * s
func_obj bool is(c) // bool isspace(c)
|
span spn
bispan bspn
func_obj err pf(it*) // int read_spc(it*) func_obj err pf(it*, rez*)
|
|
| |