Tizen 2.1 base
[external/mawk.git] / jmp.c
1
2 /********************************************
3 jmp.c
4 copyright 1991, Michael D. Brennan
5
6 This is a source file for mawk, an implementation of
7 the AWK programming language.
8
9 Mawk is distributed without warranty under the terms of
10 the GNU General Public License, version 2, 1991.
11 ********************************************/
12
13 /* $Log: jmp.c,v $
14  * Revision 1.4  1995/06/18  19:42:19  mike
15  * Remove some redundant declarations and add some prototypes
16  *
17  * Revision 1.3  1995/04/21  14:20:16  mike
18  * move_level variable to fix bug in arglist patching of moved code.
19  *
20  * Revision 1.2  1993/07/14  13:17:49  mike
21  * rm SIZE_T and run thru indent
22  *
23  * Revision 1.1.1.1  1993/07/03  18:58:15  mike
24  * move source to cvs
25  *
26  * Revision 5.3  1993/01/09  19:03:44  mike
27  * code_pop checks if the resolve_list needs relocation
28  *
29  * Revision 5.2  1993/01/07  02:50:33  mike
30  * relative vs absolute code
31  *
32  * Revision 5.1  1991/12/05  07:56:10  brennan
33  * 1.1 pre-release
34  *
35 */
36
37 /* this module deals with back patching jumps, breaks and continues,
38    and with save and restoring code when we move code.
39    There are three stacks.  If we encounter a compile error, the
40    stacks are frozen, i.e., we do not attempt error recovery
41    on the stacks
42 */
43
44
45 #include "mawk.h"
46 #include "symtype.h"
47 #include "jmp.h"
48 #include "code.h"
49 #include "sizes.h"
50 #include "init.h"
51 #include "memory.h"
52
53 #define error_state  (compile_error_count>0)
54
55
56 /*---------- back patching jumps  ---------------*/
57
58 typedef struct jmp
59 {
60    struct jmp *link ;
61    int source_offset ;
62 }
63 JMP ;
64
65 static JMP *jmp_top ;
66
67 void
68 code_jmp(jtype, target)
69    int jtype ;
70    INST *target ;
71 {
72    if (error_state)  return ;
73
74    /* WARNING: Don't emit any code before using target or
75      relocation might make it invalid */
76
77    if (target)  code2op(jtype, target - (code_ptr + 1)) ;
78    else
79    {
80       register JMP *p = ZMALLOC(JMP) ;
81
82       /* stack for back patch */
83       code2op(jtype, 0) ;
84       p->source_offset = code_offset - 1 ;
85       p->link = jmp_top ;
86       jmp_top = p ;
87    }
88 }
89
90 void
91 patch_jmp(target)               /* patch a jump on the jmp_stack */
92    INST *target ;
93 {
94    register JMP *p ;
95    register INST *source ;       /* jmp starts here */
96
97    if (!error_state)
98    {
99 #ifdef  DEBUG
100       if (!jmp_top)  bozo("jmp stack underflow") ;
101 #endif
102
103       p = jmp_top ; jmp_top = p->link ;
104       source = p->source_offset + code_base ;
105       source->op = target - source ;
106
107       ZFREE(p) ;
108    }
109 }
110
111
112 /*-- break and continue -------*/
113
114 typedef struct bc
115 {
116    struct bc *link ;             /* stack as linked list */
117    int type ;                    /* 'B' or 'C' or mark start with 0 */
118    int source_offset ;           /* position of _JMP  */
119 }
120 BC ;
121
122 static BC *bc_top ;
123
124
125
126 void
127 BC_new()                        /* mark the start of a loop */
128 {
129    BC_insert(0, (INST *) 0) ;
130 }
131
132 void
133 BC_insert(type, address)
134 int type ; INST *address ;
135 {
136    register BC *p ;
137
138    if (error_state)  return ;
139
140    if (type && !bc_top)
141    {
142       compile_error("%s statement outside of loop",
143                     type == 'B' ? "break" : "continue") ;
144
145       return ;
146    }
147    else
148    {
149       p = ZMALLOC(BC) ;
150       p->type = type ;
151       p->source_offset = address - code_base ;
152       p->link = bc_top ;
153       bc_top = p ;
154    }
155 }
156
157
158 /* patch all break and continues for one loop */
159 void
160 BC_clear(B_address, C_address)
161    INST *B_address, *C_address ;
162 {
163    register BC *p, *q ;
164    INST *source ;
165
166    if (error_state)  return ;
167
168    p = bc_top ;
169    /* pop down to the mark node */
170    while (p->type)
171    {
172       source = code_base + p->source_offset ;
173       source->op = (p->type == 'B' ? B_address : C_address)
174          - source ;
175
176       q = p ; p = p->link ; ZFREE(q) ;
177    }
178    /* remove the mark node */
179    bc_top = p->link ;
180    ZFREE(p) ;
181 }
182
183 /*-----  moving code --------------------------*/
184
185 /* a stack to hold some pieces of code while
186    reorganizing loops .
187 */
188
189 typedef struct mc
190 {                               /* mc -- move code */
191    struct mc *link ;
192    INST *code ;                  /* the save code */
193    unsigned len ;                /* its length */
194    int scope ;                   /* its scope */
195    int move_level ;              /* size of this stack when coded */
196    FBLOCK *fbp ;                 /* if scope FUNCT */
197    int offset ;                  /* distance from its code base */
198 }
199 MC ;
200
201 static MC *mc_top ;
202 int code_move_level = 0 ; /* see comment in jmp.h */
203
204 #define  NO_SCOPE       -1
205  /* means relocation of resolve list not needed */
206
207 void
208 code_push(code, len, scope, fbp)
209    INST *code ;
210    unsigned len ;
211    int scope ;
212    FBLOCK *fbp ;
213 {
214    register MC *p ;
215
216    if (!error_state)
217    {
218       p = ZMALLOC(MC) ;
219       p->len = len ;
220       p->link = mc_top ;
221       mc_top = p ;
222
223       if (len)
224       {
225          p->code = (INST *) zmalloc(sizeof(INST) * len) ;
226          memcpy(p->code, code, sizeof(INST) * len) ;
227       }
228       if (!resolve_list)  p->scope = NO_SCOPE ;
229       else
230       {
231          p->scope = scope ;
232          p->move_level = code_move_level ;
233          p->fbp = fbp ;
234          p->offset = code - code_base ;
235       }
236    }
237    code_move_level++ ;
238 }
239
240 /* copy the code at the top of the mc stack to target.
241    return the number of INSTs moved */
242
243 unsigned
244 code_pop(target)
245    INST *target ;
246 {
247    register MC *p ;
248    unsigned len ;
249    int target_offset ;
250
251    if (error_state)  return 0 ;
252
253 #ifdef  DEBUG
254    if (!mc_top)  bozo("mc underflow") ;
255 #endif
256
257    p = mc_top ; mc_top = p->link ;
258    len = p->len ;
259
260    while (target + len >= code_warn)
261    {
262       target_offset = target - code_base ;
263       code_grow() ;
264       target = code_base + target_offset ;
265    }
266
267    if (len)
268    {
269       memcpy(target, p->code, len * sizeof(INST)) ;
270       zfree(p->code, len * sizeof(INST)) ;
271    }
272
273    if (p->scope != NO_SCOPE)
274    {
275       target_offset = target - code_base ;
276       relocate_resolve_list(p->scope, p->move_level, p->fbp,
277                          p->offset, len, target_offset - p->offset) ;
278    }
279
280    ZFREE(p) ;
281    code_move_level-- ;
282    return len ;
283 }