Compiler — bir dasturlash tilida yozilgan source code’ni boshqa ko‘rinishga, odatda mashina kodi, object code, bytecode yoki boshqa dasturlash tiliga aylantiradigan dastur.
Compiler faqat matnni tarjima qilmaydi. U source code’ni tahlil qiladi, xatolarni aniqlaydi, ichki representation yaratadi, optimallashtiradi va target platforma uchun natija hosil qiladi.
C, C++, Rust, Go va boshqa tillarda compiler dastur yaratish jarayonining asosiy qismidir.
Compilation jarayoni
Klassik compiler pipeline quyidagi bosqichlardan iborat:
- lexical analysis;
- syntax analysis;
- semantic analysis;
- intermediate representation;
- optimization;
- code generation;
- object file yaratish;
- linker bilan yakuniy executable yaratish.
Har compiler bu bosqichlarni aynan bir xil tarzda ajratmasligi mumkin.
Lexical analysis
Lexer source code’ni tokenlarga bo‘ladi.
Misol:
sum = a + 10;
Tokenlar:
IDENTIFIER(sum)
ASSIGN
IDENTIFIER(a)
PLUS
NUMBER(10)
SEMICOLON
Whitespace va comment ko‘pincha parsing uchun olib tashlanadi, ammo source location saqlanadi.
Syntax analysis
Parser tokenlar ketma-ketligini grammar asosida tekshiradi.
Natija odatda Abstract Syntax Tree.
Misol:
Assignment
├── Variable: sum
└── Add
├── Variable: a
└── Number: 10
Qavs, operator priority va statement structure shu bosqichda aniqlanadi.
Semantic analysis
Syntax to‘g‘ri bo‘lsa ham ma’no xato bo‘lishi mumkin.
Compiler quyidagilarni tekshiradi:
- o‘zgaruvchi e’lon qilinganmi;
- type mosmi;
- function argument soni;
- return type;
- scope;
- access control;
- duplicate declaration;
- generic constraint.
Misol:
integer + file object
syntax jihatdan operator ko‘rinishiga mos, lekin semantic jihatdan ruxsat etilmasligi mumkin.
Symbol table
Compiler identifierlar haqida ma’lumotni symbol table’da saqlaydi.
Unda:
bo‘lishi mumkin.
Nested scope’lar alohida symbol table yoki parent bog‘lanish orqali boshqariladi.
Intermediate representation
Source tildan mustaqil ichki kod IR deb ataladi.
IR compiler front-end va back-endni ajratadi.
Bir nechta source til bir IRga aylantirilishi, keyin bir nechta target platformaga code generation qilinishi mumkin.
LLVM IR bunga mashhur misol.
Front-end
Compiler front-end source tilni tushunadi.
Vazifalari:
Yangi til qo‘shishda front-end yaratiladi.
Back-end
Back-end target architecture’ni tushunadi.
Vazifalari:
- instruction selection;
- register allocation;
- instruction scheduling;
- machine code generation;
- target-specific optimization;
- object file emission.
x86-64, ARM64 va RISC-V uchun alohida back-end bo‘lishi mumkin.
Optimization
Optimization dastur semantikasini saqlagan holda tezlik, hajm yoki energiya sarfini yaxshilaydi.
Misollar:
- constant folding;
- dead code elimination;
- inlining;
- loop unrolling;
- common subexpression elimination;
- strength reduction;
- vectorization;
- tail-call optimization.
Constant folding
Compile vaqtida hisoblanadigan ifoda oldindan yechiladi.
3 × 4 + 2
machine code’da 14 constant sifatida qolishi mumkin.
Dead code elimination
Natijaga ta’sir qilmaydigan kod olib tashlanadi.
x = 10
x = 20
print(x)
Birinchi assignment ishlatilmasa olib tashlanishi mumkin.
Side effect mavjud kodni o‘chirish mumkin emas.
Inlining
Kichik function call o‘rniga uning body’si joylashtiriladi.
Afzalligi:
- call overhead kamayadi;
- keyingi optimization imkoniyati oshadi.
Kamchiligi:
- executable hajmi kattalashadi;
- instruction cache bosimi;
- debug murakkabligi.
Register allocation
Compiler virtual qiymatlarni cheklangan CPU registerlariga joylashtiradi.
Register yetmasa qiymat stackka spill qilinadi.
Yaxshi allocation memory accessni kamaytiradi.
Code generation
IR target instructionlarga aylantiriladi.
Compiler:
- instruction tanlaydi;
- operand joylashtiradi;
- calling conventionga rioya qiladi;
- stack frame yaratadi;
- relocation yozadi;
- debug info qo‘shadi.
Object file
Compilation natijasi darhol executable bo‘lmasligi mumkin.
Object file tarkibi:
Linker bir nechta object va library’ni birlashtiradi.
Ahead-of-time compilation
AOT compiler dastur ishga tushishidan oldin target code yaratadi.
Afzalliklari:
- startup tez;
- runtime compiler talab qilinmaydi;
- predictable deployment;
- native optimization.
Kamchiligi — runtime profiling ma’lumotidan kamroq foydalanadi.
Just-in-time compilation
JIT runtime vaqtida bytecode yoki IRni native codega aylantiradi.
Afzalliklari:
- haqiqiy workload bo‘yicha optimization;
- hot functionlarni aniqlash;
- platformaga mos code.
Kamchiligi:
- startup overhead;
- qo‘shimcha memory;
- runtime murakkabligi.
Cross-compiler
Compiler bir platformada ishlab, boshqa target uchun code yaratadi.
Misol:
x86-64 Linux host → ARM embedded target
Cross toolchain:
dan iborat.
Bootstrap compiler
Compilerning o‘zi kompilyatsiya qilayotgan tilda yozilishi mumkin.
Yangi til avval boshqa tilda yoki sodda compiler bilan yaratiladi, keyin o‘zini compile qilish bosqichiga o‘tadi.
Bu self-hosting deb ataladi.
Error va warning
Compiler error code yaratishni to‘xtatadi.
Warning:
haqida xabar beradi.
Warningni e’tiborsiz qoldirish mumkin, lekin CI’da ayrim warning errorga aylantiriladi.
Debug information
Compiler source line, variable va function ma’lumotini object yoki alohida debug file’ga yozadi.
Optimizationda:
mumkin. Shu sababli optimized binary debugging murakkabroq.
Reproducible build
Bir xil source va toolchain bir xil binary berishi kerak bo‘lgan jarayon reproducible build deyiladi.
Timestamp, path, random seed va environment natijani o‘zgartirishi mumkin.
Supply-chain audit uchun muhim.
Compiler va interpreter
Compiler odatda code’ni oldindan boshqa formatga aylantiradi.
Interpreter source yoki bytecode’ni runtime’da bajaradi.
Ko‘p zamonaviy til ikkala yondashuvni birlashtiradi:
- source bytecodega compile qilinadi;
- virtual machine interpretatsiya yoki JIT qiladi.
Diagnostika
Compilation muammosida:
- compiler version;
- target;
- optimization level;
- include path;
- macro;
- language standard;
- warning;
- generated IR yoki assembly;
- linker bosqichi;
- environment
tekshiriladi.
Source bir compilerda ishlashi undefined behavior yoki non-standard extension sabab boshqasida ishlamasligi mumkin.
Bog‘liq tushunchalar
Lexer, Parser, AST, Semantic analysis, Intermediate representation, Optimization, Code generation, Assembler, Linker, JIT