Commit | Line | Data |
---|---|---|
ce996e48 | 1 | /* Copyright (c) 1980 Regents of the University of California */ |
451260e7 | 2 | static char sccsid[] = "@(#)asscan.c 4.3 %G%"; |
ce996e48 | 3 | #include <stdio.h> |
ce996e48 BJ |
4 | #include "as.h" |
5 | #include "asscan.h" | |
6 | ||
7 | /* | |
8 | * NOTE: | |
9 | * This version of the assembler does not use fread and fwrite | |
10 | * for the token buffering. The token buffers are integrals of BUFSIZ | |
11 | * at all times, so we use direct read and write. fread and fwrite | |
12 | * as supplied from BTL in stdio are HORRENDOUSLY inefficient, | |
13 | * as they use putchar for each character, nested two deep in loops. | |
14 | */ | |
15 | #define writeTEST(pointer, size, nelements, ioptr) \ | |
16 | write(ioptr->_file, pointer, nelements * size) != nelements * size | |
17 | ||
18 | #define readTEST(pointer, size, nelements, ioptr) \ | |
19 | read(ioptr->_file, pointer, nelements * size) != nelements * size | |
20 | /* | |
21 | * Variables to manage the token buffering. | |
22 | * We scan (lexically analyze) a large number of tokens, and | |
23 | * then parse all of the tokens in the scan buffer. | |
24 | * This reduces procedure call overhead when the parser | |
25 | * demands a token, allows for an efficient reread during | |
26 | * the second pass, and confuses the line number reporting | |
27 | * for errors encountered in the scanner and in the parser. | |
28 | */ | |
29 | #define TOKDALLOP 8 | |
30 | struct tokbufdesc *bufstart; /*where the buffer list begins*/ | |
31 | struct tokbufdesc *buftail; /*last one on the list*/ | |
32 | struct tokbufdesc *emptybuf; /*the one being filled*/ | |
33 | /* | |
34 | * If we are using VM, during the second pass we reclaim the used | |
35 | * token buffers for saving the relocation information | |
36 | */ | |
37 | struct tokbufdesc *tok_free; /* free pool */ | |
38 | struct tokbufdesc *tok_temp; /* temporary for doing list manipulation */ | |
39 | /* | |
40 | * Other token buffer managers | |
41 | */ | |
42 | int bufno; /*which buffer number: 0,1 for tmp file*/ | |
43 | struct tokbufdesc tokbuf[2]; /*our initial increment of buffers*/ | |
44 | ptrall tokptr; /*where the current token comes from*/ | |
45 | ptrall tokub; /*the last token in the current token buffer*/ | |
46 | ||
47 | /* | |
48 | * Variables to manage the string buffering | |
49 | * declared in asscan.h. | |
50 | */ | |
51 | int strno; /*the current string being filled*/ | |
52 | struct strdesc strbuf[3]; /*the string buffers; the first for nulls*/ | |
53 | struct strdesc *strptr; /*current string buffer being filled*/ | |
54 | ||
55 | inittmpfile() | |
56 | { | |
57 | if (passno == 1){ | |
58 | if (useVM){ | |
59 | bufstart = &tokbuf[0]; | |
60 | buftail = &tokbuf[1]; | |
61 | bufstart->tok_next = buftail; | |
62 | buftail->tok_next = 0; | |
63 | } | |
64 | tokbuf[0].tok_count = -1; | |
65 | tokbuf[1].tok_count = -1; | |
66 | } | |
67 | tok_temp = 0; | |
68 | tok_free = 0; | |
69 | bufno = 0; | |
70 | emptybuf = &tokbuf[bufno]; | |
71 | tokptr = 0; | |
72 | tokub = 0; | |
73 | } | |
74 | ||
75 | closetmpfile() | |
76 | { | |
77 | if (passno == 1){ | |
78 | if (useVM){ | |
79 | emptybuf->toks[emptybuf->tok_count++] = PARSEEOF; | |
80 | } else { | |
81 | /* | |
82 | * Clean up the buffers that haven't been | |
83 | * written out yet | |
84 | */ | |
85 | if (tokbuf[bufno ^ 1].tok_count >= 0){ | |
86 | if (writeTEST((char *)&tokbuf[bufno ^ 1], sizeof *emptybuf, 1, tmpfil)){ | |
87 | badwrite: | |
88 | yyerror("Unexpected end of file writing the interpass tmp file"); | |
89 | exit(2); | |
90 | } | |
91 | } | |
92 | /* | |
93 | * Ensure that we will read an End of file, | |
94 | * if there are more than one file names | |
95 | * in the argument list | |
96 | */ | |
97 | tokbuf[bufno].toks[tokbuf[bufno].tok_count++] = PARSEEOF; | |
98 | if (writeTEST((char *)&tokbuf[bufno], sizeof *emptybuf, 1, tmpfil)) | |
99 | goto badwrite; | |
100 | } | |
101 | } /*end of being pass 1*/ | |
102 | } | |
103 | ||
104 | #define bstrlg(from, length) \ | |
105 | *(lgtype *)from = length; \ | |
106 | (char *)from += sizeof(lgtype) + length | |
107 | ||
108 | #define bstrfromto(from,to) \ | |
109 | *(lgtype *)from = (char *)to - (char *)from - sizeof(lgtype); \ | |
110 | (char *)from += sizeof(lgtype) + (char *)to - (char *)from | |
111 | ||
112 | #define eatstrlg(from) \ | |
113 | (char *)from += sizeof(lgtype) + *(lgtype *)from | |
114 | ||
115 | #define bskiplg(from, length) \ | |
116 | *(lgtype *)from = length; \ | |
117 | (char *)from += sizeof(lgtype) + length | |
118 | ||
119 | #define bskipfromto(from, to) \ | |
120 | *(lgtype *)from = (toktype *)to - (toktype *)from - sizeof(lgtype); \ | |
121 | (char *)from += sizeof (lgtype) + (toktype *)to - (toktype *)from | |
122 | ||
123 | #define eatskiplg(from) \ | |
124 | (toktype *)from += sizeof(lgtype) + *(lgtype *)from | |
125 | ||
126 | #ifdef DEBUG | |
127 | ptrall firsttoken; | |
128 | #endif DEBUG | |
129 | ||
130 | extern int yylval; /*global communication with parser*/ | |
451260e7 | 131 | static int Lastjxxx; /*this ONLY shuts up cc; see below*/ |
ce996e48 BJ |
132 | |
133 | toktype yylex() | |
134 | { | |
135 | register ptrall bufptr; | |
136 | register toktype val; | |
137 | register struct exp *locxp; | |
138 | ||
139 | bufptr = tokptr; /*copy in the global value*/ | |
140 | top: | |
141 | if (bufptr < tokub){ | |
142 | gtoken(val, bufptr); | |
143 | switch(yylval = val){ | |
144 | case PARSEEOF : | |
145 | yylval = val = PARSEEOF; | |
146 | break; | |
147 | case BFINT: | |
148 | case INT: | |
149 | if (xp >= &explist[NEXP]) | |
150 | yyerror("Too many expressions; try simplyfing"); | |
151 | else | |
152 | locxp = xp++; | |
451260e7 RH |
153 | glong(locxp->e_xvalue, bufptr); |
154 | locxp->e_yvalue = 0; | |
ce996e48 | 155 | makevalue: |
451260e7 RH |
156 | locxp->e_xtype = XABS; |
157 | locxp->e_xloc = 0; | |
158 | locxp->e_xname = NULL; | |
ce996e48 BJ |
159 | yylval = (int)locxp; |
160 | break; | |
161 | case FLTNUM: | |
162 | if (xp >= &explist[NEXP]) | |
163 | yyerror("Too many expressions; try simplyfing"); | |
164 | else | |
165 | locxp = xp++; | |
166 | gdouble( ( (union Double *)locxp)->dvalue, bufptr); | |
167 | goto makevalue; | |
168 | case QUAD: | |
169 | if (xp >= &explist[NEXP]) | |
170 | yyerror("Too many expressions; try simplyfing"); | |
171 | else | |
172 | locxp = xp++; | |
451260e7 RH |
173 | glong(locxp->e_xvalue, bufptr); |
174 | glong(locxp->e_yvalue, bufptr); | |
ce996e48 BJ |
175 | yylval = val = INT; |
176 | goto makevalue; | |
177 | case NAME: | |
178 | gptr(yylval, bufptr); | |
179 | lastnam = (struct symtab *)yylval; | |
180 | break; | |
181 | case SIZESPEC: | |
182 | case REG: | |
183 | case INSTn: | |
184 | case INST0: | |
185 | gchar(yylval, bufptr); | |
186 | break; | |
187 | case IJXXX: | |
188 | gchar(yylval, bufptr); | |
451260e7 RH |
189 | /* We can't cast Lastjxxx into (int *) here.. */ |
190 | gptr(Lastjxxx, bufptr); | |
191 | lastjxxx = (struct symtab *)Lastjxxx; | |
ce996e48 BJ |
192 | break; |
193 | case ILINESKIP: | |
194 | gint(yylval, bufptr); | |
195 | lineno += yylval; | |
196 | goto top; | |
197 | case SKIP: | |
198 | eatskiplg(bufptr); | |
199 | goto top; | |
200 | case VOID: | |
201 | goto top; | |
202 | case STRING: | |
203 | strptr = &strbuf[strno ^= 1]; | |
204 | strptr->str_lg = *((lgtype *)bufptr); | |
205 | movestr(&strptr->str[0], | |
206 | (char *)bufptr + sizeof(lgtype), | |
207 | strptr->str_lg); | |
208 | eatstrlg(bufptr); | |
209 | yylval = (int)strptr; | |
210 | break; | |
211 | case ISTAB: | |
212 | case ISTABSTR: | |
213 | case ISTABNONE: | |
214 | case ISTABDOT: | |
215 | case IALIGN: | |
216 | gptr(yylval, bufptr); | |
217 | break; | |
218 | } | |
219 | #ifdef DEBUG | |
220 | if (toktrace){ | |
221 | char *tok_to_name(); | |
222 | printf("P: %d T#: %4d, %s ", | |
223 | passno, bufptr - firsttoken, tok_to_name(val)); | |
224 | switch(val){ | |
225 | case INT: printf("val %d", | |
451260e7 | 226 | ((struct exp *)yylval)->e_xvalue); |
ce996e48 BJ |
227 | break; |
228 | case BFINT: printf("val %d", | |
451260e7 | 229 | ((struct exp *)yylval)->e_xvalue); |
ce996e48 BJ |
230 | break; |
231 | case QUAD: printf("val[msd] = 0x%x, val[lsd] = 0x%x.", | |
451260e7 RH |
232 | ((struct exp *)yylval)->e_xvalue, |
233 | ((struct exp *)yylval)->e_yvalue); | |
ce996e48 BJ |
234 | break; |
235 | case FLTNUM: printf("value %20.17f", | |
236 | ((union Double *)yylval)->dvalue); | |
237 | break; | |
238 | case NAME: printf("\"%.8s\"", | |
451260e7 | 239 | ((struct symtab *)yylval)->s_name); |
ce996e48 BJ |
240 | break; |
241 | case REG: printf(" r%d", | |
242 | yylval); | |
243 | break; | |
244 | case IJXXX: | |
245 | case INST0: | |
246 | case INSTn: printf("%.8s", | |
451260e7 | 247 | itab[0xFF &yylval]->s_name); |
ce996e48 BJ |
248 | break; |
249 | case STRING: printf("length %d ", | |
250 | ((struct strdesc *)yylval)->str_lg); | |
251 | printf("value\"%s\"", | |
252 | ((struct strdesc *)yylval)->str); | |
253 | break; | |
254 | } /*end of the debug switch*/ | |
255 | printf("\n"); | |
256 | } | |
257 | #endif DEBUG | |
258 | ||
259 | } else { /* start a new buffer */ | |
260 | if (useVM){ | |
261 | if (passno == 2){ | |
262 | tok_temp = emptybuf->tok_next; | |
263 | emptybuf->tok_next = tok_free; | |
264 | tok_free = emptybuf; | |
265 | emptybuf = tok_temp; | |
266 | } else { | |
267 | emptybuf = emptybuf->tok_next; | |
268 | } | |
269 | bufno += 1; | |
270 | if (emptybuf == 0){ | |
271 | struct tokbufdesc *newdallop; | |
272 | int i; | |
273 | if (passno == 2) | |
274 | goto badread; | |
275 | emptybuf = newdallop = (struct tokbufdesc *) | |
276 | Calloc(TOKDALLOP, sizeof (struct tokbufdesc)); | |
277 | for (i=0; i < TOKDALLOP; i++){ | |
278 | buftail->tok_next = newdallop; | |
279 | buftail = newdallop; | |
280 | newdallop += 1; | |
281 | } | |
282 | buftail->tok_next = 0; | |
283 | } /*end of need to get more buffers*/ | |
284 | (toktype *)bufptr = &(emptybuf->toks[0]); | |
285 | if (passno == 1) | |
286 | scan_dot_s(emptybuf); | |
287 | } else { /*don't use VM*/ | |
288 | bufno ^= 1; | |
289 | emptybuf = &tokbuf[bufno]; | |
290 | ((toktype *)bufptr) = &(emptybuf->toks[0]); | |
291 | if (passno == 1){ | |
292 | /* | |
293 | * First check if there are things to write | |
294 | * out at all | |
295 | */ | |
296 | if (emptybuf->tok_count >= 0){ | |
297 | if (writeTEST((char *)emptybuf, sizeof *emptybuf, 1, tmpfil)){ | |
298 | badwrite: | |
299 | yyerror("Unexpected end of file writing the interpass tmp file"); | |
300 | exit(2); | |
301 | } | |
302 | } | |
303 | scan_dot_s(emptybuf); | |
304 | } else { /*pass 2*/ | |
305 | if (readTEST((char *)emptybuf, sizeof *emptybuf, 1, tmpfil)){ | |
306 | badread: | |
307 | yyerror("Unexpected end of file while reading the interpass tmp file"); | |
308 | exit(1); | |
309 | } | |
310 | } | |
311 | } /*end of using a real live file*/ | |
312 | (char *)tokub = (char *)bufptr + emptybuf->tok_count; | |
313 | #ifdef DEBUG | |
314 | firsttoken = bufptr; | |
315 | if (debug) | |
316 | printf("created buffernumber %d with %d tokens\n", | |
317 | bufno, emptybuf->tok_count); | |
318 | #endif DEBUG | |
319 | goto top; | |
320 | } /*end of reading/creating a new buffer*/ | |
321 | tokptr = bufptr; /*copy back the global value*/ | |
322 | return(val); | |
323 | } /*end of yylex*/ | |
324 | ||
325 | ||
326 | buildskip(from, to) | |
327 | register ptrall from, to; | |
328 | { | |
329 | int diff; | |
330 | register int frombufno; | |
331 | register struct tokbufdesc *middlebuf; | |
332 | /* | |
333 | * check if from and to are in the same buffer | |
334 | * from and to DIFFER BY AT MOST 1 buffer and to is | |
335 | * always ahead of from, with to being in the buffer emptybuf | |
336 | * points to. | |
337 | * The hard part here is accounting for the case where the | |
338 | * skip is to cross a buffer boundary; we must construct | |
339 | * two skips. | |
340 | * | |
341 | * Figure out where the buffer boundary between from and to is | |
342 | * It's easy in VM, as buffers increase to high memory, but | |
343 | * w/o VM, we alternate between two buffers, and want | |
344 | * to look at the exact middle of the contiguous buffer region. | |
345 | */ | |
346 | middlebuf = useVM ? emptybuf : &tokbuf[1]; | |
347 | if ( ( (toktype *)from > (toktype *)middlebuf) | |
348 | ^ ( (toktype *)to > (toktype *)middlebuf) | |
349 | ){ /*split across a buffer boundary*/ | |
350 | ptoken(from, SKIP); | |
351 | /* | |
352 | * Set the skip so it lands someplace beyond | |
353 | * the end of this buffer. | |
354 | * When we pull this skip out in the second pass, | |
355 | * we will temporarily move the current pointer | |
356 | * out beyond the end of the buffer, but immediately | |
357 | * do a compare and fail the compare, and then reset | |
358 | * all the pointers correctly to point into the next buffer. | |
359 | */ | |
360 | bskiplg(from, TOKBUFLG + 1); | |
361 | /* | |
362 | * Now, force from to be in the same buffer as to | |
363 | */ | |
364 | (toktype *)from = (toktype *)&(emptybuf->toks[0]); | |
365 | } | |
366 | /* | |
367 | * Now, to and from are in the same buffer | |
368 | */ | |
369 | if (from > to) | |
370 | yyerror("Internal error: bad skip construction"); | |
371 | else { | |
372 | if ( (diff = (toktype *)to - (toktype *)from) >= | |
373 | (sizeof(toktype) + sizeof(lgtype) + 1)) { | |
374 | ptoken(from, SKIP); | |
375 | bskipfromto(from, to); | |
376 | } else { | |
377 | for ( ; diff > 0; --diff) | |
378 | ptoken(from, VOID); | |
379 | } | |
380 | } | |
381 | } | |
382 | ||
383 | movestr(to, from, lg) | |
384 | register char *to, *from; | |
385 | register int lg; | |
386 | { | |
387 | if (lg <= 0) return; | |
388 | do | |
389 | *to++ = *from++; | |
390 | while (--lg); | |
391 | } | |
392 | static int newfflag = 0; | |
393 | static char *newfname; | |
394 | int scanlineno; /*the scanner's linenumber*/ | |
395 | ||
396 | new_dot_s(namep) | |
397 | char *namep; | |
398 | { | |
399 | newfflag = 1; | |
400 | newfname = namep; | |
401 | dotsname = namep; | |
402 | lineno = 1; | |
403 | scanlineno = 1; | |
404 | } | |
405 | ||
406 | /* | |
407 | * Maps characters to their use in assembly language | |
408 | */ | |
409 | #define EOFCHAR (-1) | |
410 | #define NEEDCHAR (-2) | |
411 | ||
412 | readonly short type[] = { | |
413 | NEEDSBUF, /*fill up the input buffer*/ | |
414 | SCANEOF, /*hit the hard end of file*/ | |
415 | SP, BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR, /*\0..^G*/ | |
416 | BADCHAR,SP, NL, BADCHAR,BADCHAR,SP, BADCHAR,BADCHAR, /*BS..SI*/ | |
417 | BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR, /*DLE..ETB*/ | |
418 | BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR, /*CAN..US*/ | |
419 | SP, ORNOT, DQ, SH, LITOP, REGOP, AND, SQ, /*sp .. '*/ | |
420 | LP, RP, MUL, PLUS, CM, MINUS, ALPH, DIV, /*( .. /*/ | |
421 | DIG, DIG, DIG, DIG, DIG, DIG, DIG, DIG, /*0 .. 7*/ | |
422 | DIG, DIG, COLON, SEMI, LSH, BADCHAR,RSH, BADCHAR, /*8 .. ?*/ | |
423 | BADCHAR,ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,/*@ .. G*/ | |
424 | ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,/*H .. BADCHAR*/ | |
425 | ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,/*P .. V*/ | |
426 | ALPH, ALPH, ALPH, LB, BADCHAR,RB, XOR, ALPH,/*W .. _*/ | |
427 | SIZEQUOTE,ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,/*` .. g*/ | |
428 | ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,/*h .. o*/ | |
429 | ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,/*p .. v*/ | |
430 | ALPH, ALPH, ALPH, BADCHAR,IOR, BADCHAR,TILDE, BADCHAR,/*x .. del*/ | |
431 | }; | |
432 | ||
433 | /* | |
434 | * The table of possible uses for each character to test set inclusion. | |
435 | * Different than the above table, which knows about tokens yylex | |
436 | * is to return. | |
437 | */ | |
438 | #define HEXFLAG 01 /* 'x' or 'X' */ | |
439 | #define HEXLDIGIT 02 /* 'a' .. 'f' */ | |
6cca131f | 440 | #define HEXUDIGIT 04 /* 'A' .. 'F' */ |
ce996e48 | 441 | #define ALPHA 010 /* 'A' .. 'Z', 'a' .. 'z', '_'*/ |
6cca131f | 442 | #define DIGIT 020 /* '0' .. '9' */ |
ce996e48 | 443 | #define FLOATEXP 040 /* 'd' 'e' 'D' 'E' */ |
6cca131f RH |
444 | #define SIGN 0100 /* '+' .. '-'*/ |
445 | #define REGDIGIT 0200 /* '0' .. '5' */ | |
446 | #define SZSPECBEGIN 0400 /* 'b', 'B', 'l', 'L', 'w', 'W' */ | |
447 | #define POINT 01000 /* '.' */ | |
448 | #define SPACE 02000 /* '\t' or ' ' */ | |
449 | #define BSESCAPE 04000 /* bnrtf */ | |
450 | #define STRESCAPE 010000 /* '"', '\\', '\n' */ | |
451 | #define OCTDIGIT 020000 /* '0' .. '7' */ | |
ce996e48 BJ |
452 | #define FLOATFLAG 040000 /* 'd', 'D', 'f', 'F' */ |
453 | /*after leading 0*/ | |
454 | ||
455 | readonly short charsets[] = { | |
456 | 0, 0, 0, 0, 0, 0, 0, 0, /*\0..^G*/ | |
457 | 0, SPACE, STRESCAPE,0, 0, 0, 0, 0, /*BS..SI*/ | |
458 | 0, 0, 0, 0, 0, 0, 0, 0, /*DLE..ETB*/ | |
459 | 0, 0, 0, 0, 0, 0, 0, 0, /*CAN..US*/ | |
460 | /* dollar is an alpha character */ | |
461 | SPACE, 0, STRESCAPE,0, ALPHA, 0, 0, 0, /*sp.. '*/ | |
462 | 0, 0, 0, SIGN, 0, SIGN, POINT+ALPHA,0, /*( .. /*/ | |
463 | DIGIT+REGDIGIT+OCTDIGIT, DIGIT+REGDIGIT+OCTDIGIT, /*0..1*/ | |
464 | DIGIT+REGDIGIT+OCTDIGIT, DIGIT+REGDIGIT+OCTDIGIT, /*2..3*/ | |
465 | DIGIT+REGDIGIT+OCTDIGIT, DIGIT+REGDIGIT+OCTDIGIT, /*4..5*/ | |
466 | DIGIT+OCTDIGIT, DIGIT+OCTDIGIT, /*6..7*/ | |
467 | DIGIT, DIGIT, 0, 0, 0, 0, 0, 0, /*8..?*/ | |
468 | 0, /*@*/ | |
469 | ALPHA+HEXUDIGIT,ALPHA+HEXUDIGIT+SZSPECBEGIN, /*A..B*/ | |
470 | ALPHA+HEXUDIGIT,ALPHA+HEXUDIGIT+FLOATEXP+FLOATFLAG, /*C..D*/ | |
471 | ALPHA+HEXUDIGIT+FLOATEXP,ALPHA+HEXUDIGIT+FLOATFLAG, /*E..F*/ | |
472 | ALPHA, /*G*/ | |
473 | ALPHA, ALPHA, ALPHA, ALPHA, /*H..K*/ | |
474 | ALPHA+SZSPECBEGIN, ALPHA, ALPHA, ALPHA, /*L..O*/ | |
475 | ALPHA, ALPHA, ALPHA, ALPHA, /*P..S*/ | |
476 | ALPHA, ALPHA, ALPHA, ALPHA+SZSPECBEGIN, /*T..W*/ | |
477 | ALPHA+HEXFLAG, ALPHA, ALPHA, 0,STRESCAPE,0, 0, ALPHA,/*X.._*/ | |
478 | ||
479 | 0, | |
480 | ALPHA+HEXLDIGIT,ALPHA+HEXLDIGIT+BSESCAPE+SZSPECBEGIN, /*a..b*/ | |
481 | ALPHA+HEXLDIGIT,ALPHA+HEXLDIGIT+FLOATEXP+FLOATFLAG, /*c..d*/ | |
482 | ALPHA+HEXLDIGIT+FLOATEXP,ALPHA+HEXLDIGIT+BSESCAPE+FLOATFLAG, /*e..f*/ | |
483 | ALPHA, /*g*/ | |
484 | ALPHA, ALPHA, ALPHA, ALPHA, /*h..k*/ | |
485 | ALPHA+SZSPECBEGIN, ALPHA, ALPHA+BSESCAPE, ALPHA, /*l..o*/ | |
486 | ALPHA, ALPHA, ALPHA+BSESCAPE, ALPHA, /*p..s*/ | |
487 | ALPHA+BSESCAPE, ALPHA, ALPHA, ALPHA+SZSPECBEGIN,/*t..w*/ | |
488 | ALPHA+HEXFLAG, ALPHA, ALPHA, 0,0, 0, 0, 0, /*x..del*/ | |
489 | 0}; | |
490 | ||
6cca131f | 491 | #define INCHARSET(val, kind) (charsets[val] & (kind) ) |
ce996e48 BJ |
492 | static toktype oval = NL; |
493 | ||
494 | #define NINBUFFERS 2 | |
495 | #define INBUFLG NINBUFFERS*BUFSIZ + 2 | |
496 | /* | |
497 | * We have two input buffers; the first one is reserved | |
498 | * for catching the tail of a line split across a buffer | |
499 | * boundary; the other one are used for snarfing a buffer | |
500 | * worth of .s source. | |
501 | */ | |
502 | static char inbuffer[INBUFLG]; | |
503 | static char *InBufPtr = 0; | |
504 | ||
6cca131f RH |
505 | #ifdef getchar |
506 | #undef getchar | |
ce996e48 | 507 | #endif |
6cca131f | 508 | #define getchar() *inbufptr++ |
ce996e48 | 509 | |
6cca131f RH |
510 | #ifdef ungetc |
511 | #undef ungetc | |
ce996e48 BJ |
512 | #endif |
513 | #define ungetc(char) *--inbufptr = char | |
514 | ||
515 | /* | |
516 | * fill the inbuffer from the standard input. | |
517 | * Assert: there are always n COMPLETE! lines in the buffer area. | |
518 | * Assert: there is always a \n terminating the last line | |
519 | * in the buffer area. | |
520 | * Assert: after the \n, there is an EOFCHAR (hard end of file) | |
521 | * or a NEEDCHAR (end of buffer) | |
522 | * Assert: fgets always null pads the string it reads. | |
523 | * Assert: no ungetc's are done at the end of a line or at the | |
524 | * beginning of a line. | |
525 | * | |
526 | * We read a complete buffer of characters in one single read. | |
527 | * We then back scan within this buffer to find the end of the | |
528 | * last complete line, and force the assertions, and save a pointer | |
529 | * to the incomplete line. | |
530 | * The next call to fillinbuffer will move the unread characters | |
531 | * to the end of the first buffer, and then read another two buffers, | |
532 | * completing the cycle. | |
533 | */ | |
534 | ||
535 | static char p_swapped = '\0'; | |
536 | static char *p_start = &inbuffer[NINBUFFERS * BUFSIZ]; | |
537 | static char *p_stop = &inbuffer[NINBUFFERS * BUFSIZ]; | |
538 | char *fillinbuffer() | |
539 | { | |
540 | register char *to; | |
541 | register char *from; | |
542 | char *inbufptr; | |
543 | int nread; | |
544 | ||
545 | *p_start = p_swapped; | |
546 | inbufptr = &inbuffer[1*BUFSIZ] - (p_stop - p_start); | |
547 | ||
548 | for (to = inbufptr, from = p_start; from < p_stop;) | |
549 | *to++ = *from++; | |
550 | /* | |
551 | * Now, go read two full buffers (hopefully) | |
552 | */ | |
553 | nread = read(stdin->_file, &inbuffer[1*BUFSIZ], (NINBUFFERS - 1)*BUFSIZ); | |
554 | if (nread == 0) | |
555 | return(0); | |
556 | p_stop = from = &inbuffer[1*BUFSIZ + nread]; | |
557 | *from = '\0'; | |
558 | while (*--from != '\n') /* back over the partial line */ | |
559 | continue; | |
560 | from++; /* first char of partial line */ | |
561 | p_start = from; | |
562 | p_swapped = *p_start; | |
563 | *p_start = NEEDCHAR; /* force assertion */ | |
564 | return(inbufptr); | |
565 | } | |
566 | ||
567 | scan_dot_s(bufferbox) | |
568 | struct tokbufdesc *bufferbox; | |
569 | { | |
570 | register int yylval;/*lexical value*/ | |
571 | register toktype val; /*the value returned; the character read*/ | |
572 | register int base; /*the base of the number also counter*/ | |
573 | register char *cp; | |
574 | register char *inbufptr; | |
575 | register struct symtab *op; | |
576 | register unsigned char tag; | |
577 | int forb; | |
578 | ||
579 | register ptrall bufptr; /*where to stuff tokens*/ | |
580 | ptrall lgbackpatch; /*where to stuff a string length*/ | |
581 | ptrall bufub; /*where not to stuff tokens*/ | |
582 | register int maxstrlg; /*how long a string can be*/ | |
583 | long intval; /*value of int*/ | |
584 | char fltchr[64]; /*buffer for floating values*/ | |
585 | union Double fltval; /*floating value returned*/ | |
586 | struct Quad quadval; /*quad returned from immediate constant */ | |
587 | int linescrossed; /*when doing strings and comments*/ | |
588 | ||
589 | (toktype *)bufptr = (toktype *) & (bufferbox->toks[0]); | |
590 | (toktype *)bufub = &(bufferbox->toks[AVAILTOKS]); | |
591 | ||
592 | inbufptr = InBufPtr; | |
593 | if (inbufptr == 0){ | |
594 | inbufptr = fillinbuffer(); | |
595 | if (inbufptr == 0){ /*end of file*/ | |
596 | endoffile: | |
597 | inbufptr = 0; | |
598 | ptoken(bufptr, PARSEEOF); | |
599 | goto done; | |
600 | } | |
601 | } | |
602 | ||
603 | if (newfflag){ | |
604 | ptoken(bufptr, IFILE); | |
605 | ptoken(bufptr, STRING); | |
606 | val = strlen(newfname) + 1; | |
607 | movestr( (char *)&( ( (lgtype *)bufptr)[1]), newfname, val); | |
608 | bstrlg(bufptr, val); | |
609 | ||
610 | ptoken(bufptr, ILINENO); | |
611 | ptoken(bufptr, INT); | |
612 | pint(bufptr, 1); | |
613 | newfflag = 0; | |
614 | } | |
615 | ||
616 | while (bufptr < bufub){ | |
617 | loop: | |
618 | switch(yylval = (type+2)[val = getchar()]) { | |
619 | case SCANEOF: | |
620 | inbufptr = 0; | |
621 | goto endoffile; | |
622 | ||
623 | case NEEDSBUF: | |
624 | inbufptr = fillinbuffer(); | |
625 | if (inbufptr == 0) | |
626 | goto endoffile; | |
627 | goto loop; | |
628 | ||
629 | case DIV: /*process C style comments*/ | |
630 | if ( (val = getchar()) == '*') { /*comment prelude*/ | |
631 | int incomment; | |
632 | linescrossed = 0; | |
633 | incomment = 1; | |
634 | val = getchar(); /*skip over the * */ | |
635 | do{ | |
636 | while ( (val != '*') && | |
637 | (val != '\n') && | |
638 | (val != EOFCHAR) && | |
639 | (val != NEEDCHAR)) | |
640 | val = getchar(); | |
641 | if (val == '\n'){ | |
642 | scanlineno++; | |
643 | linescrossed++; | |
644 | } else | |
645 | if (val == EOFCHAR) | |
646 | goto endoffile; | |
647 | if (val == NEEDCHAR){ | |
648 | inbufptr = fillinbuffer(); | |
649 | if (inbufptr == 0) | |
650 | goto endoffile; | |
651 | lineno++; | |
652 | incomment = 1; | |
653 | val = getchar(); /*pull in the new char*/ | |
654 | } else { /*its a star */ | |
655 | val = getchar(); | |
656 | incomment = val != '/'; | |
657 | } | |
658 | } while (incomment); | |
659 | val = ILINESKIP; | |
660 | yylval = linescrossed; | |
661 | goto ret; | |
662 | } else { /*just an ordinary DIV*/ | |
663 | ungetc(val); | |
664 | val = yylval = DIV; | |
665 | goto ret; | |
666 | } | |
667 | case SH: | |
668 | if (oval == NL){ | |
669 | /* | |
670 | * Attempt to recognize a C preprocessor | |
671 | * style comment '^#[ \t]*[0-9]*[ \t]*".*" | |
672 | */ | |
673 | val = getchar(); /*bump the #*/ | |
674 | while (INCHARSET(val, SPACE)) | |
675 | val = getchar();/*bump white */ | |
676 | if (INCHARSET(val, DIGIT)){ | |
677 | intval = 0; | |
678 | while(INCHARSET(val, DIGIT)){ | |
679 | intval = intval *10 + val - '0'; | |
680 | val = getchar(); | |
681 | } | |
682 | while (INCHARSET(val, SPACE)) | |
683 | val = getchar(); | |
684 | if (val == '"'){ | |
685 | ptoken(bufptr, ILINENO); | |
686 | ptoken(bufptr, INT); | |
687 | pint(bufptr, intval - 1); | |
688 | ptoken(bufptr, IFILE); | |
689 | /* | |
690 | * The '"' has already been | |
691 | * munched | |
692 | * | |
693 | * eatstr will not eat | |
694 | * the trailing \n, so | |
695 | * it is given to the parser | |
696 | * and counted. | |
697 | */ | |
698 | goto eatstr; | |
699 | } | |
700 | } | |
701 | } | |
702 | /* | |
703 | * Well, its just an ordinary decadent comment | |
704 | */ | |
705 | while ((val != '\n') && (val != EOFCHAR)) | |
706 | val = getchar(); | |
707 | if (val == EOFCHAR) | |
708 | goto endoffile; | |
709 | val = yylval = oval = NL; | |
710 | scanlineno++; | |
711 | goto ret; | |
712 | ||
713 | case NL: | |
714 | scanlineno++; | |
715 | val = yylval; | |
716 | goto ret; | |
717 | ||
718 | case SP: | |
719 | oval = SP; /*invalidate ^# meta comments*/ | |
720 | goto loop; | |
721 | ||
722 | case REGOP: /* % , could be used as modulo, or register*/ | |
723 | val = getchar(); | |
724 | if (INCHARSET(val, DIGIT)){ | |
725 | yylval = val-'0'; | |
726 | if (val=='1') { | |
727 | if (INCHARSET( (val = getchar()), REGDIGIT)) | |
728 | yylval = 10+val-'0'; | |
729 | else | |
730 | ungetc(val); | |
731 | } | |
732 | /* | |
733 | * God only knows what the original author | |
734 | * wanted this undocumented feature to | |
735 | * do. | |
736 | * %5++ is really r7 | |
737 | */ | |
738 | while(INCHARSET( (val = getchar()), SIGN)) { | |
739 | if (val=='+') | |
740 | yylval++; | |
741 | else | |
742 | yylval--; | |
743 | } | |
744 | ungetc(val); | |
745 | val = REG; | |
746 | } else { | |
747 | ungetc(val); | |
748 | val = REGOP; | |
749 | } | |
750 | goto ret; | |
751 | ||
752 | case ALPH: | |
753 | yylval = val; | |
754 | if (INCHARSET(val, SZSPECBEGIN)){ | |
755 | if( (val = getchar()) == '`' || val == '^'){ | |
756 | yylval |= 0100; /*convert to lower*/ | |
757 | if (yylval == 'b') yylval = 1; | |
758 | else if (yylval == 'w') yylval = 2; | |
759 | else if (yylval == 'l') yylval = 4; | |
760 | else yylval = d124; | |
761 | val = SIZESPEC; | |
762 | goto ret; | |
763 | } else { | |
764 | ungetc(val); | |
765 | val = yylval; /*restore first character*/ | |
766 | } | |
767 | } | |
768 | cp = yytext; | |
769 | do { | |
770 | if (cp < &yytext[NCPS]) | |
771 | *cp++ = val; | |
772 | } while (INCHARSET ( (val = getchar()), ALPHA | DIGIT)); | |
773 | *cp = '\0'; | |
774 | while (INCHARSET(val, SPACE)) | |
775 | val = getchar(); | |
776 | ungetc(val); | |
777 | doit: | |
451260e7 | 778 | tag = (op = *lookup(1))->s_tag; |
ce996e48 | 779 | if (tag && tag != LABELID){ |
451260e7 RH |
780 | yylval = ( (struct instab *)op)->i_opcode; |
781 | val = op->s_tag ; | |
ce996e48 BJ |
782 | goto ret; |
783 | } else { | |
784 | /* | |
785 | * Its a name... (Labels are subsets ofname) | |
786 | */ | |
787 | yylval = (int)op; | |
788 | val = NAME; | |
789 | goto ret; | |
790 | } | |
791 | ||
792 | case DIG: | |
793 | base = 10; | |
794 | cp = fltchr; | |
795 | intval = 0; | |
796 | if (val=='0') { | |
797 | val = getchar(); | |
798 | if (val == 'b') { | |
799 | yylval = -1; | |
800 | val = BFINT; | |
801 | goto ret; | |
802 | } | |
803 | if (INCHARSET(val, HEXFLAG)){ | |
804 | base = 16; | |
805 | } else | |
806 | if (INCHARSET(val, FLOATFLAG)){ | |
807 | double atof(); | |
808 | while ( (cp < &fltchr[63]) && | |
809 | INCHARSET( | |
810 | (val=getchar()), | |
811 | (DIGIT|SIGN|FLOATEXP|POINT) | |
812 | ) | |
813 | ) *cp++ = val; | |
814 | if (cp == fltchr) { | |
815 | yylval = 1; | |
816 | val = BFINT; | |
817 | goto ret; | |
818 | } | |
819 | ungetc(val); | |
820 | *cp++ = '\0'; | |
821 | fltval.dvalue = atof(fltchr); | |
822 | val = FLTNUM; | |
823 | goto ret; | |
824 | } else { | |
825 | ungetc(val); | |
826 | base = 8; | |
827 | } | |
828 | } else { | |
829 | forb = getchar(); | |
830 | if (forb == 'f' || forb == 'b') { | |
831 | yylval = val - '0' + 1; | |
832 | if (forb == 'b') | |
833 | yylval = -yylval; | |
834 | val = BFINT; | |
835 | goto ret; | |
836 | } | |
837 | ungetc(forb); /* put back non zero */ | |
838 | goto middle; | |
839 | } | |
840 | while ( (val = getchar()) == '0') | |
841 | continue; | |
842 | ungetc(val); | |
843 | while ( INCHARSET( (val = getchar()), DIGIT) || | |
844 | (base==16 && (INCHARSET(val, HEXLDIGIT|HEXUDIGIT) ) | |
845 | ) | |
846 | ){ | |
847 | if (base==8) | |
848 | intval <<= 3; | |
849 | else if (base==10) | |
850 | intval *= 10; | |
851 | else { | |
852 | intval <<= 4; | |
853 | if (INCHARSET(val, HEXLDIGIT)) | |
854 | val -= 'a' - 10 - '0'; | |
855 | else if (INCHARSET(val, HEXUDIGIT)) | |
856 | val -= 'A' - 10 - '0'; | |
857 | } | |
858 | middle: | |
859 | *cp++ = (val -= '0'); | |
860 | intval += val; | |
861 | } | |
862 | ungetc(val); | |
863 | *cp = 0; | |
864 | maxstrlg = cp - fltchr; | |
865 | if ( (maxstrlg > 8) | |
866 | && ( ( (base == 8) | |
867 | && ( (maxstrlg>11) | |
868 | || ( (maxstrlg == 11) | |
869 | && (*fltchr > 3) | |
870 | ) | |
871 | ) | |
872 | ) | |
873 | || ( (base == 16) | |
874 | && (maxstrlg > 8) | |
875 | ) | |
876 | || ( (base == 10) | |
877 | && (maxstrlg >= 10) | |
878 | ) | |
879 | ) | |
880 | ) { | |
881 | val = QUAD; | |
882 | get_quad(base, fltchr, cp, &quadval); | |
883 | } else | |
884 | val = INT; | |
885 | goto ret; | |
886 | ||
887 | case LSH: | |
888 | case RSH: | |
889 | /* | |
890 | * We allow the C style operators | |
891 | * << and >>, as well as < and > | |
892 | */ | |
893 | if ( (base = getchar()) != val) | |
894 | ungetc(base); | |
895 | val = yylval; | |
896 | goto ret; | |
897 | ||
898 | case MINUS: | |
899 | if ( (val = getchar()) =='(') | |
900 | yylval=val=MP; | |
901 | else { | |
902 | ungetc(val); | |
903 | val=MINUS; | |
904 | } | |
905 | goto ret; | |
906 | ||
907 | case SQ: | |
908 | if ((yylval = getchar()) == '\n') | |
909 | scanlineno++; /*not entirely correct*/ | |
910 | intval = yylval; | |
911 | val = INT; | |
912 | goto ret; | |
913 | ||
914 | case DQ: | |
915 | eatstr: | |
916 | linescrossed = 0; | |
917 | maxstrlg = (char *)bufub - (char *)bufptr; | |
918 | ||
919 | if (maxstrlg < MAXSTRLG) { | |
920 | ungetc('"'); | |
921 | *(toktype *)bufptr = VOID ; | |
922 | bufub = bufptr; | |
923 | goto done; | |
924 | } | |
925 | if (maxstrlg > MAXSTRLG) | |
926 | maxstrlg = MAXSTRLG; | |
927 | ||
928 | ptoken(bufptr, STRING); | |
929 | lgbackpatch = bufptr; /*this is where the size goes*/ | |
930 | bufptr += sizeof(lgtype); | |
931 | /* | |
932 | * bufptr is now set to | |
933 | * be stuffed with characters from | |
934 | * the input | |
935 | */ | |
936 | ||
937 | while ( (maxstrlg > 0) | |
938 | && !(INCHARSET( (val = getchar()), STRESCAPE)) | |
939 | ){ | |
940 | stuff: | |
941 | maxstrlg-= 1; | |
942 | pchar(bufptr, val); | |
943 | } | |
944 | if (maxstrlg <= 0){ /*enough characters to fill a string buffer*/ | |
945 | ungetc('"'); /*will read it next*/ | |
946 | } | |
947 | else if (val == '"'); /*done*/ | |
948 | else if (val == '\n'){ | |
949 | scanlineno++; | |
950 | linescrossed++; | |
951 | val = getchar(); | |
952 | if (val == EOFCHAR){ | |
953 | do_eof: | |
954 | pchar(bufptr, '\n'); | |
955 | ungetc(EOFCHAR); | |
956 | } else | |
957 | if (val == NEEDCHAR){ | |
958 | if ( (inbufptr = fillinbuffer()) == 0) | |
959 | goto do_eof; | |
960 | val = '\n'; | |
961 | goto stuff; | |
962 | } else { /* simple case */ | |
963 | ungetc(val); | |
964 | val = '\n'; | |
965 | goto stuff; | |
966 | } | |
967 | } else { | |
968 | val = getchar(); /*skip the '\\'*/ | |
969 | if ( INCHARSET(val, BSESCAPE)){ | |
970 | switch (val){ | |
971 | case 'b': val = '\b'; goto stuff; | |
972 | case 'f': val = '\f'; goto stuff; | |
973 | case 'n': val = '\n'; goto stuff; | |
974 | case 'r': val = '\r'; goto stuff; | |
975 | case 't': val = '\t'; goto stuff; | |
976 | } | |
977 | } | |
978 | if ( !(INCHARSET(val,OCTDIGIT)) ) goto stuff; | |
979 | base = 0; | |
980 | intval = 0; | |
981 | while ( (base < 3) && (INCHARSET(val, OCTDIGIT))){ | |
982 | base++;intval <<= 3;intval += val - '0'; | |
983 | val = getchar(); | |
984 | } | |
985 | ungetc(val); | |
986 | val = (char)intval; | |
987 | goto stuff; | |
988 | } | |
989 | /* | |
990 | * bufptr now points at the next free slot | |
991 | */ | |
992 | bstrfromto(lgbackpatch, bufptr); | |
993 | if (linescrossed){ | |
994 | val = ILINESKIP; | |
995 | yylval = linescrossed; | |
996 | goto ret; | |
997 | } else | |
998 | goto builtval; | |
999 | ||
1000 | case BADCHAR: | |
1001 | linescrossed = lineno; | |
1002 | lineno = scanlineno; | |
1003 | yyerror("Illegal character mapped: %d, char read:(octal) %o", | |
1004 | yylval, val); | |
1005 | lineno = linescrossed; | |
1006 | val = BADCHAR; | |
1007 | goto ret; | |
1008 | ||
1009 | default: | |
1010 | val = yylval; | |
1011 | goto ret; | |
1012 | } /*end of the switch*/ | |
1013 | /* | |
1014 | * here with one token, so stuff it | |
1015 | */ | |
1016 | ret: | |
1017 | oval = val; | |
1018 | ptoken(bufptr, val); | |
1019 | switch(val){ | |
1020 | case ILINESKIP: | |
1021 | pint(bufptr, yylval); | |
1022 | break; | |
1023 | case SIZESPEC: | |
1024 | pchar(bufptr, yylval); | |
1025 | break; | |
1026 | case BFINT: plong(bufptr, yylval); | |
1027 | break; | |
1028 | case INT: plong(bufptr, intval); | |
1029 | break; | |
1030 | case QUAD: plong(bufptr, quadval.quad_low_long); | |
1031 | plong(bufptr, quadval.quad_high_long); | |
1032 | break; | |
1033 | case FLTNUM: pdouble(bufptr, fltval.dvalue); | |
1034 | break; | |
1035 | case NAME: pptr(bufptr, (int)(struct symtab *)yylval); | |
1036 | break; | |
1037 | case REG: pchar(bufptr, yylval); | |
1038 | break; | |
1039 | case INST0: | |
1040 | case INSTn: | |
1041 | pchar(bufptr, yylval); | |
1042 | break; | |
1043 | case IJXXX: | |
1044 | pchar(bufptr, yylval); | |
1045 | pptr(bufptr, (int)(struct symtab *)symalloc()); | |
1046 | break; | |
1047 | case ISTAB: | |
1048 | case ISTABSTR: | |
1049 | case ISTABNONE: | |
1050 | case ISTABDOT: | |
1051 | case IALIGN: | |
1052 | pptr(bufptr, (int)(struct symtab *)symalloc()); | |
1053 | break; | |
1054 | /* | |
1055 | * default: | |
1056 | */ | |
1057 | } | |
1058 | builtval: ; | |
1059 | } /*end of the while to stuff the buffer*/ | |
1060 | done: | |
1061 | bufferbox->tok_count = (toktype *)bufptr - &(bufferbox->toks[0]); | |
1062 | ||
1063 | /* | |
1064 | * This is a real kludge: | |
1065 | * | |
1066 | * We put the last token in the buffer to be a MINUS | |
1067 | * symbol. This last token will never be picked up | |
1068 | * in the normal way, but can be looked at during | |
1069 | * a peekahead look that the short circuit expression | |
1070 | * evaluator uses to see if an expression is complicated. | |
1071 | * | |
1072 | * Consider the following situation: | |
1073 | * | |
1074 | * .word 45 + 47 | |
1075 | * buffer 1 | buffer 0 | |
1076 | * the peekahead would want to look across the buffer, | |
1077 | * but will look in the buffer end zone, see the minus, and | |
1078 | * fail. | |
1079 | */ | |
1080 | ptoken(bufptr, MINUS); | |
1081 | InBufPtr = inbufptr; /*copy this back*/ | |
1082 | } | |
1083 | ||
1084 | struct Quad _quadtemp; | |
1085 | get_quad(radix, cp_start, cp_end, quadptr) | |
1086 | int radix; | |
1087 | char *cp_start, *cp_end; | |
1088 | struct Quad *quadptr; | |
1089 | { | |
1090 | register char *cp = cp_start; /* r11 */ | |
1091 | register struct Quad *qp = quadptr; /* r10 */ | |
1092 | register long temp; /* r9 */ | |
1093 | ||
1094 | asm("clrq (r10)"); | |
1095 | for (; cp < cp_end; cp++){ | |
1096 | switch (radix) { | |
1097 | case 8: | |
1098 | asm ("ashq $3, (r10), (r10)"); | |
1099 | break; | |
1100 | case 16: | |
1101 | asm ("ashq $4, (r10), (r10)"); | |
1102 | break; | |
1103 | case 10: | |
1104 | asm ("ashq $1, (r10), __quadtemp"); | |
1105 | asm ("ashq $3, (r10), (r10)"); | |
1106 | asm ("addl2 __quadtemp, (r10)"); | |
1107 | asm ("adwc __quadtemp+4, 4(r10)"); | |
1108 | break; | |
1109 | } | |
1110 | asm ("cvtbl (r11), r9"); | |
1111 | asm ("addl2 r9, (r10)"); | |
1112 | asm ("adwc $0, 4(r10)"); | |
1113 | } | |
1114 | } |