mirror of
https://github.com/ThomasDickey/mawk-snapshots.git
synced 2026-01-26 11:04:34 +00:00
251 lines
4.9 KiB
C
251 lines
4.9 KiB
C
/********************************************
|
|
jmp.c
|
|
copyright 2009-2021,2024, Thomas E. Dickey
|
|
copyright 1991-1993,1995, 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.
|
|
********************************************/
|
|
|
|
/*
|
|
* $MawkId: jmp.c,v 1.9 2024/08/25 17:03:50 tom Exp $
|
|
*/
|
|
|
|
/* 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
|
|
*/
|
|
|
|
#define Visible_CELL
|
|
#define Visible_CODEBLOCK
|
|
|
|
#include <mawk.h>
|
|
#include <symtype.h>
|
|
#include <jmp.h>
|
|
#include <code.h>
|
|
#include <sizes.h>
|
|
#include <init.h>
|
|
#include <memory.h>
|
|
|
|
#define error_state (compile_error_count>0)
|
|
|
|
/*---------- back patching jumps ---------------*/
|
|
|
|
typedef struct jmp {
|
|
struct jmp *link;
|
|
int source_offset;
|
|
} JMP;
|
|
|
|
static JMP *jmp_top;
|
|
|
|
void
|
|
code_jmp(int jtype, const INST * target)
|
|
{
|
|
if (error_state)
|
|
return;
|
|
|
|
/* WARNING: Don't emit any code before using target or
|
|
relocation might make it invalid */
|
|
|
|
if (target)
|
|
code2op(jtype, (int) (target - (code_ptr + 1)));
|
|
else {
|
|
register JMP *p = ZMALLOC(JMP);
|
|
|
|
/* stack for back patch */
|
|
code2op(jtype, 0);
|
|
p->source_offset = code_offset - 1;
|
|
p->link = jmp_top;
|
|
jmp_top = p;
|
|
}
|
|
}
|
|
|
|
/* patch a jump on the jmp_stack */
|
|
void
|
|
patch_jmp(const INST * target)
|
|
{
|
|
if (!error_state) {
|
|
register JMP *p;
|
|
register INST *source; /* jmp starts here */
|
|
|
|
#ifdef DEBUG
|
|
if (!jmp_top)
|
|
bozo("jmp stack underflow");
|
|
#endif
|
|
|
|
p = jmp_top;
|
|
jmp_top = p->link;
|
|
source = p->source_offset + code_base;
|
|
source->op = (int) (target - source);
|
|
|
|
ZFREE(p);
|
|
}
|
|
}
|
|
|
|
/*-- break and continue -------*/
|
|
|
|
typedef struct bc {
|
|
struct bc *link; /* stack as linked list */
|
|
int type; /* 'B' or 'C' or mark start with 0 */
|
|
int source_offset; /* position of _JMP */
|
|
} BC;
|
|
|
|
static BC *bc_top;
|
|
|
|
void
|
|
BC_new(void) /* mark the start of a loop */
|
|
{
|
|
BC_insert(0, (INST *) 0);
|
|
}
|
|
|
|
void
|
|
BC_insert(int type, const 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 = ZMALLOC(BC);
|
|
p->type = type;
|
|
p->source_offset = (int) (address - code_base);
|
|
p->link = bc_top;
|
|
bc_top = p;
|
|
}
|
|
}
|
|
|
|
/* patch all break and continues for one loop */
|
|
void
|
|
BC_clear(INST * B_address, INST * C_address)
|
|
{
|
|
register BC *p;
|
|
|
|
if (error_state)
|
|
return;
|
|
|
|
p = bc_top;
|
|
/* pop down to the mark node */
|
|
while (p->type) {
|
|
INST *source;
|
|
register BC *q;
|
|
|
|
source = code_base + p->source_offset;
|
|
source->op = (int) ((p->type == 'B' ? B_address : C_address)
|
|
- source);
|
|
|
|
q = p;
|
|
p = p->link;
|
|
ZFREE(q);
|
|
}
|
|
/* remove the mark node */
|
|
bc_top = p->link;
|
|
ZFREE(p);
|
|
}
|
|
|
|
/*----- moving code --------------------------*/
|
|
|
|
/* a stack to hold some pieces of code while
|
|
reorganizing loops .
|
|
*/
|
|
|
|
typedef struct mc { /* mc -- move code */
|
|
struct mc *link;
|
|
INST *code; /* the save code */
|
|
unsigned len; /* its length */
|
|
int scope; /* its scope */
|
|
int move_level; /* size of this stack when coded */
|
|
FBLOCK *fbp; /* if scope FUNCT */
|
|
int offset; /* distance from its code base */
|
|
} MC;
|
|
|
|
static MC *mc_top;
|
|
int code_move_level = 0; /* see comment in jmp.h */
|
|
|
|
#define NO_SCOPE -1
|
|
/* means relocation of resolve list not needed */
|
|
|
|
void
|
|
code_push(INST * code, unsigned len, int scope, FBLOCK * fbp)
|
|
{
|
|
register MC *p;
|
|
|
|
if (!error_state) {
|
|
p = ZMALLOC(MC);
|
|
p->len = len;
|
|
p->link = mc_top;
|
|
mc_top = p;
|
|
|
|
if (len) {
|
|
p->code = (INST *) zmalloc(sizeof(INST) * len);
|
|
memcpy(p->code, code, sizeof(INST) * len);
|
|
}
|
|
if (!resolve_list)
|
|
p->scope = NO_SCOPE;
|
|
else {
|
|
p->scope = scope;
|
|
p->move_level = code_move_level;
|
|
p->fbp = fbp;
|
|
if (code)
|
|
p->offset = (int) (code - code_base);
|
|
else
|
|
p->offset = 0;
|
|
}
|
|
}
|
|
code_move_level++;
|
|
}
|
|
|
|
/* copy the code at the top of the mc stack to target.
|
|
return the number of INSTs moved */
|
|
|
|
unsigned
|
|
code_pop(INST * target)
|
|
{
|
|
register MC *p;
|
|
unsigned len;
|
|
int target_offset;
|
|
|
|
if (error_state)
|
|
return 0;
|
|
|
|
#ifdef DEBUG
|
|
if (!mc_top)
|
|
bozo("mc underflow");
|
|
#endif
|
|
|
|
p = mc_top;
|
|
mc_top = p->link;
|
|
len = p->len;
|
|
|
|
while (target + len >= code_warn) {
|
|
target_offset = (int) (target - code_base);
|
|
code_grow();
|
|
target = code_base + target_offset;
|
|
}
|
|
|
|
if (len) {
|
|
memcpy(target, p->code, len * sizeof(INST));
|
|
zfree(p->code, len * sizeof(INST));
|
|
}
|
|
|
|
if (p->scope != NO_SCOPE) {
|
|
target_offset = (int) (target - code_base);
|
|
relocate_resolve_list(p->scope, p->move_level, p->fbp,
|
|
p->offset, len, target_offset - p->offset);
|
|
}
|
|
|
|
ZFREE(p);
|
|
code_move_level--;
|
|
return len;
|
|
}
|