386BSD 0.1 development
[unix-history] / usr / src / usr.bin / awk / jmp.c
CommitLineData
a7e60862
WJ
1
2/********************************************
3jmp.c
4copyright 1991, Michael D. Brennan
5
6This is a source file for mawk, an implementation of
7the AWK programming language.
8
9Mawk is distributed without warranty under the terms of
10the GNU General Public License, version 2, 1991.
11********************************************/
12
13/* $Log: jmp.c,v $
14 * Revision 5.1 91/12/05 07:56:10 brennan
15 * 1.1 pre-release
16 *
17*/
18
19/* this module deals with back patching jumps, breaks and continues,
20 and with save and restoring code when we move code.
21 There are three stacks. If we encounter a compile error, the
22 stacks are frozen, i.e., we do not attempt error recovery
23 on the stacks
24*/
25
26
27#include "mawk.h"
28#include "jmp.h"
29#include "code.h"
30#include "sizes.h"
31#include "init.h"
32#include "memory.h"
33
34extern unsigned compile_error_count ;
35#define error_state (compile_error_count>0)
36
37
38/*---------- back patching jumps ---------------*/
39
40typedef struct jmp {
41struct jmp *link ;
42INST *source ;
43} JMP ;
44
45static JMP *jmp_top ;
46
47void code_jmp( jtype, target)
48 int jtype ;
49 INST *target ;
50{
51 register INST *source ;
52
53 if (error_state) return ;
54
55 code1(jtype) ;
56 source = code_ptr++ ;
57
58 if ( target ) source->op = target - source ;
59 else /* save source on jump stack */
60 {
61 register JMP *p = (JMP*) zmalloc(sizeof(JMP)) ;
62 p->source = source ;
63 p->link = jmp_top ;
64 jmp_top = p ;
65 }
66}
67
68void patch_jmp(target) /* patch a jump on the jmp_stack */
69 INST *target ;
70{ register JMP *p ;
71
72 if ( ! error_state )
73 {
74#ifdef DEBUG
75 if (!jmp_top) bozo("jmp stack underflow") ;
76#endif
77
78 p = jmp_top ; jmp_top = p->link ;
79
80 p->source->op = target - p->source ;
81
82 zfree(p, sizeof(JMP)) ;
83 }
84}
85
86
87/*-- break and continue -------*/
88
89typedef struct bc {
90struct bc *link ; /* stack as linked list */
91int type ; /* 'B' or 'C' or mark start with 0 */
92INST *source ; /* position of _JMP */
93} BC ;
94
95static BC *bc_top ;
96
97
98
99void BC_new() /* mark the start of a loop */
100{
101 BC_insert(0, (INST*) 0 ) ;
102}
103
104void BC_insert(type, address)
105 int type ; INST *address ;
106{ register BC * p ;
107
108 if ( error_state ) return ;
109
110 if ( type && ! bc_top )
111 {
112 compile_error("%s statement outside of loop",
113 type == 'B' ? "break" : "continue" ) ;
114
115 return ;
116 }
117 else
118 {
119 p = (BC*) zmalloc(sizeof(BC)) ;
120 p->type = type ;
121 p->source = address ;
122 p->link = bc_top ;
123 bc_top = p ;
124 }
125}
126
127
128void BC_clear(B_address, C_address)
129/* patch all break and continues for one loop */
130INST *B_address, *C_address ;
131{ register BC *p , *q ;
132
133 if (error_state) return ;
134
135 p = bc_top ;
136 /* pop down to the mark node */
137 while ( p->type )
138 {
139 p->source->op = (p->type == 'B' ? B_address : C_address)
140 - p->source ;
141
142 q = p ; p = p->link ; zfree(q, sizeof(BC)) ;
143 }
144 /* remove the mark node */
145 bc_top = p->link ;
146 zfree(p, sizeof(BC)) ;
147}
148
149/*----- moving code --------------------------*/
150
151/* a stack to hold some pieces of code while
152 reorganizing loops .
153 This used to be used on all loops. Now it is used
154 only for the 3rd expression on a for loop and
155 for the fist part of a range pattern
156*/
157
158typedef struct mc { /* mc -- move code */
159struct mc *link ;
160INST *code ;
161unsigned len ;
162} MC ;
163
164static MC *mc_top ;
165
166
167void code_push( code, len)
168 INST *code ; unsigned len ;
169{
170 register MC *p ;
171
172 if (! error_state )
173 {
174 p = (MC*) zmalloc(sizeof(MC)) ;
175 p->len = len ;
176 p->link = mc_top ;
177 mc_top = p ;
178
179 if ( len )
180 {
181 p->code = (INST*) zmalloc(sizeof(INST)*len) ;
182 (void) memcpy(p->code, code, SIZE_T(sizeof(INST)*len)) ;
183 }
184 }
185}
186
187/* copy the code at the top of the mc stack to target.
188 return the number of INSTs moved */
189
190unsigned code_pop(target)
191 INST *target ;
192{
193 register MC *p ;
194 unsigned retval ;
195
196 if (error_state) return 0 ;
197
198#ifdef DEBUG
199 if ( ! mc_top ) bozo("mc underflow") ;
200#endif
201
202 p = mc_top ; mc_top = p->link ;
203
204 if ( retval = p->len )
205 {
206 (void) memcpy(target, p->code, SIZE_T(p->len*sizeof(INST))) ;
207 zfree(p->code, p->len*sizeof(INST)) ;
208 }
209
210 zfree(p, sizeof(MC)) ;
211 return retval ;
212}