This preprocessor gives an amazing feature to any 8051 assembler. It can
generate code corresponding to higher languages constructs, such as
	do { } while
	while { }
	if ( ) then { } else { }
	and others

Actually, the preprocessor generates code for the 8051 family of microproces-
sors, but it can be modified to be used with other processors.

The structured constructs are done with conditional jumps to labels generated
by this program. The basic principle is to generate unique labels for the
assembler. 
To have a unique label, we take the type of construct, the nesting 
level, and a sequential counter for each level of the construct. when the 
label is generated, it looks like this.

		WH_12020:
WH_ is the construct type,
12 is the nesting level and
020 is a sequential number for that level.

The IF_CMP and IF_EQU/IF_NOT_EQU macros can recognize many constant 
forms. The only constant value checked is 00 or NULL, so that the code 
generated is simplified from a CJNE to a JNZ in most cases.

A DO_WHILE(--Rn,NE,00h) macro will be translated into a DJNZ Rn.

Some powerful macros are the WHILE/IF_CMP(register,condition,value) because 
they generate the proper subtraction and jump according to the specified 
condition.

Register/value can be a register, a direct address, an indirect register 
or an immediate value.
 
A possible drawback may be in nested IF THEN ELSE; code generated will have
possibly a chain of jumps. For nested IF ENDIF, there is no problem.

A work around for this is to use the SWITCH instead.

There should not be any label in the same line as the macro, it's not 
necessary anyway. There can be comments in the same line as the macro, but
it will not be printed in the output file.

Constants defined in your programs can have these formats:
 	00h-0ffh
 	h'00 - h'ff
	x'00 - x'ff
	0x'00 - 0x'ff
 	0x00 - 0xff
	$00 - $ff
 
Condition:  <,  >, <=, >=, <>, !=, ==, = 
            LT, HT, LE, HE, NE,     EQ

<>, !=, NE are equivalent
==, =, EQ are equivalent
<, LT are equivalent
>, HT are equivalent
<=, LE are equivalent
>=, HE are equivalent

Register can be R0 to R7, #value, @R0, @R1, Direct_Address 
Value can be R0 to R7, #value, @R0, @R1, Direct_Address 

In some macros, there is a MASK value. When the MASK is not needed,
specify %M_MACRO_XXX (Register,,Value). There is no space between the
2 commas.
if there is no mask, no ANL instruction will be generated


Here's the C equivalent of the macros

do {statement} while (bit)
do {statement} while (!bit)
do {statement} while (register <condition> value)
do {statement} while ((register & mask) == value)
do {statement} while ((register & mask) != value)
do {statement} while (dptr) != value)
break

for the multiple test, the C equivalent is noted:

	else if (register & mask) == value1 or value2 or value3

I mean here: if register and mask equals one of these 3 values

If for any reason, you would like to change the macro names, it's possible:
just modify them in the parser section in the file structured_pgm.awk
You can also add your own macros.

======== DO WHILE LOOP ===========
At the beginning of the DO WHILE loop, put a macro
	%M_DO
		;put your assembler code here
		;it can be indented to increase readability
		
At the end of the DO WHILE loop, put one of the possible conditions:

do {statement} while (bit)
%M_DO_WHILE_BIT(bit)

do {statement} while (!bit)
%M_DO_WHILE_NOT_BIT(bit)

do {statement} while (register <condition> value)
%M_DO_WHILE(register,condition,value)

do {statement} while ((register & mask) == value)
%M_DO_WHILE_EQU(REGISTER,MASK,VALUE)

do {statement} while ((register & mask) != value)
%M_DO_WHILE_NOT_EQU(REGISTER,MASK,VALUE)

do {statement} while (dptr) != value)
The low byte of DPTR is checked first.
%M_DO_WHILE_DPTR_NE(VALUE_H,VALUE_L)

To jump out of the DO loop, put this macro inside.
%M_DO_BREAK

This will jump to the beginning of the DO loop without doing
the ending condition. This is equivalent to a "goto Label" with
the Label defined at the beginning of the DO WHILE loop.
%M_REDO

======== WHILE WEND LOOP ===========

At the end of the WHILE loop, put this macro.
%M_WH_END

At the beginning of the WHILE WEND, put one of the possible conditions:
%M_WHILE_BIT(bit)

%M_WHILE_NOT_BIT(bit)

%M_WHILE(register,condition,value)

%M_WH_BREAK

======== IF THEN ELSE ===========
The M_ELSE and M_ELSE_IF sections are optional, they can be omitted in your
source code
The M_ENDIF is required at the end of the IF block

%M_IF_BIT(bit)
	statement
%M_ELSE_IF_BIT(bit)
	statement
%M_ELSE_IF_NOT_BIT(bit)
	statement
%M_ELSE
	statement
%M_ENDIF

%M_IF_NOT_BIT(bit)
	statement
%M_ELSE_IF_BIT(bit)
	statement
%M_ELSE_IF_NOT_BIT(bit)
	statement
%M_ELSE
	statement
%M_ENDIF

THE FOLLOWING MACROS CAN USE M_ELSE ALSO

How to mix these different tests ?
The M_IF_EQU and M_IF_NOT_EQU forms uses the accumulator for storing the result of
(register & mask). 
Tests are on the same level when they are in an M_IF M_ELSEIF ... M_ELSE M_ENDIF chain.
When tests are not on the same level (nested), tests can be freely mixed together
except the M_IF_NOT(register) which doesn't do the calculation (register & mask).

if !(register)		// register == 0 
%M_IF_NOT(register)
	statement
%M_ENDIF

if (register & mask) != value
%M_IF_NOT_EQU(REGISTER,MASK,VALUE)
	statement
%M_ENDIF

if (register & mask) == value
%M_IF_EQU(REGISTER,MASK,VALUE)

else if (register & mask) == value
%M_ELSE_IF_EQU(VALUE)

else if (register & mask) == value1 or value2
%M_ELSE_IF_EQU_OR2(VALUE1,VALUE2)

else if (register & mask) == value1 or value2 or value3
%M_ELSE_IF_EQU_OR3(VALUE1,VALUE2,VALUE3)

else if (register & mask) == value1 or value2 or value3 or value4
%M_ELSE_IF_EQU_OR4(VALUE1,VALUE2,VALUE3,VALUE4)

if (register & mask) == value1 or value2
M_IF_EQU_OR2(REGISTER,MASK,VALUE1,VALUE2)

if (register & mask) == value1 or value2 or value3
M_IF_EQU_OR3(REGISTER,MASK,VALUE1,VALUE2,VALUE3)

if (register & mask) == value1 or value2 or value3 or value4
M_IF_EQU_OR4(REGISTER,MASK,VALUE1,VALUE2,VALUE3,VALUE4)

if (register condition value)
This macro uses the accumulator for the compare.
%M_IF_CMP(register,condition,value)
	statement
%M_ELSE
	statement
%M_ENDIF

======== SWITCH CASE ===========

%M_SWITCH(register,mask)
	%M_CASE(value)
		statement
		%M_SW_BREAK
	
	;if (register & mask) == value1 or value2
	%M_CASE_OR2(value1,value2)
		statement
		%M_SW_BREAK
	
	;if (register & mask) == value1 or value2 or value3
	%M_CASE_OR3(value1,value2,value3)	
		statement
		%M_SW_BREAK
	
	;if (register & mask) == value1 or value2 or value3 or value4
	%M_CASE_OR4(value1,value2,value3,value4)
		statement
		%M_SW_BREAK
	
	%M_SW_DEFAULT
		statement
%M_SW_END

===============================
A %M_BREAK can replace one of the %M_xx_BREAK above.
A %M_BREAK in a IF block will jump to the end of the IF block
%M_DEFAULT can be used instead of %M_SW_DEFAULT  






