[comp.compilers] An assembly language for teaching an undergraduate level compiler class

sher@cs.Buffalo.EDU (09/04/89)

When I found out I was going to teach compilers I decided that probably 
the assembly language of the machine they were going to be on was going to
be a problem.  Too complex, too little documentation, the possibility of 
crashing the machine ....  I was looking for an assembly language that
was portable (so I can use it on several machines), simple (so I can focus
on theory) and easily modified (so I could fix mistakes and introduce
complexity if such is needed).  This led me to design a 
riscy assembly language out of C macros.  Any machine with a C compiler could
accept this assembly language so it was portable.  It's a simple
register machine with a large (but not enormous) stack and so on.  
Because I designed it this way I can monitor how many instructions are 
executed and how long they take and so illustrate optimization and other
such concepts.  However I can't easily do things like indirect memory 
(a la DEC20) or storing the pc (can't get it in C).  Since I suspect there
may be some fellow teachers of compilers (intro language processing to be
exact) out there I thought with permission of the moderator I'd post the 
thing.  Its only 100 odd lines long so net bandwidth won't be overwhelmed.
Here it is:
-David Sher
Ps: I know the stack statements are a bit wierd, every machine has a bit 
of wierdness no?
------------------------------cut here------------------------------------
/*
    This file contains the macros that translate my pseudo assembly language
    into code.  This allows me to have a machine independent assembly language
    for teaching compilers.  Written in 1989 by David Sher,
    sher@cs.Buffalo.EDU.  Released into the public domain by the author, who
    would appreciate it if his name were kept on any copies you make.
*/

#include <stdio.h>

/*
    global variables that keep track of how long the program took and
    how many instructions were executed
*/
int INSTR_COUNT = 0;	        /* # of instructions */
int INSTR_TIME  = 0;		/* time for instructions */

/* ajay :
   System-wide constants (different sizes) */

#define WORD   (sizeof(int))
#define BYTE   (sizeof(char))

/*
    definitions of timings
*/
#define MEM_ACCESS  4
#define SIMPLE_OP   1
#define COMPLEX_OP  10
#define STACK_ACCESS  5
#define CONDITIONAL  2
#define IO_CALL  10

/*
    Place for registers
*/

int REGS[7];

/*
    Place for the stack
*/
int STACK[65535];
int *SP = STACK;

/*
    Macros to control the main block
*/
/* begins the main block */
#define BEGIN	main(){
/* ends the main block */
#define END	printf("\nExecuted %d instructions, took %d units of time\n",INSTR_COUNT,INSTR_TIME); exit(0);}

/*
    Macro for static storage allocation , and allocating strings ..
*/
#define BLOCK(NAME,SIZE) int NAME[(SIZE)];

/*
    Macros for moving between memory and registers
*/
#define LOAD(R,A) 	REGS[R] = *(A); INSTR_COUNT++; INSTR_TIME += MEM_ACCESS;
#define LOAD_IMMEDIATE(R,A) REGS[R] = ((int) A); INSTR_COUNT++; INSTR_TIME += MEM_ACCESS;
#define LOAD_INDIRECT(R,R2) REGS[R] = *((int *) REGS[R2]); INSTR_COUNT++; INSTR_TIME += MEM_ACCESS;
#define STORE(R,A) 	*(A) = REGS[R]; INSTR_COUNT++; INSTR_TIME += MEM_ACCESS;
#define STORE_INDIRECT(R,R2)  *((int *) REGS[R2]) = REGS[R]; INSTR_COUNT++; INSTR_TIME += MEM_ACCESS;

/*
    Macros for stack manipulation
*/
#define PUSH(R1,R2) 	((REGS[R2])? (*(SP - REGS[R2] + 1) = REGS[R1]) : \
                                     (*(++SP) = REGS[R1])); INSTR_COUNT++; INSTR_TIME += STACK_ACCESS;
#define POP(R)          REGS[R] = *SP--;INSTR_COUNT++; INSTR_TIME += SIMPLE_OP;
#define GET(R1,R2)  	REGS[R1] = *(SP - REGS[R2] - 1); INSTR_COUNT++; INSTR_TIME += STACK_ACCESS;

/*
    Macros for Arithmetic
*/
#define INC(R)          REGS[R]++ ; INSTR_COUNT++ ; INSTR_TIME += SIMPLE_OP ;
#define DEC(R)          REGS[R]-- ; INSTR_COUNT++ ; INSTR_TIME += SIMPLE_OP ;
#define ADD(R1,R2,R3) 	REGS[R3] = REGS[R1] + REGS[R2]; INSTR_COUNT++; INSTR_TIME += SIMPLE_OP;
#define SUBTRACT(R1,R2,R3) REGS[R3] = REGS[R1] - REGS[R2]; INSTR_COUNT++; INSTR_TIME += SIMPLE_OP;
#define MULTIPLY(R1,R2,R3) REGS[R3] = REGS[R1] * REGS[R2]; INSTR_COUNT++; INSTR_TIME += COMPLEX_OP;
#define DIVIDE(R1,R2,R3) REGS[R3] = REGS[R1] / REGS[R2]; INSTR_COUNT++; INSTR_TIME += COMPLEX_OP;


  /*
  Flow of control statements
  */

#define NOP		INSTR_COUNT++; INSTR_TIME += SIMPLE_OP;
#define JUMP(L)		INSTR_COUNT++; INSTR_TIME += SIMPLE_OP;goto L;
#define JUMP_ZERO(R,L)	INSTR_COUNT++; INSTR_TIME += CONDITIONAL;if( REGS[R] == 0 ) goto L;
#define JUMP_NEGATIVE(R,L)    INSTR_COUNT++; INSTR_TIME += CONDITIONAL;if( REGS[R] < 0 ) goto L;
#define JUMP_POSITIVE(R,L)    INSTR_COUNT++; INSTR_TIME += CONDITIONAL;if( REGS[R] > 0 ) goto L;

/*
    SUBROUTINE management
*/
#define BEGIN_PROCEEDURE(NAME)	void NAME(){
#define END_PROCEEDURE		}
#define CALL(NAME)		NAME(); INSTR_COUNT++; INSTR_TIME += STACK_ACCESS;

/*
    I/O management
*/
#define READ(R)		REGS[R] = (int) getchar(); INSTR_COUNT++; INSTR_TIME += IO_CALL;
#define WRITE(R)	(void) putchar((char) REGS[R]); INSTR_COUNT++; INSTR_TIME += IO_CALL;



/* debugging help ...     */

#define DUMP  printf("Register Dump :- \n"); printf("     R0      R1      R2      R3      R4      R5      R6\n"); printf("%7x %7x %7x %7x %7x %7x %7x\n\n",REGS[0],REGS[1],REGS[2],REGS[3],REGS[4],REGS[5],REGS[6]);

-David Sher
ARPA: sher@cs.buffalo.edu	BITNET: sher@sunybcs
UUCP: {rutgers,ames,boulder,decvax}!sunybcs!sher

[From sher@cs.Buffalo.EDU]
-- 
Send compilers articles to compilers@ima.isc.com or, perhaps, Levine@YALE.EDU
{ decvax | harvard | yale | bbn }!ima.  Meta-mail to ima!compilers-request.
Please send responses to the author of the message, not the poster.