Thus the turbo-basic compiler functions

(2 parte)
from: http://ch.twi.tudelft.nl/~sidney/atari/turbo basic/compiler internals.html

Here again the P-CODE:

 Number of 41 02 00 00 00 00 fp->intpeek int >fp push number of 40 01 00 00 00 00 movepull ADD fp - > int

In the first step the Optimierer seizes the number "41 02 00 00 00 00 fp->int"together, by converting the value into the Integer representation. From this develops:

 Izahl 200 peek int >fp push number of 40 01 00 00 00 00 movepull ADD fp->int

Note: There are two Fp-Accus, $$D4 to $$D9 and $$EO to $$E5. Integers stand thereby in the processor registers A and Y thereby contain Y the with high order and A the low order byte.

The Optimierer seizes now "Izahl 200 peek"too"lpeek 200"together. The first example became "LDA # < 200:LDY # > 200:JSR PEEK"as code produce and the second example"LDA 200:LDY #0". Now we have thus:

 Ipeek 200 int >fp push number of 40 01 00 00 00 00 movepull ADD fp - > int

Now becomes "push number & movepull ADDS"too"ADD # &"in summary. From it results:

 Ipeek 200 int >fp ADDS # 40 01 00 00 00 00 fp->int

Next the Optimierer notices the consequence "int >fp ADD # & fp->int"and this instruction sequence tries to simplify. Thus one saves later a transformation. Since the number is smaller than 256, this succeeds also.

Now the Optimierer carried its work out. Subsequently, correct machine code is produced.

Out "lpeek 200"develops"LDA 200:LDY #0", "Iadd # 1"becomes too"LDX #1:JSR IADD"(this subroutine reference is necessary, since otherwise also an OVERFLOW could take place; Integer value more largely than 65535!)

That was already everything. To the instruction COLOR becomes still "STA $$C8"attached. Altogether arises thus:

         LDA 200 LDY #0 LDX #1 JSR IADD STA $$C8

Without optimization substantially more program code would be produced, which is many slower still in addition:

         LDA # < Z20O LDY # > Z20O JSR LDOYA JSR FPI?  JSR PEEK JSR IFP JSR PUSH LDA # < Z1 LDY # > Z1 JSR MOVEPULL JSR ADD JSR FPI?  STA $$C8

In addition within the constant range:

 Z200 BYTE $41, $02, $00, $00, $00, $00 Z1 BYTE $40, $01, $00, $00, $00, $00

Through optimization thus much program code can be saved. In relation to a genuine machine code the result looks however still quite extensive. In machine language became "Inc. $$C8", which needs only 2 byte, which resembles causes. In hexadecimals $$C8 corresponds thereby to the decimal value 200. In our example the compiler codes the basic instruction COLOR 1 however optimally, i.e. "LDA #1:STA $$C8".

Optimally compiles

However the compiler can produce for optimal code only in the rarest cases. Finally only the transformation from FP is unnecessary to INT and in reverse and this also only when using constants. With variables this kind of the optimization is not permissible. Already the saving of some bytes is in most cases enough, because for example shop of a variable and the transformation in one are settled instead of two integer values by only one subroutine reference.

Also everything that would be possible, is not optimized. For example computes itself "A=10/3"not in advance, although it would be quite meaningful. But such optimizations the programmer can anticipate if necessary. However such cases are much too rare, than that this would be worthwhile itself here. The longer the compiler, the more briefly the appropriate BASIC programs. There are however some computations, whose optimization is particularly worthwhile itself: "^2"its own, fast routine receives. In the compiler needs "A=B^2"the same time as"A=B*B". It exists likewise a fast exponential routine, which is present already in the mathematics part of the run time library. Thus or similarly all instructions are treated with parameters. If several parameters are present, this naturally buffered becomes.

A further be worth-worth instruction is that POKEInstruction. For example becomes "POKE 16,64"through"LDA #64:STA 16"translates.

With PRINTInstruction are to be considered still the commas. Also INPUT READ GET and LOCATE contain still some problems. A detailed explanation would blow up the framework of this article however.

Separately to treat are all instructions, which affect the linear program sequence. That GOTOInstruction can be translated comparatively simply. First the routine is called, which translates an Integer expression and optimizes (like above); however do not generate it it yet into the final machine code. First only the P-CODE is produced. Then on the basis the P-CODE it is examined whether a number follows. If, becomes JMPInstruction compiles. First only "07 line", from which itself after passport 2 "4C address"results in. If no, the routine for the production of machine code called and "JSR GOTOX"attached. With a computed GOSUB becomes for example either "JSR GOSUBX"or before"Jmp ($07)"- instruction that GOTOInstruction a subroutine reference compiles. This contains then, on the basic stack, the ruecksprungadresse of the instruction increased by three values. It becomes however not simple JSR compiled, since otherwise the number of subroutine levels would be limited by the too small 6502-Stack. Outer ground electrodes must the parameters for those FOR-NEXT ONELoops on this pile to be likewise put down. They occupy in each case 16 byte, so that very fast an OVERFLOW of the 6502-Stack would threaten. This could catastrophic consequences have and the compatibility to the interpreter basic strongly limit. At least the lower half of the page 1 is free, and there are programs, which use more than 10 geschachtelte loops. The time delay by this simulated stack holds itself however within limits.

The compiler uses a similar stack also for the translation of DO-LOOP REPEAT-UNTIL WHILE-TURN and FOR-NEXT ONELoops as well as of the EXITInstruction.

DO the current address on this pile is put down. In addition it receives those DOBefehlskennung. In the case of translation of the associated LOOP becomes the identification thereupon it examines whether DO is missing and then JMPInstruction in the address determined before compiles. Should between DO and LOOP EXIT confessed, then this instruction left its own identification on the stack and produced an JMP instruction with "Dummy" address. LOOP replaces this address by on the own JMP instruction the following.

Speed is trumpf

REPEAT the procedure is similar as DO. Only the identification differs. If UNTIL on one REPEATInstruction follows, first the following expression is translated. A conditioned jump is only then attached. There the 6502 only relatively short, conditioned jumps knows, becomes with "BNE * +5:JMP ad"worked. Naturally must also UNTIL possible EXITInstructions consider.

WHILE-TURN corresponds evenly to the discussing, only here the condition at the loop beginning stands.

FOR-NEXT ONELoops it is to be still noted that additionally the basic stack is used. Therefore becomes automatically POPInstruction into that EXITInstruction enclosed.

Thus the impact of the compiler is avowed. Perhaps is however not yet completely clear you, as the interpreter and the compiler determine the order of the computations. The interpreter implements the computations, the compiler produces a P-CODE. Nevertheless both function according to the same principle. For the intermediate storage of the operators in each case a stack (pile) serves. In addition a simple example:

 8*Sin(A)+16

The compiler reads the number 8. As number it is compiled immediately. (the interpreter became it on the number pile placing.) Then that is read tokens for multiplication (*) with the priority 5. Since the pile for operators is still empty (priority 0), that tokens there put down. Next follows SIN with the highest possible priority (9). Because this is larger than on the pile (5), becomes also SIN on the pile put. Then the opened clip follows. As special function the clip calls the same routine again, however recursively. The value is thus translated accordingly or computed into parentheses. Then the variable A comes to the row. Variable ones are compiled, exactly the same as numbers, immediately. Then the clip locks as end characteristic. It continues to go with the original upper setting. It follows now tokens for addition (+), whose priority is smaller (4) than on the pile. Therefore now that becomes SINInstruction compiles. Still the available priority with that becomes subsequently, "*" - token (5) compared. Since it is again smaller, the multiplication is compiled now.

The empty stack has the priority 0, therefore that is put down tokens for addition on the stack. Then the number of 16 and the end characteristic with the priority 0 finally follow. The pile is afterwards empty, those addition is compiled, and that procedure is terminated. The developed P-CODE reads "Number of 8 Var A Sin Mult number of 16 ADDS".

As simply as here described, is not compiling BASIC programs however. This steep one was to be demonstrated rather to, how the turbo-compiler functions in principle. If all procedures should be described with compiling, this would fill a book. Still another tip: The standard Atari basic is not because of an operating system error able, "A=NOT EMERGENCY Ato compute ". This is connected with the batch processing. Try this instruction sequence out nevertheless simply once on its Atari 800XL. Due to the syntax check the instruction is not permissible. The old Atari computers reacted to "A=NOT EMERGENCY A"with a system crash. Enter the program line nevertheless simply once under turbo- basic XL. They will see that also such complex, logic functions duly to function.

(franc Ostrowski/wb)