Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
718 | jacekm | 1 | /* |
2 | ** Small-C Compiler -- Part 2 -- Front End and Miscellaneous. |
||
3 | ** Copyright 1982, 1983, 1985, 1988 J. E. Hendrix |
||
4 | ** Copyright 1998 H T Walheim |
||
5 | ** All rights reserved. |
||
6 | */ |
||
7 | |||
8 | #include |
||
9 | #include "cc.h" |
||
10 | |||
11 | extern char |
||
12 | *symtab, *macn, *macq, *pline, *mline, optimize, |
||
13 | alarm, *glbptr, *line, *lptr, *cptr, *cptr2, *cptr3, |
||
14 | *locptr, msname[NAMESIZE], pause, quote[2]; |
||
15 | |||
16 | extern int |
||
17 | *wq, ccode, ch, csp, eof, errflag, iflevel, |
||
18 | input, input2, listfp, macptr, nch, |
||
19 | nxtlab, op[16], opindex, opsize, output, pptr, |
||
20 | skiplevel, *wqptr; |
||
21 | |||
22 | /********************** input functions **********************/ |
||
23 | |||
24 | preprocess() { |
||
25 | int k; |
||
26 | char c; |
||
27 | if(ccode) { |
||
28 | line = mline; |
||
29 | ifline(); |
||
30 | if(eof) return; |
||
31 | } |
||
32 | else { |
||
33 | inline(); |
||
34 | return; |
||
35 | } |
||
36 | pptr = -1; |
||
37 | while(ch != NEWLINE && ch) { |
||
38 | if(white()) { |
||
39 | keepch(' '); |
||
40 | while(white()) gch(); |
||
41 | } |
||
42 | else if(ch == '"') { |
||
43 | keepch(ch); |
||
44 | gch(); |
||
45 | while(ch != '"' || (*(lptr-1) == 92 && *(lptr-2) != 92)) { |
||
46 | if(ch == NULL) { |
||
47 | error("no quote"); |
||
48 | break; |
||
49 | } |
||
50 | keepch(gch()); |
||
51 | } |
||
52 | gch(); |
||
53 | keepch('"'); |
||
54 | } |
||
55 | else if(ch == 39) { |
||
56 | keepch(39); |
||
57 | gch(); |
||
58 | while(ch != 39 || (*(lptr-1) == 92 && *(lptr-2) != 92)) { |
||
59 | if(ch == NULL) { |
||
60 | error("no apostrophe"); |
||
61 | break; |
||
62 | } |
||
63 | keepch(gch()); |
||
64 | } |
||
65 | gch(); |
||
66 | keepch(39); |
||
67 | } |
||
68 | else if(ch == '/' && nch == '*') |
||
69 | { |
||
70 | bump(2); |
||
71 | while((ch == '*' && nch == '/') == 0) |
||
72 | { |
||
73 | if(ch) |
||
74 | bump(1); |
||
75 | else |
||
76 | { |
||
77 | ifline(); |
||
78 | if(eof) |
||
79 | break; |
||
80 | } |
||
81 | } |
||
82 | bump(2); |
||
83 | } |
||
84 | else if(ch == '/' && nch == '/') |
||
85 | { |
||
86 | bump(2); |
||
87 | while(ch != NEWLINE) |
||
88 | { |
||
89 | if(ch) |
||
90 | bump(1); |
||
91 | else |
||
92 | { |
||
93 | if(eof) |
||
94 | break; |
||
95 | } |
||
96 | } |
||
97 | bump(1); |
||
98 | } |
||
99 | else if(an(ch)) { |
||
100 | k = 0; |
||
101 | while(an(ch) && k < NAMEMAX) { |
||
102 | msname[k++] = ch; |
||
103 | gch(); |
||
104 | } |
||
105 | msname[k] = NULL; |
||
106 | if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0)) { |
||
107 | k = getint(cptr+NAMESIZE, 2/*INTSIZE*/); |
||
108 | while(c = macq[k++]) keepch(c); |
||
109 | while(an(ch)) gch(); |
||
110 | } |
||
111 | else { |
||
112 | k = 0; |
||
113 | while(c = msname[k++]) keepch(c); |
||
114 | } |
||
115 | } |
||
116 | else keepch(gch()); |
||
117 | } |
||
118 | if(pptr >= LINEMAX) error("line too long"); |
||
119 | keepch(NULL); |
||
120 | line = pline; |
||
121 | bump(0); |
||
122 | } |
||
123 | |||
124 | keepch(c) char c; { |
||
125 | if(pptr < LINEMAX) pline[++pptr] = c; |
||
126 | } |
||
127 | |||
128 | ifline() { |
||
129 | while(1) { |
||
130 | inline(); |
||
131 | if(eof) return; |
||
132 | if(match("#ifdef")) { |
||
133 | ++iflevel; |
||
134 | if(skiplevel) continue; |
||
135 | symname(msname); |
||
136 | if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0) == 0) |
||
137 | skiplevel = iflevel; |
||
138 | continue; |
||
139 | } |
||
140 | if(match("#ifndef")) { |
||
141 | ++iflevel; |
||
142 | if(skiplevel) continue; |
||
143 | symname(msname); |
||
144 | if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0)) |
||
145 | skiplevel = iflevel; |
||
146 | continue; |
||
147 | } |
||
148 | if(match("#else")) { |
||
149 | if(iflevel) { |
||
150 | if(skiplevel == iflevel) skiplevel = 0; |
||
151 | else if(skiplevel == 0) skiplevel = iflevel; |
||
152 | } |
||
153 | else noiferr(); |
||
154 | continue; |
||
155 | } |
||
156 | if(match("#endif")) { |
||
157 | if(iflevel) { |
||
158 | if(skiplevel == iflevel) skiplevel = 0; |
||
159 | --iflevel; |
||
160 | } |
||
161 | else noiferr(); |
||
162 | continue; |
||
163 | } |
||
164 | if(skiplevel) continue; |
||
165 | if(ch == 0) continue; |
||
166 | break; |
||
167 | } |
||
168 | } |
||
169 | |||
170 | inline() { /* numerous revisions */ |
||
171 | int k, unit; |
||
172 | |||
173 | if(input == EOF) openfile(); |
||
174 | if(eof) return; |
||
175 | if((unit = input2) == EOF) unit = input; |
||
176 | if(fgets(line, LINEMAX, unit) == NULL) { |
||
177 | fclose(unit); |
||
178 | if(input2 != EOF) |
||
179 | input2 = EOF; |
||
180 | else input = EOF; |
||
181 | *line = NULL; |
||
182 | } |
||
183 | else if(listfp) |
||
184 | { |
||
185 | if(listfp == output) fputc(';', output); |
||
186 | fputs(line, listfp); |
||
187 | } |
||
188 | #ifdef _MSC_VER |
||
189 | else |
||
190 | { |
||
191 | fputc(';', output); |
||
192 | fputs(line, output); |
||
193 | } |
||
194 | #endif |
||
195 | bump(0); |
||
196 | } |
||
197 | |||
198 | inbyte() { |
||
199 | while(ch == 0) { |
||
200 | if(eof) return 0; |
||
201 | preprocess(); |
||
202 | } |
||
203 | return gch(); |
||
204 | } |
||
205 | |||
206 | /********************* scanning functions ********************/ |
||
207 | |||
208 | /* |
||
209 | ** test if next input string is legal symbol name |
||
210 | */ |
||
211 | symname(sname) char *sname; { |
||
212 | int k;char c; |
||
213 | blanks(); |
||
214 | if(alpha(ch) == 0) return (*sname = 0); |
||
215 | k = 0; |
||
216 | while(an(ch)) { |
||
217 | sname[k] = gch(); |
||
218 | if(k < NAMEMAX) ++k; |
||
219 | } |
||
220 | sname[k] = 0; |
||
221 | return 1; |
||
222 | } |
||
223 | |||
224 | need(str) char *str; { |
||
225 | if(match(str) == 0) error("missing token"); |
||
226 | } |
||
227 | |||
228 | ns() { |
||
229 | if(match(";") == 0) error("no semicolon"); |
||
230 | else errflag = 0; |
||
231 | } |
||
232 | |||
233 | match(lit) char *lit; { |
||
234 | int k; |
||
235 | blanks(); |
||
236 | if(k = streq(lptr, lit)) { |
||
237 | bump(k); |
||
238 | return 1; |
||
239 | } |
||
240 | return 0; |
||
241 | } |
||
242 | |||
243 | streq(str1, str2) char str1[], str2[]; { |
||
244 | int k; |
||
245 | k = 0; |
||
246 | while (str2[k]) { |
||
247 | if(str1[k] != str2[k]) return 0; |
||
248 | ++k; |
||
249 | } |
||
250 | return k; |
||
251 | } |
||
252 | |||
253 | amatch(lit, len) char *lit; int len; { |
||
254 | int k; |
||
255 | blanks(); |
||
256 | if(k = astreq(lptr, lit, len)) { |
||
257 | bump(k); |
||
258 | return 1; |
||
259 | } |
||
260 | return 0; |
||
261 | } |
||
262 | |||
263 | astreq(str1, str2, len) char str1[], str2[]; int len; { |
||
264 | int k; |
||
265 | k = 0; |
||
266 | while (k < len) { |
||
267 | if(str1[k] != str2[k]) break; |
||
268 | /* |
||
269 | ** must detect end of symbol table names terminated by |
||
270 | ** symbol length in binary |
||
271 | */ |
||
272 | if(str2[k] < ' ') break; |
||
273 | if(str1[k] < ' ') break; |
||
274 | ++k; |
||
275 | } |
||
276 | if(an(str1[k]) || an(str2[k])) return 0; |
||
277 | return k; |
||
278 | } |
||
279 | |||
280 | nextop(list) char *list; { |
||
281 | char op[4]; |
||
282 | opindex = 0; |
||
283 | blanks(); |
||
284 | while(1) { |
||
285 | opsize = 0; |
||
286 | while(*list > ' ') op[opsize++] = *list++; |
||
287 | op[opsize] = 0; |
||
288 | if(opsize = streq(lptr, op)) |
||
289 | if(*(lptr+opsize) != '=' && |
||
290 | *(lptr+opsize) != *(lptr+opsize-1)) |
||
291 | return 1; |
||
292 | if(*list) { |
||
293 | ++list; |
||
294 | ++opindex; |
||
295 | } |
||
296 | else return 0; |
||
297 | } |
||
298 | } |
||
299 | |||
300 | blanks() { |
||
301 | while(1) { |
||
302 | while(ch) { |
||
303 | if(white()) gch(); |
||
304 | else return; |
||
305 | } |
||
306 | if(line == mline) return; |
||
307 | preprocess(); |
||
308 | if(eof) break; |
||
309 | } |
||
310 | } |
||
311 | |||
312 | white() { |
||
313 | return (*lptr <= ' ' && *lptr); |
||
314 | } |
||
315 | |||
316 | gch() { |
||
317 | int c; |
||
318 | if(c = ch) bump(1); |
||
319 | return c; |
||
320 | } |
||
321 | |||
322 | bump(n) int n; { |
||
323 | if(n) lptr += n; |
||
324 | else lptr = line; |
||
325 | if(ch = nch = *lptr) nch = *(lptr+1); |
||
326 | } |
||
327 | |||
328 | kill() { |
||
329 | *line = 0; |
||
330 | bump(0); |
||
331 | } |
||
332 | |||
333 | skip() { |
||
334 | if(an(inbyte())) |
||
335 | while(an(ch)) gch(); |
||
336 | else while(an(ch) == 0) { |
||
337 | if(ch == 0) break; |
||
338 | gch(); |
||
339 | } |
||
340 | blanks(); |
||
341 | } |
||
342 | |||
343 | endst() { |
||
344 | blanks(); |
||
345 | return (streq(lptr, ";") || ch == 0); |
||
346 | } |
||
347 | |||
348 | /*********** symbol table management functions ***********/ |
||
349 | |||
350 | addsym(sname, id, type, size, value, lgpp, class) |
||
351 | char *sname, id, type; |
||
352 | int size, value, *lgpp, class; |
||
353 | { |
||
354 | if(lgpp == &glbptr) |
||
355 | { |
||
356 | if(cptr2 = findglb(sname)) |
||
357 | return cptr2; |
||
358 | if(cptr == 0) |
||
359 | { |
||
360 | error("global symbol table overflow"); |
||
361 | return 0; |
||
362 | } |
||
363 | } |
||
364 | else |
||
365 | { |
||
366 | if(locptr > (ENDLOC-SYMMAX)) |
||
367 | { |
||
368 | error("local symbol table overflow"); |
||
369 | exit(ERRCODE); |
||
370 | } |
||
371 | cptr = *lgpp; |
||
372 | } |
||
373 | cptr[IDENT] = id; |
||
374 | cptr[TYPE] = type; |
||
375 | cptr[CLASS] = class; |
||
376 | putint(size, cptr + SIZE, INTSIZE); |
||
377 | putint(value, cptr + OFFSET, INTSIZE); |
||
378 | cptr3 = cptr2 = cptr + NAME; |
||
379 | while(an(*sname)) |
||
380 | *cptr2++ = *sname++; |
||
381 | |||
382 | if(lgpp == &locptr) |
||
383 | { |
||
384 | *cptr2 = cptr2 - cptr3; /* set length */ |
||
385 | *lgpp = ++cptr2; |
||
386 | } |
||
387 | return cptr; |
||
388 | } |
||
389 | |||
390 | /* |
||
391 | ** search for symbol match |
||
392 | ** on return cptr points to slot found or empty slot |
||
393 | */ |
||
394 | search(sname, buf, len, end, max, off) |
||
395 | char *sname, *buf, *end; int len, max, off; { |
||
396 | cptr = |
||
397 | cptr2 = buf+((hash(sname)%(max-1))*len); |
||
398 | while(*cptr != NULL) { |
||
399 | if(astreq(sname, cptr+off, NAMEMAX)) return 1; |
||
400 | if((cptr = cptr+len) >= end) cptr = buf; |
||
401 | if(cptr == cptr2) return (cptr = 0); |
||
402 | } |
||
403 | return 0; |
||
404 | } |
||
405 | |||
406 | hash(sname) char *sname; { |
||
407 | int i, c; |
||
408 | i = 0; |
||
409 | while(c = *sname++) i = (i << 1) + c; |
||
410 | return i; |
||
411 | } |
||
412 | |||
413 | findglb(sname) char *sname; { |
||
414 | if(search(sname, STARTGLB, SYMMAX, ENDGLB, NUMGLBS, NAME)) |
||
415 | return cptr; |
||
416 | return 0; |
||
417 | } |
||
418 | |||
419 | findloc(sname) char *sname; { |
||
420 | cptr = locptr - 1; /* search backward for block locals */ |
||
421 | while(cptr > STARTLOC) { |
||
422 | cptr = cptr - *cptr; |
||
423 | if(astreq(sname, cptr, NAMEMAX)) return (cptr - NAME); |
||
424 | cptr = cptr - NAME - 1; |
||
425 | } |
||
426 | return 0; |
||
427 | } |
||
428 | |||
429 | nextsym(entry) char *entry; { |
||
430 | entry = entry + NAME; |
||
431 | while(*entry++ >= ' '); /* find length byte */ |
||
432 | return entry; |
||
433 | } |
||
434 | |||
435 | /******** while queue management functions *********/ |
||
436 | |||
437 | addwhile(ptr) int ptr[]; { |
||
438 | int k; |
||
439 | ptr[WQSP] = csp; /* and stk ptr */ |
||
440 | ptr[WQLOOP] = getlabel(); /* and looping label */ |
||
441 | ptr[WQEXIT] = getlabel(); /* and exit label */ |
||
442 | if(wqptr == WQMAX) { |
||
443 | error("control statement nesting limit"); |
||
444 | exit(ERRCODE); |
||
445 | } |
||
446 | k = 0; |
||
447 | while (k < WQSIZ) *wqptr++ = ptr[k++]; |
||
448 | } |
||
449 | |||
450 | readwhile(ptr) int *ptr; { |
||
451 | if(ptr <= wq) { |
||
452 | error("out of context"); |
||
453 | return 0; |
||
454 | } |
||
455 | else return (ptr - WQSIZ); |
||
456 | } |
||
457 | |||
458 | delwhile() { |
||
459 | if(wqptr > wq) wqptr -= WQSIZ; |
||
460 | } |
||
461 | |||
462 | /****************** utility functions ********************/ |
||
463 | |||
464 | /* |
||
465 | ** test if c is alphabetic |
||
466 | */ |
||
467 | alpha(c) char c; { |
||
468 | return (isalpha(c) || c == '_'); |
||
469 | } |
||
470 | |||
471 | /* |
||
472 | ** test if given character is alphanumeric |
||
473 | */ |
||
474 | an(c) char c; { |
||
475 | return (alpha(c) || isdigit(c)); |
||
476 | } |
||
477 | |||
478 | /* |
||
479 | ** return next avail internal label number |
||
480 | */ |
||
481 | getlabel() { |
||
482 | return(++nxtlab); |
||
483 | } |
||
484 | |||
485 | /* |
||
486 | ** get integer of length len from address addr |
||
487 | ** (byte sequence set by "putint") |
||
488 | */ |
||
489 | getint(addr, len) char *addr; int len; { |
||
490 | int i; |
||
491 | i = *(addr + --len); /* high order byte sign extended */ |
||
492 | while(len--) i = (i << 8) | *(addr + len) & 255; |
||
493 | return i; |
||
494 | } |
||
495 | |||
496 | /* |
||
497 | ** put integer i of length len into address addr |
||
498 | ** (low byte first) |
||
499 | */ |
||
500 | putint(i, addr, len) char *addr; int i, len; { |
||
501 | while(len--) { |
||
502 | *addr++ = i; |
||
503 | i = i >> 8; |
||
504 | } |
||
505 | } |
||
506 | |||
507 | lout(line, fd) char *line; int fd; { |
||
508 | fputs(line, fd); |
||
509 | fputc(NEWLINE, fd); |
||
510 | } |
||
511 | |||
512 | /******************* error functions *********************/ |
||
513 | |||
514 | illname() { |
||
515 | error("illegal symbol"); |
||
516 | skip(); |
||
517 | } |
||
518 | |||
519 | multidef(sname) char *sname; { |
||
520 | error("already defined"); |
||
521 | } |
||
522 | |||
523 | needlval() { |
||
524 | error("must be lvalue"); |
||
525 | } |
||
526 | |||
527 | noiferr() { |
||
528 | error("no matching #if..."); |
||
529 | errflag = 0; |
||
530 | } |
||
531 | |||
532 | error(msg) |
||
533 | char msg[]; |
||
534 | { |
||
535 | if(errflag) |
||
536 | return; |
||
537 | else |
||
538 | errflag = 1; |
||
539 | |||
540 | lout(line, stderr); |
||
541 | errout(msg, stderr); |
||
542 | if(alarm) |
||
543 | fputc(7, stderr); |
||
544 | if(pause) |
||
545 | while(fgetc(stderr) != NEWLINE); |
||
546 | if(listfp > 0) |
||
547 | errout(msg, listfp); |
||
548 | } |
||
549 | |||
550 | errout(msg, fp) char msg[]; int fp; { |
||
551 | int k; |
||
552 | k = line+2; |
||
553 | while(k++ <= lptr) fputc(' ', fp); |
||
554 | lout("/\\", fp); |
||
555 | fputs("**** ", fp); lout(msg, fp); |
||
556 | }=>><>=>>><>=>>>>>>> |
||
557 |