NetBSD/gnu/usr.bin/awk/jmp.c

216 lines
4.1 KiB
C

/********************************************
jmp.c
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the AWK programming language.
Mawk is distributed without warranty under the terms of
the GNU General Public License, version 2, 1991.
********************************************/
/* $Log: jmp.c,v $
/* Revision 1.2 1993/07/02 23:57:31 jtc
/* Updated to mawk 1.1.4
/*
* Revision 5.1 1991/12/05 07:56:10 brennan
* 1.1 pre-release
*
*/
/* this module deals with back patching jumps, breaks and continues,
and with save and restoring code when we move code.
There are three stacks. If we encounter a compile error, the
stacks are frozen, i.e., we do not attempt error recovery
on the stacks
*/
#include "mawk.h"
#include "jmp.h"
#include "code.h"
#include "sizes.h"
#include "init.h"
#include "memory.h"
extern unsigned compile_error_count ;
#define error_state (compile_error_count>0)
/*---------- back patching jumps ---------------*/
typedef struct jmp {
struct jmp *link ;
INST *source ;
} JMP ;
static JMP *jmp_top ;
void code_jmp( jtype, target)
int jtype ;
INST *target ;
{
register INST *source ;
if (error_state) return ;
code1(jtype) ;
source = code_ptr++ ;
if ( target ) source->op = target - source ;
else /* save source on jump stack */
{
register JMP *p = (JMP*) zmalloc(sizeof(JMP)) ;
p->source = source ;
p->link = jmp_top ;
jmp_top = p ;
}
}
void patch_jmp(target) /* patch a jump on the jmp_stack */
INST *target ;
{ register JMP *p ;
if ( ! error_state )
{
#ifdef DEBUG
if (!jmp_top) bozo("jmp stack underflow") ;
#endif
p = jmp_top ; jmp_top = p->link ;
p->source->op = target - p->source ;
zfree(p, sizeof(JMP)) ;
}
}
/*-- break and continue -------*/
typedef struct bc {
struct bc *link ; /* stack as linked list */
int type ; /* 'B' or 'C' or mark start with 0 */
INST *source ; /* position of _JMP */
} BC ;
static BC *bc_top ;
void BC_new() /* mark the start of a loop */
{
BC_insert(0, (INST*) 0 ) ;
}
void BC_insert(type, address)
int type ; INST *address ;
{ register BC * p ;
if ( error_state ) return ;
if ( type && ! bc_top )
{
compile_error("%s statement outside of loop",
type == 'B' ? "break" : "continue" ) ;
return ;
}
else
{
p = (BC*) zmalloc(sizeof(BC)) ;
p->type = type ;
p->source = address ;
p->link = bc_top ;
bc_top = p ;
}
}
void BC_clear(B_address, C_address)
/* patch all break and continues for one loop */
INST *B_address, *C_address ;
{ register BC *p , *q ;
if (error_state) return ;
p = bc_top ;
/* pop down to the mark node */
while ( p->type )
{
p->source->op = (p->type == 'B' ? B_address : C_address)
- p->source ;
q = p ; p = p->link ; zfree(q, sizeof(BC)) ;
}
/* remove the mark node */
bc_top = p->link ;
zfree(p, sizeof(BC)) ;
}
/*----- moving code --------------------------*/
/* a stack to hold some pieces of code while
reorganizing loops .
This used to be used on all loops. Now it is used
only for the 3rd expression on a for loop and
for the fist part of a range pattern
*/
typedef struct mc { /* mc -- move code */
struct mc *link ;
INST *code ;
unsigned len ;
} MC ;
static MC *mc_top ;
void code_push( code, len)
INST *code ; unsigned len ;
{
register MC *p ;
if (! error_state )
{
p = (MC*) zmalloc(sizeof(MC)) ;
p->len = len ;
p->link = mc_top ;
mc_top = p ;
if ( len )
{
p->code = (INST*) zmalloc(sizeof(INST)*len) ;
(void) memcpy(p->code, code, SIZE_T(sizeof(INST)*len)) ;
}
}
}
/* copy the code at the top of the mc stack to target.
return the number of INSTs moved */
unsigned code_pop(target)
INST *target ;
{
register MC *p ;
unsigned retval ;
if (error_state) return 0 ;
#ifdef DEBUG
if ( ! mc_top ) bozo("mc underflow") ;
#endif
p = mc_top ; mc_top = p->link ;
if ( retval = p->len )
{
(void) memcpy(target, p->code, SIZE_T(p->len*sizeof(INST))) ;
zfree(p->code, p->len*sizeof(INST)) ;
}
zfree(p, sizeof(MC)) ;
return retval ;
}