| | 1 | #ifdef RCSID |
| | 2 | static char RCSid[] = |
| | 3 | "$Header: d:/cvsroot/tads/TADS2/EMT.C,v 1.2 1999/05/17 02:52:11 MJRoberts Exp $"; |
| | 4 | #endif |
| | 5 | |
| | 6 | /* |
| | 7 | * Copyright (c) 1991, 2002 Michael J. Roberts. All Rights Reserved. |
| | 8 | * |
| | 9 | * Please see the accompanying license file, LICENSE.TXT, for information |
| | 10 | * on using and copying this software. |
| | 11 | */ |
| | 12 | /* |
| | 13 | Name |
| | 14 | emt.c - emitter |
| | 15 | Function |
| | 16 | Code emitter |
| | 17 | Notes |
| | 18 | None |
| | 19 | Modified |
| | 20 | 09/23/91 MJRoberts - creation |
| | 21 | */ |
| | 22 | |
| | 23 | #include <assert.h> |
| | 24 | #include "os.h" |
| | 25 | #include "std.h" |
| | 26 | #include "emt.h" |
| | 27 | #include "opc.h" |
| | 28 | #include "err.h" |
| | 29 | #include "tok.h" |
| | 30 | |
| | 31 | void emtval(emtcxdef *ctx, tokdef *tok, uchar *base) |
| | 32 | { |
| | 33 | ushort oplen; |
| | 34 | |
| | 35 | switch(tok->toktyp) |
| | 36 | { |
| | 37 | case TOKTSYMBOL: |
| | 38 | switch(tok->toksym.tokstyp) |
| | 39 | { |
| | 40 | case TOKSTARGC: |
| | 41 | emtop(ctx, OPCARGC); |
| | 42 | return; |
| | 43 | |
| | 44 | case TOKSTSELF: |
| | 45 | emtop(ctx, OPCPUSHSELF); |
| | 46 | return; |
| | 47 | |
| | 48 | case TOKSTOBJ: |
| | 49 | case TOKSTFWDOBJ: |
| | 50 | emtop(ctx, OPCPUSHOBJ); |
| | 51 | break; |
| | 52 | case TOKSTLOCAL: |
| | 53 | if (tok->toksym.toksfr) |
| | 54 | { |
| | 55 | emtop(ctx, OPCGETDBLCL); /* debug local - specifies frame */ |
| | 56 | emtint2(ctx, ctx->emtcxfrob); /* emit frame object */ |
| | 57 | emtint2(ctx, tok->toksym.toksfr); /* emit frame offset */ |
| | 58 | } |
| | 59 | else |
| | 60 | emtop(ctx, OPCGETLCL); |
| | 61 | break; |
| | 62 | |
| | 63 | case TOKSTBIFN: |
| | 64 | emtop(ctx, OPCBUILTIN); |
| | 65 | emtbyte(ctx, 0); |
| | 66 | break; |
| | 67 | case TOKSTFUNC: |
| | 68 | case TOKSTFWDFN: |
| | 69 | emtop(ctx, OPCPUSHFN); |
| | 70 | break; |
| | 71 | case TOKSTPROP: |
| | 72 | emtop(ctx, OPCGETPSELF); |
| | 73 | emtbyte(ctx, 0); |
| | 74 | break; |
| | 75 | case TOKSTPROPSPEC: |
| | 76 | emtop(ctx, OPCGETPSELFDATA); |
| | 77 | break; |
| | 78 | default: |
| | 79 | errsig(ctx->emtcxerr, ERR_REQOBJ); |
| | 80 | /* NOTREACHED */ |
| | 81 | } |
| | 82 | emtint2(ctx, tok->toksym.toksval); |
| | 83 | return; |
| | 84 | |
| | 85 | case TOKTNUMBER: |
| | 86 | emtop(ctx, OPCPUSHNUM); |
| | 87 | emtint4(ctx, tok->tokval); |
| | 88 | return; |
| | 89 | |
| | 90 | case TOKTNIL: |
| | 91 | emtop(ctx, OPCPUSHNIL); |
| | 92 | return; |
| | 93 | case TOKTTRUE: |
| | 94 | emtop(ctx, OPCPUSHTRUE); |
| | 95 | return; |
| | 96 | |
| | 97 | case TOKTPOUND: |
| | 98 | emtop(ctx, OPCPUSHPN); |
| | 99 | emtint2(ctx, tok->tokofs); |
| | 100 | return; |
| | 101 | |
| | 102 | case TOKTSSTRING: |
| | 103 | emtop(ctx, OPCPUSHSTR); |
| | 104 | break; |
| | 105 | case TOKTDSTRING: |
| | 106 | emtop(ctx, OPCSAY); |
| | 107 | break; |
| | 108 | case TOKTLIST: |
| | 109 | emtop(ctx, OPCPUSHLST); |
| | 110 | emtlst(ctx, (uint)tok->tokofs, base); |
| | 111 | return; |
| | 112 | } |
| | 113 | |
| | 114 | /* if we haven't returned already, we have a large operand */ |
| | 115 | oplen = osrp2(base + tok->tokofs); |
| | 116 | emtmem(ctx, base + tok->tokofs, oplen); |
| | 117 | } |
| | 118 | |
| | 119 | /* emit a list value */ |
| | 120 | void emtlst(emtcxdef *ctx, uint ofs, uchar *base) |
| | 121 | { |
| | 122 | uint initofs; |
| | 123 | ushort i; |
| | 124 | emtlidef *lst; |
| | 125 | emtledef *ele; |
| | 126 | |
| | 127 | initofs = ctx->emtcxofs; /* save starting offset */ |
| | 128 | emtint2(ctx, 2); /* emit placeholder length */ |
| | 129 | if (ofs == 0) return; /* nothing more to do for empty list */ |
| | 130 | |
| | 131 | lst = (emtlidef *)(base + ofs); |
| | 132 | |
| | 133 | for (i = lst->emtlicnt, ele = &lst->emtliele[i-1] ; i ; --ele, --i) |
| | 134 | { |
| | 135 | uchar dat; |
| | 136 | |
| | 137 | switch(ele->emtletyp) |
| | 138 | { |
| | 139 | case TOKTLIST: |
| | 140 | emtbyte(ctx, DAT_LIST); |
| | 141 | emtlst(ctx, (uint)ele->emtleval, base); |
| | 142 | continue; |
| | 143 | |
| | 144 | case TOKTSSTRING: |
| | 145 | { |
| | 146 | uint oplen = osrp2(base + ele->emtleval); |
| | 147 | |
| | 148 | emtbyte(ctx, DAT_SSTRING); |
| | 149 | emtmem(ctx, base + ele->emtleval, oplen); |
| | 150 | continue; |
| | 151 | } |
| | 152 | |
| | 153 | case TOKTNUMBER: |
| | 154 | dat = DAT_NUMBER; |
| | 155 | break; |
| | 156 | case TOKTNIL: |
| | 157 | dat = DAT_NIL; |
| | 158 | break; |
| | 159 | case TOKTTRUE: |
| | 160 | dat = DAT_TRUE; |
| | 161 | break; |
| | 162 | |
| | 163 | case TOKTPOUND: |
| | 164 | dat = DAT_PROPNUM; |
| | 165 | goto symbol; |
| | 166 | case TOKTFUNCTION: |
| | 167 | dat = DAT_FNADDR; |
| | 168 | goto symbol; |
| | 169 | case TOKTOBJECT: |
| | 170 | dat = DAT_OBJECT; |
| | 171 | goto symbol; |
| | 172 | case TOKTDOT: |
| | 173 | dat = DAT_PROPNUM; |
| | 174 | /* FALLTHROUGH */ |
| | 175 | symbol: |
| | 176 | emtbyte(ctx, dat); |
| | 177 | emtint2(ctx, (ushort)ele->emtleval); |
| | 178 | continue; |
| | 179 | |
| | 180 | default: |
| | 181 | assert(FALSE); |
| | 182 | break; |
| | 183 | } |
| | 184 | |
| | 185 | /* if we get here, emit datatype in dat, plus value */ |
| | 186 | emtbyte(ctx, dat); |
| | 187 | if (dat != DAT_TRUE && dat != DAT_NIL) |
| | 188 | emtint4(ctx, ele->emtleval); |
| | 189 | } |
| | 190 | oswp2(ctx->emtcxptr + initofs, ctx->emtcxofs - initofs); |
| | 191 | } |
| | 192 | |
| | 193 | /* reserve space for code, expanding object if needed */ |
| | 194 | void emtres(emtcxdef *ctx, ushort bytes) |
| | 195 | { |
| | 196 | ushort oldsiz = mcmobjsiz(ctx->emtcxmem, ctx->emtcxobj); |
| | 197 | ushort need; |
| | 198 | |
| | 199 | need = ctx->emtcxofs + bytes + 1; |
| | 200 | |
| | 201 | if (need > oldsiz) |
| | 202 | { |
| | 203 | ushort newsiz; |
| | 204 | |
| | 205 | newsiz = need + EMTINC; |
| | 206 | if (newsiz < oldsiz) errsig(ctx->emtcxerr, ERR_OBJOVF); |
| | 207 | ctx->emtcxptr = mcmrealo(ctx->emtcxmem, ctx->emtcxobj, newsiz); |
| | 208 | assert(mcmobjsiz(ctx->emtcxmem, ctx->emtcxobj) >= need); |
| | 209 | } |
| | 210 | } |
| | 211 | |
| | 212 | /* get a new temporary label */ |
| | 213 | uint emtglbl(emtcxdef *ctx) |
| | 214 | { |
| | 215 | uint ret = ctx->emtcxlfre; |
| | 216 | |
| | 217 | if (ctx->emtcxlfre == EMTLLNKEND) errsig(ctx->emtcxerr, ERR_NOLBL); |
| | 218 | ctx->emtcxlfre = ctx->emtcxlbl[ret].emtllnk; |
| | 219 | ctx->emtcxlbl[ret].emtllnk = EMTLLNKEND; /* nothing in label's list */ |
| | 220 | ctx->emtcxlbl[ret].emtlflg = 0; /* label is not yet set */ |
| | 221 | return(ret); |
| | 222 | } |
| | 223 | |
| | 224 | /* get a new label and set to the current position */ |
| | 225 | uint emtgslbl(emtcxdef *ctx) |
| | 226 | { |
| | 227 | uint ret = ctx->emtcxlfre; |
| | 228 | |
| | 229 | if (ctx->emtcxlfre == EMTLLNKEND) errsig(ctx->emtcxerr, ERR_NOLBL); |
| | 230 | ctx->emtcxlfre = ctx->emtcxlbl[ret].emtllnk; |
| | 231 | ctx->emtcxlbl[ret].emtllnk = EMTLLNKEND; /* nothing in label's list */ |
| | 232 | ctx->emtcxlbl[ret].emtlflg = EMTLFSET; /* label is not yet set */ |
| | 233 | ctx->emtcxlbl[ret].emtlofs = ctx->emtcxofs; /* set position */ |
| | 234 | return(ret); |
| | 235 | } |
| | 236 | |
| | 237 | /* set a temporary label */ |
| | 238 | void emtslbl(emtcxdef *ctx, noreg uint *lblp, int release) |
| | 239 | { |
| | 240 | uint lbl = *lblp; |
| | 241 | emtldef *p = &ctx->emtcxlbl[lbl]; |
| | 242 | uint fwd; |
| | 243 | emtldef *fwdp; |
| | 244 | ushort nxt; |
| | 245 | short diff; |
| | 246 | ushort curpos = ctx->emtcxofs; |
| | 247 | |
| | 248 | p->emtlofs = curpos; |
| | 249 | p->emtlflg |= EMTLFSET; |
| | 250 | |
| | 251 | /* run through forward reference list, fixing up each reference */ |
| | 252 | for (fwd = p->emtllnk ; fwd != EMTLLNKEND ; fwd = nxt) |
| | 253 | { |
| | 254 | fwdp = &ctx->emtcxlbl[fwd]; /* get pointer to current record */ |
| | 255 | nxt = fwdp->emtllnk; /* remember the next record */ |
| | 256 | |
| | 257 | /* write the fixup, and release the forward reference */ |
| | 258 | diff = curpos - fwdp->emtlofs; |
| | 259 | oswp2(ctx->emtcxptr + fwdp->emtlofs, diff); |
| | 260 | fwdp->emtllnk = EMTLLNKEND; |
| | 261 | emtdlbl(ctx, &fwd); |
| | 262 | } |
| | 263 | |
| | 264 | p->emtllnk = EMTLLNKEND; /* there are no more forward refs for label */ |
| | 265 | if (release) emtdlbl(ctx, lblp); |
| | 266 | } |
| | 267 | |
| | 268 | /* release a temporary label */ |
| | 269 | void emtdlbl(emtcxdef *ctx, noreg uint *lblp) |
| | 270 | { |
| | 271 | /* if label has forward references, internal error: label never set */ |
| | 272 | if (ctx->emtcxlbl[*lblp].emtllnk != EMTLLNKEND) |
| | 273 | errsig(ctx->emtcxerr, ERR_LBNOSET); |
| | 274 | |
| | 275 | ctx->emtcxlbl[*lblp].emtllnk = ctx->emtcxlfre; |
| | 276 | ctx->emtcxlfre = *lblp; |
| | 277 | *lblp = EMTLLNKEND; |
| | 278 | } |
| | 279 | |
| | 280 | /* clear a temporary label without error checking */ |
| | 281 | void emtclbl(emtcxdef *ctx, noreg uint *lblp) |
| | 282 | { |
| | 283 | emtslbl(ctx, lblp, TRUE); /* clear up forward ref's, and delete */ |
| | 284 | } |
| | 285 | |
| | 286 | /* emit a jump to a temporary label */ |
| | 287 | void emtjmp(emtcxdef *ctx, uchar op, uint lbl) |
| | 288 | { |
| | 289 | emtldef *p = &ctx->emtcxlbl[lbl]; |
| | 290 | short diff; |
| | 291 | uint fwd; |
| | 292 | |
| | 293 | emtop(ctx, op); |
| | 294 | |
| | 295 | if (p->emtlflg & EMTLFSET) |
| | 296 | diff = p->emtlofs - ctx->emtcxofs; /* back ref - compute delta */ |
| | 297 | else |
| | 298 | { |
| | 299 | diff = 0; |
| | 300 | fwd = emtglbl(ctx); /* get a forward ref fixup reminder */ |
| | 301 | ctx->emtcxlbl[fwd].emtllnk = p->emtllnk; /* link into label's list */ |
| | 302 | ctx->emtcxlbl[fwd].emtlofs = ctx->emtcxofs; /* remember where */ |
| | 303 | p->emtllnk = fwd; /* make it new head of this label's list */ |
| | 304 | } |
| | 305 | emtint2(ctx, diff); |
| | 306 | } |
| | 307 | |
| | 308 | /* set up the labels - put all in free list */ |
| | 309 | void emtlini(emtcxdef *ctx) |
| | 310 | { |
| | 311 | int i; |
| | 312 | emtldef *p; |
| | 313 | int max; |
| | 314 | |
| | 315 | for (max = ctx->emtcxlcnt, i = 1, p = ctx->emtcxlbl ; i < max ; ++p, ++i) |
| | 316 | p->emtllnk = i; |
| | 317 | p->emtllnk = EMTLLNKEND; |
| | 318 | ctx->emtcxlfre = 0; |
| | 319 | } |