Ағылшыншамен салыстырыңыз: абзацты басыңыз — түпнұсқа терезеде ашылады. Абзац астындағы EN түймесі оны мәтін ішінде көрсетеді.
Мазмұны
Кіріспе
Компьютерлік бағдарламалауда бір реттік өтетін компилятор — әрбір компиляциялық бөліктің элементтерін бір ғана рет қарап өтіп, әрбір элементті тікелей түпкілікті машиналық кодқа аударатын компилятор. Бұл, бағдарламаны бастапқы кодтан машиналық кодқа дейінгі аралық кезеңдерде бір немесе бірнеше аралық түрлерге түрлендіретін және әрбір кезеңде компиляциялық бөліктің барлығын қайта өңдейтін көп реттік өтетін компилятордан өзгеше. Бұл компилятордың логикалық жұмыс істеу қағидасын көрсетеді, бастапқы файлды бір рет оқуды емес. Мысалы, бастапқы файл бір рет уақытша жадқа оқылып, содан кейін сол көшірмесі бірнеше рет қаралуы мүмкін. IBM 1130 Fortran компиляторы бастапқы кодты жадында сақтап, көп рет өңдеуді қолданды; ал диск жеке жады болмаған жүйелерде ассемблерге бастапқы кодты карта оқырманға/перфораторға екі рет беру қажет болды.
In computer programming, a one pass compiler is a compiler that passes through the parts of each compilation unit only once, immediately translating each part into its final machine code. This is in contrast to a multi pass compiler which converts the program into one or more intermediate representations in steps between source code and machine code, and which reprocesses the entire compilation unit in each sequential pass. This refers to the logical functioning of the compiler, not to the actual reading of the source file once only. For instance, the source file could be read once into temporary storage but that copy could then be scanned many times. The IBM 1130 Fortran compiler stored the source in memory and used many passes; by contrast the assembler, on systems lacking a disc storage unit, required that the source deck of cards be presented twice to the card reader/punch.
Қасиеттері
Бір өтетін компиляторлар көп өтетін компиляторлардан кішідірек және жылдамырақ. Бір өтетін компиляторлар қолда бар ақпараттың шектеулі көлеміне байланысты көп өтетін компиляторлар сияқты тиімді бағдарламаларды жасауға қабілетсіз. Көптеген тиімді компиляторлық оңтайландырулар негізгі блок, цикл (әсіресе ішкі циклдар), кіші бағдарлама немесе бүкіл модуль бойынша бірнеше рет өтуді қажет етеді. Кейбіреулері бүкіл бағдарлама бойынша өтуді талап етеді. Кейбір бағдарламалау тілдерін олардың құрылымына байланысты бір рет өтетін компилятормен құрастыру мүмкін емес. Мысалы, PL/I бағдарламаның кез келген жерінде, тіпті әлі жарияланбаған элементтерге сілтеме жасалғаннан кейін деректерді жариялауға рұқсат береді, сондықтан бүкіл бағдарлама тексерілгенше код жасау мүмкін емес. Тілдің анықтамасы құрастырылатын бастапқы кодты жасайтын алдын ала процессор операторларын да қамтиды: бірнеше өтулер міндетті. Керісінше, көптеген бағдарламалау тілдері бір өтетін компиляторлармен құрастыру үшін арнайы жасалған және бір өтетін компиляцияға мүмкіндік беретін арнайы құрылымдарды қамтиды.
One pass compilers are smaller and faster than multi pass compilers. One pass compilers are unable to generate as efficient programs as multi pass compilers due to the limited scope of available information. Many effective compiler optimizations require multiple passes over a basic block, loop (especially nested loops), subroutine, or entire module. Some require passes over an entire program. Some programming languages simply cannot be compiled in a single pass, as a result of their design. For example PL/I allows data declarations to be placed anywhere within a program, specifically, after some references to the not yet declared items, so no code can be generated until the entire program has been scanned. The language definition also includes pre processor statements that generate source code to be compiled: multiple passes are certain. In contrast, many programming languages have been designed specifically to be compiled with one pass compilers, and include special constructs to allow one pass compilation.
Қиындықтар
Негізгі мәселе – алға сілтемелер жасау. Көздік файлдың бір бөлігіндегі символдың дұрыс түсіндірілуі, файлда одан кейін келетін басқа символдардың болуына немесе болмауына байланысты болуы мүмкін. Олар кездеспейінше, ағымдағы символ үшін дұрыс код жасалмайды. Бұл контекстке тәуелділік мәселесі, ал оның ауқымы жақын орналасқан символдардан бастап, көздік мәтіннің кез келген үлкен көлеміне дейін жете алады.
The basic problem is of forward references. The correct interpretation of a symbol at some point in the source file may be dependent on the presence or absence of other symbols further on in the source file and until they are encountered, correct code for the current symbol cannot be produced. This is the problem of context dependence, and the span can be anywhere from adjacent symbols to arbitrarily large amounts of source text.
Жергілікті жағдай
Болжам жасайық, < символы "кемде" салыстыру үшін танылады, мысалы, "көпте" салыстыруға қарама-қарсы. Таңба кодтау шектеулеріне байланысты, ≤ глифі стандартты кодтауда қолжетімді болмауы мүмкін, сондықтан "<=" құрамалы бейнелеуге рұқсат етіледі. Бұл контекст келесі символмен анықталғанымен, "<" кездескен кезде ол белгісіз болады. Сол сияқты, "=" символы әрқашан "=" дегенді білдірмейді, мысалы, ол құрамалы символдың бөлігі болғанда. Басқа құрамалы символдарға "<" арнайы символы қолжетімді болмаған жағдайда ".lt." кіруі мүмкін. Глиф ¬ ("жоқ") таңбасының коды қолжетімсіз болған жағдайда, "<>" "¬=" немесе "тең емес" үшін тағы бір мүмкіндік бар. Кейбір жүйелер ¬ үшін ~ немесе ! символдарын да қолданады. Бір тәсіл – "<" символынан кейін сканерлеуді алға жылжыту, ал "=" символына тап болғанда кері қайту. Бұл, әрине, мәтіннің осы бөлігін екі рет қарауды білдіреді, одан аулақ болу керек. Мұндай жағдайда, бастапқы файл карта оқу құрылғысы сияқты кері оқуды қолдамайтын құрылғыдан алынуы мүмкін. Ертерек шешім қабылдаудың орнына, кейіннен жойылған болуы мүмкін, лексикалық талдаушы кванттық суперпозиция ұғымына ұқсас бірнеше интерпретацияларды сақтай алады, содан кейін анықтайтын символ байқалғанда ғана нақты таңдауға келеді. Мысалы, COBOL компиляторлары ондық тұрақтылардағы және жазбалардың соңындағы нүктелерді ажырату үшін бір өтеді. Мұндай схема бір өтімді компиляторда қолжетімді емес. Атаулар да осыған ұқсас. Көптеген тілдер өздерін бір таңбалы атаулармен шектемейді, сондықтан "x" таңбасы бір таңбалы атау ретінде "текст" сияқты атаудағы "x" таңбасынан өте өзгеше, енді контекст тікелей жапсарлас таңбалардан асып түседі. Лексикалық талдаушының міндеті – тілдің белгілеріне бірізділікпен берілген бастапқы ағынның элементтерін бөлу. Бұл тек сөздер ғана емес, өйткені "<" және "<=" де белгілер болып табылады. Атаулар әдетте әріппен басталады және әріптермен, сандармен және " " сияқты бірнеше қосымша символдармен жалғасады. Сандарды көрсетуге рұқсат етілген синтаксис таңқаларлықтай күрделі, мысалы, +3.14159E+0 жарамды болуы мүмкін. Токендер арасында кез келген сандағы бос орынға рұқсат ету әдеттегідей, ал Фортран белгілі бір токендер ішіндегі бос орындарға рұқсат беруде (және елемеуде) ерекше, сондықтан "GO TO" және "GOTO" "<=" және "< =" сияқты эквивалентті. Алайда, кейбір жүйелер белгілі бір токендерді шектеу үшін бос орындарды талап етуі мүмкін, ал басқалары, мысалы Python, бағдарлама блоктарының аясын көрсету үшін жетекші бос орындарды қолданады, олар әдетте Бастау және Аяқтау немесе ұқсас маркерлермен көрсетіледі.
Suppose that the symbol < is recognized as being for a "less than" comparison, as opposed to "greater than" for example. Because of character coding limitations, the glyph ≤ may not be available in a standard encoding, so a compound representation is to be allowed, "<=". Even though this context is determined by the very next symbol, it is unknown when "<" is encountered. Similarly, the symbol "=" does not always mean "=", as when it is a part of a compound symbol. Other compound symbols might include ". lt." for the case when the special character "<" is unavailable. Yet another possibility where a character code for the glyph ¬ ("not") is unavailable is "<>" for "¬=" or "not equal" some systems employ ~ or ! for ¬ as still further variation. One approach is to advance the scan after "<" and on encountering the "=", backtrack. This of course means that there will be two passes over that portion of text, which is to be avoided. For that matter, the source file may come from a device not supporting a go back and reread operation, such as a card reader. Instead of making an early decision that may later have to be undone, the lexical analyser can maintain multiple interpretations rather like the notion of Quantum Superposition, collapsing to a specific choice only on later observing the determining symbol. Notably, COBOL compilers devote a pass to distinguishing between full stops appearing in decimal constants and the full stops that appear at the end of statements. Such a scheme is unavailable to a single pass compiler. Similarly with the names of items. Few languages restrict themselves to single character names, so the character "x" as a single character name is quite different from the character "x" within a name such as "text" now the context extends beyond the immediately adjacent characters. It is the task of the lexical analyser to separate the items of the sequential source stream into the tokens of the language. Not just words, because "<" and "<=" are tokens also. Names typically start with a letter and continue with letters and digits, and perhaps a few additional symbols such as " ". The syntax allowed for specifying numbers is surprisingly complex, for example +3.14159E+0 can be valid. It is usual to allow an arbitrary number of space characters between tokens, and Fortran is unusual in allowing (and ignoring) spaces within apparent tokens also so that "GO TO" and "GOTO" are equivalent as are "<=" and "< =". However, some systems may require spaces to delimit certain tokens, and others, such as Python, use leading spaces to indicate the scope of program blocks that otherwise might be indicated by Begin End or similar markers.
Өкінішті шешімдер
Жоғарыда сипатталғандай, кейбір өрістері кейінірек түзетілуі мүмкін екендігі ескеріліп код жасалғанмен, мұндай код тізбектерінің көлемі тұрақты деген тұжырым жасалды. Бірақ бұл әрқашан дұрыс болмайды. Көптеген компьютерлерде әртүрлі көлемде жадты пайдаланатын операциялар қарастырылған, әсіресе салыстырмалы адрестеу. Мысалы, егер мақсат 128 немесе +127 адрестеу қадамының ішінде болса, сегіз биттік адрестік өріс қолданылуы мүмкін, әйтпесе, оған жету үшін әлдеқайда үлкен адрестік өріс қажет болады. Осылайша, егер код қысқа адрестік өріспен жасалса, кейіннен оны қайта қарап, ұзын өріс қолдану үшін түзету қажет болуы мүмкін. Нәтижесінде, өзгертілгеннен кейін бұрынғы кодтағы сілтемелерді де түзету қажет болады. Сол сияқты, өзгеріске қатысты кері сілтемелерді де, тіпті белгілі адрестерге жасалған сілтемелерді де түзету керек. Сонымен қатар, түзету туралы ақпараттың өзі дұрыс түзетілуі тиіс. Басқа жағынан, жақындық нақты болмаған жағдайларда ұзын адрестерді пайдалануға болады, бірақ мұндай код енді тиімді болмайды.
Although the description above has employed the notion that code may be generated with certain fields left to be fixed up later, there was an implicit assumption that the size of such code sequences was stable. This may not be the case. Many computers have provision for operations occupying different amounts of storage, notably relative addressing whereby if the destination is within say 128 or +127 addressing steps then an eight bit address field can be used, otherwise a much larger address field is required to reach. Thus if the code were generated with a hopeful short address field, later it may become necessary to go back and adjust the code to use a longer field, with the consequence that earlier code referencing locations after the change will have to be adjusted as well. Likewise, later references going backwards across the change will have to be fixed, even those that had been to known addresses. And as well, the fixup information will itself have to be fixed, correctly. On the other hand, long addresses could be used for all cases when nearness is not certain, but the resulting code will no longer be ideal.
Бір рет өткізілетін ретті кіріс, реттіліксіз шығыс
Бір ғана мәлімдемедегі оптимизациялау мүмкіндіктерінің кейбірі айтылды. Бірнеше мәлімдемелер бойынша оптимизациялау үшін, мұндай мәлімдемелердің мазмұны кодты шығару алдында талданып, өңделуі мүмкін дерек құрылымында сақталуын қажет етеді. Мұндай жағдайда, түзетулерге рұқсат етілгенімен, уақытша кодты жасау кедергі келтіреді. Шегінде, компилятор бүкіл бағдарламаны ішкі форматта бейнелейтін дерек құрылымын жасайды, бірақ бастапқы файлды басынан соңына дейін толық қараудың қажеті жоқ деген пікірді айтуға болады. Бұл мүмкіндік компиляторды жариялайтын PR құжатында көрсетілуі мүмкін. Сондықтан, компилятор өзінің кодын бір қадаммен, тіпті бастапқы кодтың әр бөлігі оқылған бойда жасауға қабілетсіз. Шығыс деректер тізбектей жазылуы мүмкін, бірақ тек егер бөлімнің шығысы сол бөлімге қатысты барлық күтіліп тұрған түзетулер аяқталғаннан кейін ғана шығарылса.
Already mentioned are some possibilities for optimisation within a single statement. Optimisations across multiple statements would require that the content of such statements be held in some sort of data structure that could be analysed and manipulated before code is emitted. In such a case, producing provisional code, even with fixups allowed for, would be a hindrance. In the limit this means the compiler would generate a data structure representing the entire program in an internal form, but a straw could be clutched and the claim made that there is no actual second pass of the source file from start to end. Possibly in the PR document advertising the compiler. Notably therefore, a compiler cannot generate its code in a single relentlessly forwards sequence, still less immediately as each part of the source is read. The output could still be written sequentially, but only if output of a section is deferred until all pending fixups for that section have been made.
Рәсімдер мен функциялар
Пайдалану алдындағы декларация процедуралар мен функцияларды орындау үшін де оңай талап болып табылады, бұл процедуралар ішінде процедураларды орналастыруға да қатысты. ALGOL, Pascal, PL/I және басқалары сияқты, MATLAB және (1995 жылдан бастап) Fortran функцияға (немесе процедураға) басқа функцияның (немесе процедураның) анықтамасын қамтуға мүмкіндік береді, бірақ бұл жүйелер оларды қамтитын функция ішінде ғана көрінетін, бірақ оларды қамтитын процедура аяқталғаннан кейін анықтауға болады. Бірақ рекурсияға рұқсат берілгенде, мәселе туындайды. Әрқайсысы екіншісін шақыратын екі процедураны пайдалану алдында екеуі де жариялауға болмайды. Біріншіден, бастапқы файлда бірінші болу керек. Бұл маңызды емес, егер, белгісіз айнымалымен кездескен кезде, кездескеннен жеткілікті түрде компилятор белгісіз процедураны шақыру үшін қолайлы кодты шығара алса, әрине, "жөндеу" аппаратымен, процедураның анықтамасы кездескен кезде қайта оралып, дұрыс мекенжайды толтыру үшін. Бұл, мысалы, параметрлері жоқ процедура үшін орын алады. Функцияны шақырудан қайтарылған нәтиже шақырудан ажыратылатын типте болуы мүмкін, бірақ бұл әрқашан дұрыс болмауы мүмкін: функция жылжымалы нүкте нәтижесін қайтара алады, бірақ оның мәні бүтін санға беріледі. Pascal бұл мәселені "алдын ала жариялауды" талап ету арқылы шешеді. Процедураның немесе функцияның бір декларациясы бірінші берілуі тиіс, бірақ процедураның немесе функцияның денесі орнына "forward" кілт сөзін беру керек. Содан кейін басқа процедура немесе функция жарияланып, оның құрамын анықтауға болады. Кейбір кезде "forward" процедура немесе функция функцияның денесімен бірге қайта жарияланады. Параметрлері бар процедураны (немесе функцияны) шақыру үшін олардың түрі белгілі болады (олар пайдалану алдында жарияланады), бірақ олардың процедураны шақырудағы қолданылуы болмауы мүмкін. Мысалы, Fortran барлық параметрлерді сілтеме арқылы (яғни мекенжай бойынша) береді, сондықтан кодты жасаудың бірден қиындығы жоқ (әрқашанғыдай, нақты мекенжайлар кейіннен түзетіледі), бірақ Pascal және басқа тілдер бағдарламашының таңдауы бойынша параметрлерді әр түрлі әдістермен беруге мүмкіндік береді (сілтеме арқылы, немесе мәні бойынша, тіпті "атымен") және бұл тек процедураның анықтамасымен белгіленеді, ол анықтаманы кездестіргенге дейін белгісіз. Паскаль үшін, параметрлер спецификациясында "Var" префиксі оны сілтеме арқылы қабылдауға тиіс екенін білдіреді, оның болмауы мәні арқылы білдіреді. Бірінші жағдайда компилятор параметрдің мекенжайын беретін кодты, ал екіншісінде әртүрлі кодты, әдетте стек арқылы, мәннің көшірмесін беретін кодты құруы керек. Әдеттегідей, "жөндеу" механизмін қолдануға болады, бірақ ол өте күрделі болады. Көп жолды компиляторлар, әрине, барлық қажетті ақпаратты алға-артқа ауыстыра алады, бірақ бір жолды компиляторлар жасай алмайды. Кодты жасауды сканерлеу алға жылжу кезінде тоқтату мүмкін (және оның нәтижелері ішкі сақтауда сақталады) қажетті нысан кездескенше, және бұл кодты жасау сатысы жақын арада жететіндіктен, бастапқыдан екінші рет өту деп қарастырылмайды, ол тек біраз уақыт тоқтап тұрды. Бірақ бұл күрделі мәселе. Оның орнына арнайы конструкция енгізіледі, ол арқылы параметрді пайдаланудың процедураның анықтамасы оның кейінгі толық анықтамасынан "алдыңғы" деп жарияланады, сондықтан компилятор оны пайдаланудан бұрын, қажет болған жағдайда, білуі мүмкін. Бірінші Fortranнан (1957) бастап бағдарламаның бөліктерін бөлек құрастыру мүмкін болды, бұл процедуралар мен функциялардың кітапханаларын құруды қолдайды. Компиляцияланатын бастапқы файлдағы функцияларды шақыратын процедураға белгілі емес функция қайтарған нәтиже түрін білуі керек, егер тек нәтижеді табу үшін дұрыс орынға қарайтын кодты жасау үшін. Бастапқыда, тек бүтін сандар мен жылжымалы нүктелі айнымалылар болған кезде, таңдау жасырын декларациялау ережелеріне қалдырылуы мүмкін еді, бірақ өлшемдер мен типтердің көбеюімен шақыру процедурасына функция үшін типтік декларация қажет болады. Бұл ерекше емес, процедураның ішінде мәлімделген айнымалыға ұқсас нысанда. Бір жолды құрастырудың қазіргі кезеңінде бір нысан туралы ақпарат қажет, сондықтан ол үшін дұрыс кодты қазір, егер кейіннен адресді түзетумен жасалса, қажет. Қажетті ақпарат бастапқы файлда немесе жеке жинақталған код файлында кездеседі ме, жоқ па, ақпаратты қандай да бір протокол ұсынады. Процедураның (немесе функцияның) барлық шақырулары бір-бірімен үйлесімділік үшін тексеріледі ме, жоқ па, бұл бөлек мәселе. Algol-дан шыққан тілдерде бұл тексеру әдетте қатаң болады, бірақ басқа жүйелер бейжай болуы мүмкін. Параметрлердің саны мен түріндегі қателер әдетте бағдарламаны құлатуға әкеледі, опциялық параметрлері бар процедураларды есепке алмайынша. Бағдарламаның бөліктерін бөлек құрастыруға рұқсат беретін және кейін "байланыстырылатын" жүйелер параметрлер мен нәтижелердің дұрыс түрін және санын да тексеруі керек, өйткені қателер жасау оңайрақ, бірақ көбінесе жасалмайды. Кейбір тілдер (мысалы, Algol) "жаңарту" немесе "кеңейту" немесе "көтеру" деген формальды ұғымға ие, онда процедура, мысалы, қос нақтылық параметрін күтетін болса, оны бір нақтылық айнымалысымен шақырылуы мүмкін, және бұл жағдайда компилятор бір нақтылық айнымалысын уақытша қос нақтылық айнымалысына сақтайтын кодты жасайды, ол нақты параметр болады. Дегенмен, бұл параметрді беру механизмін көшіруге және шығаруға өзгертеді, бұл нәтижесінде мінез-құлқының айқын айырмашылықтарына әкелуі мүмкін. Тәжірибесіздікке айналатын нәрсе - процедура бір нақтылық айнымалысының мекенжайын алатын кезде, ол қос нақтылық параметрін күтеді, немесе басқа өлшемдердегі өзгерістер. Процедураның ішінде параметрдің мәні оқылғанда, оның берілген параметрінен гөрі көбірек сақтау оқылады және нәтижесіндегі мән жақсартуға ұқсамайды. Жағдай одан да нашар, егер процедура өзінің параметрінің мәнін өзгертетін болса: бірдеңе зардап шегеді. Бұл қателерді табу және түзету үшін көп шыдамдылық жұмсалуы мүмкін.
Declaration before use is likewise an easy requirement to meet for procedures and functions, and this applies also to the nesting of procedures within procedures. As with ALGOL, Pascal, PL/I and many others, MATLAB and (since 1995) Fortran allow a function (or procedure) to contain the definition of another function (or procedure), visible only within the containing function, but these systems require that they be defined after the end of the containing procedure. But when recursion is allowed, a problem arises. Two procedures, each invoking the other, cannot both be declared before usage. One must be first in the source file. This need not matter if, as on the encounter with an unknown variable, sufficient can be deduced from the encounter that the compiler could generate suitable code for the invocation of the unknown procedure, with of course the "fixup" apparatus in place to come back and fill in the correct address for the destination when the procedure's definition is encountered. This would be the case for a procedure with no parameters, for example. The returned result from a function invocation may be of a type discernable from the invocation, but this may not always be correct: a function could return a floating point result but have its value assigned to an integer. Pascal solves this problem by requiring "predeclaration." One of the procedure or function declarations must be given first, but, instead of the body of the procedure or function, the keyword forward is given. Then the other procedure or function can be declared and its body defined. At some point the "forward" procedure or function is redeclared, along with the body of the function. For the invocation of a procedure (or function) with parameters, their type will be known (they being declared before use) but their usage in the procedure invocation may not be. Fortran for example passes all parameters by reference (i. e. by address) so there is no immediate difficulty with generating the code (as always, with actual addresses to be fixed up later), but Pascal and other languages allow parameters to be passed by different methods at the programmer's choice (by reference, or by value, or even perhaps by "name") and this is signified only in the definition of the procedure, which is unknown before the definition has been encountered. Specifically for Pascal, in the specification of parameters a prefix "Var" signifies that it must be received by reference, its absence signifies by value. In the first case the compiler must generate code that passes the address of the parameter, while in the second it must generate different code that passes a copy of the value, usually via a stack. As always, a "fixup" mechanism could be invoked to deal with this, but it would be very messy. Multi pass compilers can of course collate all the required information as they shuttle back and forth, but single pass compilers cannot. Code generation could be paused while the scan advances (and its results be held in internal storage) until such time as the needed entity is encountered, and this might not be regarded as resulting in a second pass through the source because the code generation stage will soon catch up, it was merely halting for a while. But this would be complex. Instead a special construction is introduced, whereby the procedure's definition of parameter usage is declared "forward" of its later full definition so that the compiler may know it before use, as it requires. From First Fortran (1957) onwards, separate compilation of portions of a program has been possible, supporting the creation of libraries of procedures and functions. A procedure in the source file being compiled that invokes a function from such an outside collection must know the type of result returned by the unknown function, if only to generate code that looks in the right place to find the result. Originally, when there were only integers and floating point variables, the choice could be left to the rules for implicit declaration, but with the proliferation of sizes and also types the invoking procedure will need a type declaration for the function. This is not special, having the same form as for a variable declared inside the procedure. The requirement to be met is that at the current point in a single pass compilation, information on an entity is needed so that the correct code for it can be produced now, if with address fixups later. Whether the required information will be encountered later on in the source file or is to be found in some separately compiled code file, the information is provided by some protocol here. Whether or not all invocations of a procedure (or function) are checked for compatibility with each other and their definitions is a separate matter. In languages descended from Algol like inspiration, this checking is usually rigorous, but other systems can be indifferent. Leaving aside systems that allow a procedure to have optional parameters, mistakes in the number and type of parameters will normally cause a program to crash. Systems that allow separate compilation of parts of a complete programme that later are "linked" together should also check for the correct type and number of parameters and results as mistakes are even easier to make, but often do not. Some languages (such as Algol) have a formal notion of "upgrading" or "widening" or "promotion", whereby a procedure that expects say a double precision parameter may be invoked with it as a single precision variable, and in this case the compiler generates code that stores the single precision variable into a temporary double precision variable which becomes the actual parameter. This however changes the parameter passing mechanism to copy in, copy out which may lead to subtle differences in behaviour. Far less subtle are the consequences when a procedure receives the address of a single precision variable when it expects a double precision parameter, or other size variations. When within the procedure the parameter's value is read, more storage will be read than that of its given parameter and the resulting value is unlikely to be an improvement. Far worse is when the procedure changes the value of its parameter: something is sure to be damaged. Much patience can be expended in finding and correcting these oversights.
Алдын ала өңдеуші рекурсиясы
Күрделі деректер жиынтығын жариялағанда, Odd және Even функцияларын қолдануға мүмкіндік тууы мүмкін. Мысалы, егер деректер жиынтығы X-тің сақталу көлемі байттардың тақ саны болса, Odd(ByteSize(X)) тестінің бақылауымен оған бір байттық элемент қосылып, осылайша жұп санды жасауға болады. Жоғарыда келтірілгендей Odd және Even функцияларының эквивалентті жариялануын ескере отырып, «алдын ала» жариялау қажет болмауы мүмкін, себебі параметрлердің қолданылуы алдын ала процессорға белгілі, ол деректерді сілтеме арқылы немесе мән арқылы берудің мүмкіндігін қарастырмауы тиіс. Дегенмен, осы функцияларды олардың анықтамасынан тыс, бастапқы кодта олардың нақты анықтамасынан кейін ғана шақыруға болады, өйткені шақырудың нәтижесі белгілі болуы керек. Әрине, егер алдын ала процессор бастапқы файлды бірнеше рет өңдесе, бұл басқаша болуы мүмкін.
When declaring complex data aggregates, a possible usage of functions Odd and Even could arise. Perhaps if a data aggregate X has a storage size that is an odd number of bytes, a single byte item might be added to it under the control of a test upon Odd(ByteSize(X)) so as to make an even number. Given the equivalent declarations of Odd and Even as above, a "forward" declaration probably wouldn't be needed because the usage of the parameters is known to the pre processor which is unlikely to present opportunities to choose between by reference and by value. However, there could be no invocations of these functions in the source code (outside their definitions) until after their actual definition, because the result of the invocation is required to be known. Unless of course the pre processor engaged in multiple passes of its source file.
Залал келтіретін деп саналатын алдын ала декларациялар
Кез келген адам, үлкен бағдарламадағы процедуралардың жарияланымдары мен қолданылуының, сондай-ақ оның процедуралар жинағы кітапханаларын пайдалануы арасындағы үйлесімділікті сақтауға тырысқан болса, әсіресе өзгерістерге ұшыраған жағдайда, шақырылған бірақ ағымдағы жинақтауда анықталмаған процедуралар үшін алдын ала жарияланымдарды немесе осыған ұқсас қосымша жарияланымдарды қолдануда қиындыққа тап болар. Әсіресе, әр түрлі бастапқы файлдардағы қашық жерлер арасындағы синхрондылықты сақтау үшін ұқыптылық қажет. Белгілі бір сөзді қолданатын жарияланымдарды табу оңай, бірақ егер пайдалы жарияланымдар қарапайым жарияланымдардан ажыратылмаса, міндет қиынға соғады. Бір реттік жинақтау мақсатынан бас тарту осы қиындықты жойса, көбінесе жылдам жинақтаудың пайдасы жеткіліксіз болып көрінеді.
Anyone who has attempted to maintain coherence amongst the declarations and usages of procedures in a large program and its usage of libraries of routines, especially one undergoing changes, will have struggled over the usage of forward or similar added declarations for procedures invoked but not defined in the current compilation. Maintaining synchrony between widely separated locations especially across different source files requires diligence. Those declarations using the reserved word are easy to find, but if the helpful declarations are not distinguished from ordinary declarations, the task becomes troublesome. The gain of supposedly swifter compilation may seem insufficient when simply abandoning the goal of one pass compilation would remove this imposition.