APP - Assembly Pre-Processor ---------------------------- Version 2.0, 28-April-1990 PUBLIC DOMAIN written by Karl Lehenbauer, first release 12/8/88, with a lot of design input by Peter da Silva. Version 2.0, released 4/28/90, incorporated changes by Brett Bourbin (Selgus Limited) involving input/output file handling and added the dbra looping construct. Karl made a backwards-compatible version of the new i/o file handling, converted to ANSI C, spruced up the docs, etc. Disclaimer and Redistribution Information ----------------------------------------- APP is placed freely into the public domain for any use without restriction. APP comes without warranties, expressed or implied. This is free software. We don't have a contract. We're not asking for money for this, but if you use it a lot, a check for $10 or $20 would always be appreciated. Make checks to Hackercorp, 3918 Panorama, Missouri City, TX 77459 What it is ---------- APP is a preprocessor for the 68000 assembler that comes with Aztec C for the Amiga. It will probably work with other 68000 assemblers. It works fine with 68020/68030 instructions, too. It can easily be adapted to other processor architectures as well. APP provides structured programming constructs for the assembly language programmer. Specifically, APP provides support for IF-THEN-ELSE-ELSEIF- ENDIF constructs and for DO-WHILE-UNTIL-ENDDO constructs. Consider the C pseudocode fragment: long a, b; if (a < 0) { less_than_zero_stuff(); } else { not_less_that_zero_stuff(); } In assembler (or pre-77 FORTRAN, for example) to do the same thing requires the creation of two bogus labels, as in: move.l _a,d0 bge else_part jsr _less_than_zero_stuff bra past_the_else else_part jsr _not_less_than_zero_stuff past_the_else When you start nesting these deeply, the code quickly becomes unreadable. Note also that you have to reverse the sense to branch around the code you really want to execute. This makes the code less clear. If the assembler had structured programming constructs like C, Modula 2, Forth, etc, the creation of these superfluous labels is unnecessary. Using APP, the above code fragment can be rewritten: move.l _a,d0 .if lt jsr _less_than_zero_stuff .else jsr _not_less_than_zero_stuff .endif To define an "if", enter an opcode of ".if" and an operand of a condition code that the assembler recognizes as a branch when following behind a 'b', as in condition codes "le", "lt", "eq", "ne", "gt", "ge" yielding "ble", "blt", "beq", "bne", "bgt", "bge" You will have issued instructions to set up the condition codes before the ".if". For "if", APP will assemble a conditional branch with the sense reversed, branching to the matching ".else", ".elseif", or ".endif". APP will make up labels and produce the equivalent branching code as above. I have chosen to make APP's labels be 'L' followed by an increasing sequential integer label number. This was chosen to avoid conflicting with Manx's '.' followed by the number so you can incrementally "structurize" and test as you hand optimize the output of cc with optimization and assembly source generation flags selected. APP also supports a do/enddo construct. The way it works is ".enddo" compiles a "branch always" instruction back to the corresponding ".do". To exit the do/enddo, three constructs are provided. These are ".while", ".until" and ".dbra". ".while" takes a condition code and, if it is true, execution continues below the while, else a branch past the enddo is taken. ".until" in the opposite manner, if the condition code is true a branch past the enddo is taken otherwise it isn't. (".dbra" will be described later below.) For example, .do ;conditional setup stuff . . .while ne ; execution stuff . . .enddo ...will execute code between the do and the enddo until the condition code at the "while" isn't true anymore. Multiple .whiles and .untils may be used and .whiles and .untils may be freely intermixed. An additional do structure provided on the 68000 series to take advantage of specific 68000 looping capabilities. This is the decrement-and-branch, DBRA, instruction. Using DBRA, many simple copying loops can be coded with only two instructions. Consequently, dbra is provided as a .do-terminating instruction as an alternative to .enddo, as in: .do ; loop code ; .dbra d5 In the preceding example, the loop code will be executed a number of times equal to the value in d5, with the dbra instruction decrementing d5 each time through the loop until d5 is zero when dbra checks it, at which time it will "fall through", executing the next instruction after the dbra. Note that .dbra is different from dbra in that .dbra indicates to app that it terminates a matching .do, thus that app is to generate a dbra instruction to decrement the specified register and branch back to the corresponding .do statement, while a "dbra" is just a regular dbra instruction, app just passes it through, and it requires the register and a label like any other label-branching instruction on the 68000. Nesting of conditionals is permitted to a depth of 32. When nesting, I reccommend indenting your code, as in: tst.l d0 .if gt add.l d0,d1 cmp.l #max,d1 .if gt move.l #max,d1 .endif .endif Setting tab stops at four seems to work well. How To Invoke APP ----------------- APP takes the name of the structured assembly source it is to compile into standard assembly source code on the command line, as in app foo.app This produces foo.asm, if app doesn't detect any errors while processing the file. When used in the above manner, the name of the source file must end with .app, and app will always create the output file with a .asm extension. Alternatively, you may specify the output file, as in: app -o foo.asm foo.a Note that for the second form, the .app extension of the source filename is not required. Integrating APP with your makefile ---------------------------------- If you add the following rules to your makefile and list object files corresponding to your assembly preprocessor source .app files in your make dependencies, make will run APP over your .app files and then run "as" over the resulting .asm files automatically. .app.o: app $*.app as $*.asm Condition Codes Known by APP ---------------------------- The following condition codes may be used APP's .if, .elseif, .while and .until statements: "ne" "eq" "lt" "ge" "le" "gt" "cc" "cs" "vc" "vs" "hi" "ls" "pl" "mi" Consult your 68000 Reference Manual if you need to know what status register bits and states correspond to these codes. They're the standard ones. APP Error Messages ------------------ APP does a lot of checking of your APP "dot" statements to insure their validity. Specifically, APP insures that all .ifs have matching .endifs, that all .dos have matching .enddo or .dbra, that only one .else is specified inside a .if, that .elseifs are only specified inside .ifs, that .whiles and .untils are only specified inside a .do and that all "dot" structures are closed at end of file. If APP does detect an error, it prints an error message including the line number and exits. (It could conceivably go on, but I have yet to take it this far.) If APP is pointing to the last line in the file, the problem is that you didn't close a .if or .do structure somewhere earlier in the file. If APP exits with an error, it removes the .asm output file so the file won't confuse "make" into thinking everything went OK with APP when it really didn't. Enumeration of Variations by Pseudo-Example ------------------------------------------- .if cc .endif .if cc .else .endif .if cc .elseif cc .endif .if cc .elseif cc .elseif cc .endif .do .enddo .do .while cc .enddo .do .until cc .enddo .do .until cc .until cc .while cc .enddo .do .dbra reg .do .until cc .while cc .dbra reg Miscellaneous Notes ------------------- APP conditionals may be nested up to 32 levels deep. If you need to go deeper (seven or eight seems like the realistic-use upper limit to me), change the MAX_NESTING_LEVELS define in app.c. All the APP constructs must be entered in lower case only, and the condition codes as well. Note that the functions provided by APP could have been done by assembler macros if the Aztec assembler had supported the ability to expand a macro with an argument being the *value* of a SET variable, had string variables or the ability to concatenate text with a SET variable -- it doesn't, and similar problems appear in other assemblers as well. Note also that APP doesn't check condition codes for validity unless their sense has to be reversed. It probably should check them, but invalid ones won't get past the assembler in any case. APP is so vanilla in its construction that it should run on about any machine with a C compiler and a stdio library. It for sure runs under Aztec C on the Amiga and on Intel '286 Multibus Xenix (don't ask why). Version 1.1 and onward, though, require an ANSI standard C compiler. The documentation was significantly more work than the code. Warm Regards, Karl @ The Alternate Hacker's Haven -- Houston, TX, 12/11/88 updated - 4/28/90 Usenet: uunet!sugar!karl Internet/BITNET: karl@sugar.hackercorp.com