Fordítóprogram

Ez a szócikk azokkal a fordítóprogramokkal foglalkozik, melyek egyik programozási nyelvről a másikra alakítanak át kódot. A nyelvi fordítással kapcsolatban lásd a Gépi fordítás szócikket.

A fordítóprogram (angolul compiler) olyan számítógépes program, amely valamely programozási nyelven írt programot képes másik nyelv szabályaira lefordítani, például gépi kódra, köztes kódra, vagy egy másik programozási nyelv kódjára. A fordítóprogram elnevezést első sorban olyan programokra használják, ahol a forráskód (source code) valamilyen magas szintű programozási nyelv (például a C# Java), a célnyelv, amire lefordul a program pedig valamilyen alacsony szintű nyelv (pl. assembly vagy gépi kód), amik már futtatható kódok.

Egy tipikus többnyelvű, többcélú fordítóprogram működésének sematikus vázlata

Sokféle különböző fordítóprogram létezik. Ha a lefordított program olyan számítógépen bír futni, aminek a CPU-ja vagy az operációs rendszere különbözik attól a számítógéptől, amin a fordítás végbement, akkor keresztirányú fordítóprogramról (cross compilerről) beszélünk. A bootstrap compiler olyan fordító, amit azon a nyelven írnak, amit le kíván fordítani. Az a fordító ami alacsony szintű nyelvről magasabb szintű nyelvre fordít decompiler-nek nevezik. Az a program, ami adott magas szintű programozási nyelvről egy másik magas szintű programozási nyelvre fordít source-to-source compiler. Egy nyelv újraíró olyan program, ami a kifejezések formáját nyelvváltoztatás nélkül hajtja végre. A fordító generátor ompiler-compiler fogalom olyan programozó eszközt takar, amely elemzőt, értelmezőt vagy fordítót hoz létre a programozási nyelv és a gép formális leírása alapján.

CsoportosításSzerkesztés

A fordítandó programot forrásprogramnak (nyelvét forrásnyelvnek), a lefordított programot tárgyprogramnak (nyelvét tárgynyelvnek) nevezzük.

E szerint a fordítóprogramokat a következőképp csoportosíthatjuk:

  • natív-kódra fordítók
  • több platformra fordítók
  • magas szintű nyelvből egy másik magas szintű nyelvre

KivitelezésSzerkesztés

A fordítóprogram végrehajtja a formális átalakítást egy magas szintű forrásnyelvről egy alacsony szintű tárgynyelvre. A fordítókészlet meghatároz egy végponttól végpontba (end to end) megoldást, vagy kezelhet egy meghatározott részhalmazt, amely kapcsolódik más fordítási eszközökhöz pl. előfeldolgozókhoz (preprocessors), összeszerelőkhöz (assemblers), összekötőkhöz(linkers). A tervezési követelmények szigorúan meghatározott felületeket tartalmaznak mind a fordítóelemek mind pedig a támogató eszközök között.

Kezdetben a fordítók tervezésének megközelítését közvetlenül befolyásolták a feldolgozandó számítógépes nyelv összetettsége, a tervező személy(ek) tapasztalata és a rendelkezésre álló források. Az erőforrás-korlátozások szükségessé tették a forráskód többszöri áthaladását.

Egy viszonylag egyszerű nyelv fordítója, amelyet ember írt, lehet egyetlen monolitikus szoftver. Mivel azonban a forrásnyelv ettől bonyolultabbá válhat, a terv több egymástól függő fázisra bontható. Külön szakaszok biztosítják a tervezési fejlesztéseket, amelyek a fejlesztés a fordítási folyamat funkcióira összpontosítanak.


A fordítóprogramok két fázisban dolgozzák fel a kódot:

  • az elsőben lefordítja a forráskódot egy közbeeső kódra (előrész)
  • a második fázisban történik az úgynevezett fordítási eljárás. (hátrész)

Első fázis (Front End)Szerkesztés

Ezt a fázist három nagy fázisra lehet bontani: lexikális elemzésre, szintaktikai elemzésre és szemantikai elemzésre.

A front end a forráskódot elemzi a program belső reprezentációjának és az ún. közbenső reprezentációnak (intermediate representation, IR) felépítéséhez. Ezen felül kezeli a szimbólumtáblát, egy adatszerkezetet amely leképzi a forráskód minden szimbólumát a kapcsolódó információkkal mint például a hely, típus és hatókört (scope).

Lexikális elemzésSzerkesztés

A forráskód tokenizálása, felbontása a szintaktikai elemzőnek értelmezhető szimbólumokká, azaz a nyers forrásszövegből kreál szimbólumsorozatot, általában operátorok, fenntartott szavak, azonosítók stb. formájában. A lexikai hibák általában elírásokból adódnak, ezeket legjobb tudásuk szerint elfedik az elemzők, sokszor kitalálva, mit is akarhatott írni a programozó.

Szintaktikai elemzésSzerkesztés

A nagyrészt környezetfüggetlen nyelvtan alapján felépíti a szintaxisfát, az esetleges hibákat tudása szerint átugorva.

Főbb fajtái az LL és az LR elemzők.

Szemantikai elemzésSzerkesztés

A dinamikus szemantika ellenőrzése történik ebben a szakaszban, típusellenőrzések, függvények paraméterszáma, típushelyessége, általában a programkód értelmessége. Míg a lexikális és a szintaktikus ellenőrzésre már igen jó automatizált eszközeink vannak, a szemantikus elemzést mindeddig nem sikerült általánosan és hatékonyan automatizálni.

HátrészSzerkesztés

Itt történik a közbeeső kód lefordítása gépi kódra. Ez is több lépésből tevődik össze:

  1. optimizálás: opcionális, a közbeeső kód átalakítása kisebb és gyorsabb formába (a program kívülről látható működése ettől (többnyire) nem változik). Általában ezt már az assembly nyelvű kódon végzi a fordítóprogram.
  2. kódgenerálás: a gépi kód generálása. A mnemonikok egyszerű átfordítása gépi kóddá valamint a modulon belül feloldható hivatkozások feloldása, ugrási címkék kiszámítása.

Fordítóprogram vagy interpreter?Szerkesztés

A magas szintű programozási nyelven megírt programot futtatáshoz fordítóprogrammal lefordítjuk gépi kódra, vagy interpreterrel interpretárjuk, vagyis értelmezzük. Az első esetben ún. object code keletkezik, amiből szerkesztéssel lehet futtatható programot készíteni. A második esetben általában nem keletkezik futtatható program, legfeljebb egy tömör, mindenféle felesleges résztől mentes közbülső kód (néha ún. bytecode), amit az interpreter második fázisa végrehajt.

TörténetSzerkesztés

A tudósok, matematikusok és mérnökök által kidolgozott elméleti számítási koncepciók képezték a digitális modern számítástechnika fejlesztésének alapját a második világháború idején. Az elsődleges bináris nyelvek azért fejlődtek ki, mert a digitális eszközök csak az egyeseket és a nullákat, valamint az alapjául szolgáló gépi architektúra áramkörmintáit értik meg. Az 1940-es évek végén assembly nyelveket hoztak létre, hogy a számítógépes architektúrák jobban kivitelezhetők legyenek. A korai számítógépek korlátozott memóriakapacitása komoly technikai kihívásokhoz vezetett az első fordító tervezésekor. Ezért a fordítási folyamatot több kisebb programra kellett felosztani. A felhasználói felületek programjai előállítják azokat az elemző termékeket, amelyeket a back end a célkód előállításához használnak. Ahogyan a számítógépes technológia több forrást biztosított, a fordítók jobban igazodhattak magához a fordítási folyamathoz.

A programozók számára általában hatékonyabb a magas szintű nyelv használata, így a magas szintű nyelvek fejlesztése a digitális számítógépek által kínált lehetőségekből fakad. A magas szintű nyelvek olyan formális nyelvek, amelyeket szintaxisuk és szemantikájuk szigorúan meghatároznak, és amelyek a magas szintű nyelvi architektúrát alkotják. Ezen formális nyelvek elemei a következők:

  • Ábécé, bármilyen véges szimbólumkészlet;
  • Karakterlánc, a szimbólumok véges sorozata;
  • Nyelv, bármilyen karakterlánckészlet ábécében.

A mondatokat egy nyelvben meghatározhatja egy nyelvtannak nevezett szabálykészlet.

A Backus – Naur forma (BNF) leírja a nyelv „mondatainak” szintaxisát, és John Backus az Algol 60 szintaxisához használta. Az ötletek Noam Chomsky, nyelvész, kontextus nélküli nyelvtani fogalmaiból származnak. "A BNF és annak kiterjesztései sztenderd eszközökké váltak a programozási jelölések szintaxisának leírására, és sok esetben a fordítók részeit automatikusan generálják a BNF leírásból."

Az 1940-es években Konrad Zuse egy algoritmikus programozási nyelvet készített Plankalkül ("Plan Calculus") néven. Noha az 1970-es évekig nem valósult meg a megvalósítás, a későbbiekben az APL-ben látott koncepciókat mutatta be, amelyeket Ken Iverson tervezett az 1950-es évek végén.A z APL egy nyelv matematikai számításokhoz.

A magas szintű nyelvtervezés a digitális számítástechnika kialakulási éveiben hasznos programozási eszközöket nyújtott számos alkalmazáshoz:

  • A mérnöki és tudományos alkalmazásokban használt FORTRAN (Formula Translation) tekinthető az első magas szintű nyelvnek.
  • A COBOL (Common Business-Oriented Language) az A-0-ból és a FLOW-MATIC-ból alakult ki az üzleti alkalmazások domináns magas szintű nyelvévé.
  • LISP (List Processor)szimbolikus számításhoz.

A fordítótechnika a magas szintű forrásprogram szigorúan meghatározott átalakításának szükségességéből fejlődött ki a digitális számítógép alacsony szintű célprogramjává. A fordítót előtérként lehet tekinteni a forráskód elemzésének kezelésére, és a back end az elemzés célkódba történő szintetizálására. A front end és a back end közötti optimalizálás hatékonyabb célkódot eredményezhet.

Korai mérföldkövek a fordító technológia fejlesztésében:

  • 1952 - Alick Glennie által kidolgozott Autokód-fordítót a Manchesteri Egyetemen a Manchester Mark I számítógéphez egyenek tekintik az első összeállított programozási nyelvek közül.
  • 1952 - Grace Hopper Remington Rand csapata az A-0 programozási nyelv fordítóját írta (és már a fordító kifejezést használta annak leírására), bár az A-0 fordító inkább betöltőként vagy összekötőként működött, mintsem úgy mint egy  teljes fordító.
  • 1954-1957 - John Backus vezetésével az IBM fejlesztette ki a FORTRAN-t, amelyet általában az első magas szintű nyelvként tartanak számon. 1957-ben befejezték a FORTRAN fordítót, amelyet úgy tekintenek, mint az első egyértelműen teljes fordító bevezetését.
  • 1959 - Az adatrendszer-nyelvi konferencia (CODASYL) elindította a COBOL fejlesztését. A COBOL kialakítása az A-0 és a FLOW-MATIC rajzokra támaszkodott. Az 1960-as évek elején a COBOL-t több architektúrára állították össze.
  • 1958-1962 - John McCarthy,az MIT-nél tervezte meg a LISP-t. A szimbólumfeldolgozó képességek hasznos funkciókat nyújtottak a mesterséges intelligencia kutatására. 1962-ben a LISP 1.5 kiadás néhány eszközt felsorolt: Stephen Russell és Daniel J. Edwards írta az interpretert,míg Tim Hart és Mike Levin a fordítót és az assemblert írta.

A korai operációs rendszereket és szoftvereket assembly nyelven írták. A 60-as években és a 70-es évek elején az erőforrások korlátozottsága miatt a magas szintű nyelvek használata a rendszerprogramozásban továbbra is vitatott volt. Számos kutatási és ipari erőfeszítés azonban elindította az elmozdulást a magas szintű rendszerek programozási nyelvei felé, például a BCPL, a BLISS, a B és a C.

BCPL-t (alapvető kombinált programozási nyelv), amelyet 1966-ban tervezett Martin Richards a Cambridge-i Egyetemen, eredetileg fordító író eszközként fejlesztették ki. Számos fordítót implementáltak, Richards könyve betekintést nyújt a nyelvbe és annak fordítójára. A BCPL nemcsak befolyásos rendszerprogramozási nyelv volt, amelyet továbbra is használnak a kutatásban, hanem alapot adott a B és a C nyelv megtervezéséhez is.

A BLISS-t (alapvető nyelv a rendszerszoftverek megvalósításához) a Digital Equipment Corporation (DEC) PDP-10 számítógép számára fejlesztették ki W. A. Wulf Carnegie Mellon Egyetem (CMU) kutatócsoportja. A CMU csapata egy évvel később, 1970-ben fejlesztette ki a BLISS-11 fordítót.

A Multics (Multiplexed Information and Computing Service), idő-megosztó operációs rendszer projekt, bevonta az MIT-t, a Bell Labs-t, a General Electric-t (később Honeywell), és Fernando Corbató vezette az MIT-ből. A Multics az IBM és az IBM User Group által kifejlesztett PL / I nyelven készült. Az IBM célja az üzleti, tudományos és rendszerprogramozási követelmények teljesítése volt. Vannak más nyelvek is, amelyeket figyelembe lehetett volna venni, de a PL / én a legteljesebb megoldást kínálta, annak ellenére, hogy még nem implementálták.A Multics projekt első néhány évében a nyelv egy részét lefordították assembly nyelvre az Early PL / I (EPL) fordítóval, Doug McIlroy és Bob Morris segítségével, a Bell Labs-tól.Az EPL addig támogatta a projektet, amíg a teljes PL / I számára nem sikerült elindítani egy boot-pántozó fordítót.

A Bell Labs 1969-ben kiszállt a Multics projektből: "Az idő múlásával a reményt frusztráció váltotta fel, mivel a csoport erőfeszítései kezdetben nem tudtak gazdaságilag hasznos rendszert előállítani."A további részvétel növelte volna a projekt támogatási költségeit. A kutatók tehát más fejlesztési lehetőségekhez fordultak.

A BCPL koncepciókon alapuló B rendszerprogramozási nyelvet Dennis Ritchie és Ken Thompson írta. Ritchie létrehozott egy rendszerindító-heveder-fordítót a B-hez, és megírta az Unics (Uniplexed Information and Computing Service) operációs rendszert a PDP-7-hez. Az Unics végül Unix-ként maradt fent.

A Bell Labs megkezdte a C egyik kiterjesztésének a fejlesztését és bővítését a B és a BCPL alapján. A BCPL-fordítót a Bell Labs szállította a Multics-ba, és a BCPL volt a preferált nyelv a Bell Labs-ben. Kezdetben a Bell Labs B fordítójának front end-programját használták, míg a C fordítót kifejlesztették.1971-ben egy új PDP-11 biztosította az erőforrást a B kiterjesztések meghatározásához és a fordító újraírásához.1973-ra a C nyelv tervezése alapvetően kész volt, és a PDP-11 Unix kernelét C-ben átírták. Steve Johnson elindította a Portable C Compiler (PCC) fejlesztését, hogy támogassa a C fordítókészülékek regenerálását az új gépekre.

Az objektum-orientált programozás (OOP) érdekes lehetőségeket kínál az alkalmazás fejlesztéséhez és karbantartásához. Az OOP-koncepciók visszamenőleg visszatérnek, de a LISP és a szimuláció nyelvtudományának részét képezték. A Bell Labs-nél a C++ fejlesztők érdeklődését felkeltette az OOP. A C++ -ot először 1980-ban használták a rendszerek programozáshoz. Az eredeti kialakítás kihasználta a C nyelvi rendszerek programozási képességeit a Simula koncepciókkal. Az Objektum-orientált lehetőségeket 1983-ban adtak hozzá. A Cfront program C++ kezelőfelületet valósított meg a C84 nyelvi fordítójára. A következő években több C++ fordítót fejlesztettek ki, ahogy a C++ népszerűsége növekedett.

Sok alkalmazási tartományban gyorsan felmerült egy magasabb szintű nyelv használatának gondolata. Az újabb programozási nyelvek által támogatott bővülő funkcionalitás és a számítógépes architektúrák növekvő bonyolultsága miatt a fordítók bonyolultabbá váltak.

A DARPA (Védelmi Fejlett Kutatási Projektek Ügynöksége) 1970-ben szponzorálta a Wulf CMU kutatócsoportjának fordítóprojektjét. A termelésminőség-fordító-fordító PQCC-tervezésével a forrásnyelv és a cél formális meghatározásaiból előállítanák a termelési minőség-fordítót (PQC). A PQCC megpróbálta kibővíteni a fordító-fordító kifejezést a hagyományos jelentéseken túl, mint értelmező generátor (például Yacc) nagy siker nélkül. A PQCC-t helyesebben fordítógenerátornak lehetne hivatkozni.

A PQCC kutatása a kódgenerációs folyamatban valóban automatikus fordító-író rendszer felépítését tűzte ki célul.Az erőfeszítés során felfedezték és megtervezték a PQC fázisszerkezetét. A BLISS-11 fordító biztosította a kezdeti struktúrát. A fázisok tartalmazták az elemzéseket (front end), a közbenső fordítást a virtuális gépre (middle end) és a célba történő fordítást (back end). A TCOL-t a PQCC kutatáshoz fejlesztették ki, hogy kezelje a nyelvspecifikus konstrukciókat a közbenső ábrázolásban. A TCOL változatai támogatnak különböző nyelveket.A PQCC projekt az automatizált fordítókészítés technikáit vizsgálta.A tervezési koncepciók hasznosnak bizonyultak az Ada objektum-orientált programozási nyelvének és fordítóinak optimalizálásában.

Az Ada Stoneman dokumentum formalizálta a program-támogatási környezetet (APSE) a kerneltel (KAPSE) és a minimállal (MAPSE) együtt. Az Ada tolmács, a NYU / ED támogatta a fejlesztési és szabványosítási erőfeszítéseket az Amerikai Nemzeti Szabványügyi Intézettel (ANSI) és a Nemzetközi Szabványügyi Szervezettel (ISO). Az Ada katonai szolgálatának az USA katonai szolgálat általi kezdeti fejlesztése a Stoneman dokumentum mentén teljes integrált tervezési környezetbe foglalta a fordítókat. A hadsereg és a haditengerészet az Ada Language System (ALS) projekten dolgozott, amely a DEC / VAX architektúrára irányult, miközben a légierő az Ada Integrált Környezetben (AIE) indult az IBM 370 sorozat számára. Noha a projektek nem adták meg a kívánt eredményeket, hozzá járult az Ada fejlődésének általános hatásához.

Egyéb Ada-fordító kutatások kezdődtek Nagy-Britanniában a York-i Egyetemen és Németországban a Karlsruhe-i Egyetemen. Az Egyesült Államokban a Verdix (amelyet később a Rational vásárolt meg) szállította a Verdix Ada Fejlesztő Rendszert (VADS) a hadseregnek. A VADS egy sor fejlesztési eszközt biztosított, beleértve egy fordítót is.Az Unix / VADS különféle Unix platformon is elhelyezhető, mint például a DEC Ultrix vagy a Sun 3/60 Solaris, melyet a Motorola 68020-ra céloztak meg a hadsereg CECOM kiértékelése során. Hamarosan sok Ada-fordító állt rendelkezésre, amelyek teljesítették az Ada-érvényesítési teszteket. A Free Software Foundation GNU projekt kifejlesztette a GNU Compiler Collection (GCC) alkalmazást, amely alapvető képességet biztosít több nyelv és cél támogatására. Az Ada verziós GNAT az egyik legszélesebb körben használt Ada fordító. A GNAT ingyenes, de van kereskedelmi támogatás is, például az AdaCore-t 1994-ben alapították, hogy az Ada számára kereskedelmi szoftvermegoldásokat biztosítson. A GNAT Pro tartalmazza a GNU GCC alapú GNAT-ot egy eszközkészlettel, amely integrált fejlesztési környezetet biztosít.

A magas szintű nyelvek továbbra is elősegítették az összeállítók kutatását és fejlesztését. A fókuszterületek közé tartozik az optimalizálás és az automatikus kódgenerálás. A programozási nyelvek és a fejlesztési környezetek tendenciái befolyásolták a fordító technológiát.További fordítókat beillesztettek a nyelvi disztribúciókba (PERL, Java Development Kit) és az IDE alkotóelemeként (VADS, Eclipse, Ada Pro). Növekedett a technológiák kölcsönös kapcsolata és kölcsönös függősége. A webszolgáltatások megjelenése elősegítette a webnyelvek és a szkriptnyelvek növekedését. A parancsfájlok visszavezetik a parancssori felületek (CLI) kezdeti napjait, ahol a felhasználó megadhatott parancsokat, amelyeket a rendszer végrehajt. A felhasználói héj-koncepciók a nyelvekkel fejlesztettek ki shell programok létrehozására. A korai Windows tervek egyszerű batch programozási lehetőséget kínáltak. E nyelv hagyományos átalakítása értelmezőt használt. A Bash és a Batch fordítókat nem használták széles körben. Az utóbbi időben a kifinomult értelmezett nyelvek a fejlesztői eszközkészlet részévé váltak. A modern szkriptnyelvek közé tartozik a PHP, a Python, a Ruby és a Lua. (A Lua-t széles körben használják a játékfejlesztésben.) Mindegyik rendelkezik tolmács- és fordítói támogatással.

"Amikor az összeállítás területe az 50-es évek végén megkezdődött, a hangsúly a magas szintű nyelvi programok gépi kódra fordítására korlátozódott ...A fordító területe egyre inkább összefonódik más tudományágakkal, beleértve a számítógépes architektúrát, a programozási nyelveket, a formális módszereket, a szoftverfejlesztést és a számítógépes biztonságot. "A "Compiler Research: The Next 50 Year" cikk kiemelte az objektum-orientált nyelvek és a Java fontosságát. A biztonságot és a párhuzamos számítástechnikát megemlítették a jövőbeli kutatási célok között.

Az 1990-es évek során nagy számban jelentek meg szabad fordítóprogramok a GNU projekt és a nyílt forráskód mozgalomban. Sok közülük nagyon jó minőségű.

TípusokSzerkesztés

A fordítók egyik osztályozása az alapján történik, hogy a generált kódot melyik platformon szeretnénk végrehajtani. Ezt célplatformnak nevezik.

A natív vagy hosztolt fordító az amelynek kimenete közvetlenül ugyanazon a számítógépen és operációs rendszeren fut le, mint amin a fordító maga fut. A keresztirányú fordító kimenetét más platformon történő futtatásra tervezték. A keresztirányú fordítót gyakran olyan beágyazott rendszerekhez való szoftver fejlesztésekor használják, ahol ami nem támogatja magát a fejlesztési környezetet.

Azokat a fordítókat, amik egy virtuális gépnek (VM) állítanak elő futtatható kódot, nem szokták a natív vagy keresztirányú fordítók közé besorolni.

Habár az átlagos fordítók gépi kódra fordítják a forrás kódot, sok, ettől különböző fordító létezik:

  • Forrásból-forrásba (source-to-source) fordítók olyan típusú fordítók, amik forrásnyelve és célnyelve egyaránt magas szintű programozási nyelv.
  • A Bytecode fordítók egy elméleti gép assembly kódjára fordítják a forrásnyelvet, mint pl. néhány Prolog implementáció
    • Ez a Prolog gép WAM-ként ismert
    • A Java és a Python bytcode fordítói is ide tartoznak
  • A futásidejű fordítás (Just-in-Time vagy JIT compiler) a bájtkódot a futási időben fordítja natív kódra. Sok különböző modern programozási nyelv is Ilyen fordítót használ pl. Java, Python, JavaScript, Microsoft .NET CLI. A JIT fordító egy interpreter belsejében fut. Amikor az interpreter érzékeli, hogy a kód útvonala "forró", azaz nemrég futtatott, a "felébreszti" a JIT fordítót ami aztán elvégzi a fordítást ezzel növelve a teljesítményt.
  • Hardveres fordítók (hardware compiler, syntheses tools) kimenete utasítások sorozata helyett a hardver konfigurációja.
  • Az assembler egy olyan program amely az ember által olvasható assembly nyelvet fordítja gépi kódra, amik a hardver által ténylegesen értelmezett utasítások.
  • Az a program ami alacsony szintű nyelvről fordít magasabb szintű nyelvre decompilernek nevezik.
  • A fordító ami magas szintű nyelvről fordít egy másik magas szintű nyelvre fordítónak (translator), source-to-source compilernek vagy nyelv újraírónak (rewriter) nevezik.
  • Egy olyan programot, amely egy olyan objektumkód formátummá fordít, amelyet a fordítógép nem támogat, keresztirányú (cross-compiler) fordítónak nevezünk.
  • Azt a programot, ami egy objektumkódot ugyanolyan objektumkóddá alakít optimalizációk és átalakítások közben, binary compilernek nevezzük.

Kapcsolódó szócikkekSzerkesztés

ForrásokSzerkesztés

További információkSzerkesztés