Bosh sahifa Wiki Compiler

Compiler

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:

  1. lexical analysis;
  2. syntax analysis;
  3. semantic analysis;
  4. intermediate representation;
  5. optimization;
  6. code generation;
  7. object file yaratish;
  8. 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:

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:

  • machine code;
  • data section;
  • symbol table;
  • relocation;
  • debug information;
  • metadata.

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:

  • shubhali conversion;
  • unused variable;
  • unreachable code;
  • deprecated API;
  • implicit behavior

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:

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