Commit | Line | Data |
---|---|---|
a7e60862 WJ |
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 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 | ||
34 | extern unsigned compile_error_count ; | |
35 | #define error_state (compile_error_count>0) | |
36 | ||
37 | ||
38 | /*---------- back patching jumps ---------------*/ | |
39 | ||
40 | typedef struct jmp { | |
41 | struct jmp *link ; | |
42 | INST *source ; | |
43 | } JMP ; | |
44 | ||
45 | static JMP *jmp_top ; | |
46 | ||
47 | void 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 | ||
68 | void 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 | ||
89 | typedef struct bc { | |
90 | struct bc *link ; /* stack as linked list */ | |
91 | int type ; /* 'B' or 'C' or mark start with 0 */ | |
92 | INST *source ; /* position of _JMP */ | |
93 | } BC ; | |
94 | ||
95 | static BC *bc_top ; | |
96 | ||
97 | ||
98 | ||
99 | void BC_new() /* mark the start of a loop */ | |
100 | { | |
101 | BC_insert(0, (INST*) 0 ) ; | |
102 | } | |
103 | ||
104 | void 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 | ||
128 | void BC_clear(B_address, C_address) | |
129 | /* patch all break and continues for one loop */ | |
130 | INST *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 | ||
158 | typedef struct mc { /* mc -- move code */ | |
159 | struct mc *link ; | |
160 | INST *code ; | |
161 | unsigned len ; | |
162 | } MC ; | |
163 | ||
164 | static MC *mc_top ; | |
165 | ||
166 | ||
167 | void 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 | ||
190 | unsigned 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 | } |