/********************************************
jmp.c
libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
based on mawk code coming with the below copyright:
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.
********************************************/
/* 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 "symtype.h"
#include "jmp.h"
#include "code.h"
#include "sizes.h"
#include "init.h"
#include "memory.h"
#define error_state (MAWK->compile_error_count>0)
/*---------- back patching jumps ---------------*/
void mawk_code_jmp(mawk_state_t *MAWK, int jtype, INST *target)
{
if (error_state)
return;
/* WARNING: Don't emit any code before using target or
relocation might make it invalid */
if (target)
mawk_code2op(MAWK, jtype, target - (mawk_code_ptr + 1));
else {
register JMP *p = MAWK_ZMALLOC(MAWK, JMP);
/* stack for back patch */
mawk_code2op(MAWK, jtype, 0);
p->source_offset = mawk_code_offset - 1;
p->link = MAWK->jmp_top;
MAWK->jmp_top = p;
}
}
void mawk_patch_jmp(mawk_state_t *MAWK, INST *target) /* patch a jump on the jmp_stack */
{
register JMP *p;
register INST *source; /* jmp starts here */
if (!error_state) {
#ifdef DEBUG
if (!MAWK->jmp_top)
mawk_bozo(MAWK, "jmp stack underflow");
#endif
p = MAWK->jmp_top;
MAWK->jmp_top = p->link;
source = p->source_offset + mawk_code_base;
source->op = target - source;
MAWK_ZFREE(MAWK, p);
}
}
/*-- break and continue -------*/
void mawk_BC_new(mawk_state_t * MAWK)
{ /* mark the start of a loop */
mawk_BC_insert(MAWK, 0, (INST *) 0);
}
void mawk_BC_insert(mawk_state_t *MAWK, int type, INST *address)
{
register BC *p;
if (error_state)
return;
if (type && !MAWK->bc_top) {
mawk_compile_error(MAWK, "%s statement outside of loop", type == 'B' ? "break" : "continue");
return;
}
else {
p = MAWK_ZMALLOC(MAWK, BC);
p->type = type;
p->source_offset = address - mawk_code_base;
p->link = MAWK->bc_top;
MAWK->bc_top = p;
}
}
/* patch all break and continues for one loop */
void mawk_BC_clear(mawk_state_t *MAWK, INST *B_address, INST *C_address)
{
register BC *p, *q;
INST *source;
if (error_state)
return;
p = MAWK->bc_top;
/* pop down to the mark node */
while (p->type) {
source = mawk_code_base + p->source_offset;
source->op = (p->type == 'B' ? B_address : C_address)
- source;
q = p;
p = p->link;
MAWK_ZFREE(MAWK, q);
}
/* remove the mark node */
MAWK->bc_top = p->link;
MAWK_ZFREE(MAWK, p);
}
/*----- moving code --------------------------*/
#define NO_SCOPE -1
/* means relocation of resolve list not needed */
void mawk_code_push(mawk_state_t *MAWK, INST *code, unsigned len, int scope, FBLOCK *fbp)
{
register MC *p;
if (!error_state) {
p = MAWK_ZMALLOC(MAWK, MC);
p->len = len;
p->link = MAWK->mc_top;
MAWK->mc_top = p;
if (len) {
p->code = (INST *) mawk_zmalloc(MAWK, sizeof(INST) * len);
memcpy(p->code, code, sizeof(INST) * len);
}
if (!MAWK->resolve_list)
p->scope = NO_SCOPE;
else {
p->scope = scope;
p->move_level = MAWK->ps.code_move_level;
p->fbp = fbp;
if (code != NULL)
p->offset = code - mawk_code_base;
else
p->offset = 0;
}
}
MAWK->ps.code_move_level++;
}
/* copy the code at the top of the mc stack to target.
return the number of INSTs moved */
unsigned mawk_code_pop(mawk_state_t *MAWK, INST *target)
{
register MC *p;
unsigned len;
int target_offset;
if (error_state)
return 0;
#ifdef DEBUG
if (!MAWK->mc_top)
mawk_bozo(MAWK, "mc underflow");
#endif
p = MAWK->mc_top;
MAWK->mc_top = p->link;
len = p->len;
while (target + len >= mawk_code_warn) {
target_offset = target - mawk_code_base;
mawk_code_grow(MAWK);
target = mawk_code_base + target_offset;
}
if (len) {
memcpy(target, p->code, len * sizeof(INST));
mawk_zfree(MAWK, p->code, len * sizeof(INST));
}
if (p->scope != NO_SCOPE) {
target_offset = target - mawk_code_base;
mawk_relocate_resolve_list(MAWK, p->scope, p->move_level, p->fbp, p->offset, len, target_offset - p->offset);
}
MAWK_ZFREE(MAWK, p);
MAWK->ps.code_move_level--;
return len;
}