|
|
1.1 root 1: /* This is the Assembler Pre-Processor
2: Copyright (C) 1987 Free Software Foundation, Inc.
3:
4: This file is part of GAS, the GNU Assembler.
5:
6: GAS is free software; you can redistribute it and/or modify
7: it under the terms of the GNU General Public License as published by
8: the Free Software Foundation; either version 1, or (at your option)
9: any later version.
10:
11: GAS is distributed in the hope that it will be useful,
12: but WITHOUT ANY WARRANTY; without even the implied warranty of
13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: GNU General Public License for more details.
15:
16: You should have received a copy of the GNU General Public License
17: along with GAS; see the file COPYING. If not, write to
18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19:
20: /* App, the assembler pre-processor. This pre-processor strips out excess
21: spaces, turns single-quoted characters into a decimal constant, and turns
22: # <number> <filename> <garbage> into a .line <number>;.file <filename> pair.
23: This needs better error-handling.
24: */
25: #include <stdio.h>
26: #include <string.h>
27: #include "as.h"
28: #include "md.h"
29: #include "app.h"
30: #include "messages.h"
31:
32: FILE *scrub_file = NULL;
33: char *scrub_string = NULL;
34: char *scrub_last_string = NULL;
35:
36: #ifdef NeXT /* .include feature */
37: /* These are moved out of do_scrub() so save_scrub_context() can save them */
38: static state;
39: static old_state;
40: static char *out_string;
41: static char out_buf[20];
42: static add_newlines = 0;
43: #endif /* NeXT .include feature */
44:
45: static char lex [256];
46: static char symbol_chars[] =
47: "$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
48:
49: #define LEX_IS_SYMBOL_COMPONENT (1)
50: #define LEX_IS_WHITESPACE (2)
51: #define LEX_IS_LINE_SEPERATOR (4)
52: #define LEX_IS_COMMENT_START (8) /* JF added these two */
53: #define LEX_IS_LINE_COMMENT_START (16)
54: #define IS_SYMBOL_COMPONENT(c) (lex [c] & LEX_IS_SYMBOL_COMPONENT)
55: #define IS_WHITESPACE(c) (lex [c] & LEX_IS_WHITESPACE)
56: #define IS_LINE_SEPERATOR(c) (lex [c] & LEX_IS_LINE_SEPERATOR)
57: #define IS_COMMENT(c) (lex [c] & LEX_IS_COMMENT_START)
58: #define IS_LINE_COMMENT(c) (lex [c] & LEX_IS_LINE_COMMENT_START)
59:
60: void
61: do_scrub_begin(
62: void)
63: {
64: char *p;
65: const char *q;
66:
67: memset(lex, '\0', sizeof(lex)); /* Trust NOBODY! */
68: lex [' '] |= LEX_IS_WHITESPACE;
69: lex ['\t'] |= LEX_IS_WHITESPACE;
70: for (p =symbol_chars;*p;++p)
71: lex [(int)*p] |= LEX_IS_SYMBOL_COMPONENT;
72: lex ['\n'] |= LEX_IS_LINE_SEPERATOR;
73: #ifndef DONTDEF
74: #ifdef NeXT
75: /*
76: * This DOES not cause ':' to be a LINE SEPERATOR but does make the
77: * second if logic after flushchar: in do_scrub_next_char() to handle
78: * "foo :" and strip the blanks. This is the way has always been and
79: * must be this way to work.
80: */
81: #endif /* NeXT */
82: lex [':'] |= LEX_IS_LINE_SEPERATOR;
83: #endif /* !defined(DONTDEF) */
84:
85: #if defined(M88K) || defined(M98K) || defined(HPPA)
86: lex ['@'] |= LEX_IS_LINE_SEPERATOR;
87: #else
88: lex [';'] |= LEX_IS_LINE_SEPERATOR;
89: #endif
90: for (q=md_comment_chars;*q;q++)
91: lex[(int)*q] |= LEX_IS_COMMENT_START;
92: for (q=md_line_comment_chars;*q;q++)
93: lex[(int)*q] |= LEX_IS_LINE_COMMENT_START;
94: }
95:
96: int
97: scrub_from_file(
98: void)
99: {
100: return getc(scrub_file);
101: }
102:
103: void
104: scrub_to_file(
105: int ch)
106: {
107: ungetc(ch, scrub_file);
108: }
109:
110: int
111: scrub_from_string(
112: void)
113: {
114: return scrub_string == scrub_last_string ? EOF : *scrub_string++;
115: }
116:
117: void
118: scrub_to_string(
119: int ch)
120: {
121: *--scrub_string = ch;
122: }
123:
124: int
125: do_scrub_next_char(
126: int (*get)(void),
127: void (*unget)(int ch))
128: /* FILE *fp; */
129: {
130: /* State 0: beginning of normal line
131: 1: After first whitespace on normal line (flush more white)
132: 2: After first non-white on normal line (keep 1white)
133: 3: after second white on normal line (flush white)
134: 4: after putting out a .line, put out digits
135: 5: parsing a string, then go to old-state
136: 6: putting out \ escape in a "d string.
137: 7: After putting out a .file, put out string.
138: 8: After putting out a .file string, flush until newline.
139: -1: output string in out_string and go to the state in old_state
140: -2: flush text until a '*' '/' is seen, then go to state old_state
141: */
142:
143: #ifndef NeXT /* .include feature */
144: static state;
145: static old_state;
146: static char *out_string;
147: static char out_buf[20];
148: static add_newlines = 0;
149: #endif /* NeXT .include feature */
150: int ch;
151:
152: if(state==-1) {
153: ch= *out_string++;
154: if(*out_string==0) {
155: state=old_state;
156: old_state=3;
157: }
158: return ch;
159: }
160: if(state==-2) {
161: for(;;) {
162: do ch=(*get)();
163: while(ch!=EOF && ch!='\n' && ch!='*');
164: if(ch=='\n' || ch==EOF)
165: return ch;
166: ch=(*get)();
167: if(ch==EOF || ch=='/')
168: break;
169: (*unget)(ch);
170: }
171: state=old_state;
172: return ' ';
173: }
174: if(state==4) {
175: ch=(*get)();
176: if(ch==EOF || (ch>='0' && ch<='9'))
177: return ch;
178: else {
179: while(ch!=EOF && IS_WHITESPACE(ch))
180: ch=(*get)();
181: if(ch=='"') {
182: (*unget)(ch);
183: #if defined(M88K) || defined(M98K) || defined(HPPA)
184: out_string="@ .file ";
185: #else
186: out_string="; .file ";
187: #endif
188: old_state=7;
189: state= -1;
190: return *out_string++;
191: } else {
192: while(ch!=EOF && ch!='\n')
193: ch=(*get)();
194: #ifdef NeXT
195: /* bug fix for bug #8918, which was when
196: * a full line comment line this:
197: * # 40 MP1 = M + 1
198: * got confused with a cpp output like:
199: * # 1 "hello.c" 1
200: */
201: state = 0;
202: #endif /* NeXT */
203: return ch;
204: }
205: }
206: }
207: if(state==5) {
208: ch=(*get)();
209: if(ch=='"') {
210: state=old_state;
211: return '"';
212: } else if(ch=='\\') {
213: state=6;
214: return ch;
215: } else if(ch==EOF) {
216: as_warn("End of file in string: inserted '\"'");
217: state=old_state;
218: (*unget)('\n');
219: return '"';
220: } else {
221: return ch;
222: }
223: }
224: if(state==6) {
225: state=5;
226: ch=(*get)();
227: switch(ch) {
228: /* This is neet. Turn "string
229: more string" into "string\n more string"
230: */
231: case '\n':
232: (*unget)('n');
233: add_newlines++;
234: return '\\';
235:
236: case '"':
237: case '\\':
238: case 'b':
239: case 'f':
240: case 'n':
241: case 'r':
242: case 't':
243: case '0':
244: case '1':
245: case '2':
246: case '3':
247: case '4':
248: case '5':
249: case '6':
250: case '7':
251: break;
252: default:
253: as_warn("Unknown escape '\\%c' in string: Ignored",ch);
254: break;
255:
256: case EOF:
257: as_warn("End of file in string: '\"' inserted");
258: return '"';
259: }
260: return ch;
261: }
262:
263: if(state==7) {
264: ch=(*get)();
265: state=5;
266: old_state=8;
267: return ch;
268: }
269:
270: if(state==8) {
271: do ch= (*get)();
272: while(ch!='\n');
273: state=0;
274: return ch;
275: }
276:
277: flushchar:
278: ch=(*get)();
279: switch(ch) {
280: case ' ':
281: case '\t':
282: do ch=(*get)();
283: while(ch!=EOF && IS_WHITESPACE(ch));
284: if(ch==EOF)
285: return ch;
286: if(IS_COMMENT(ch) || (state==0 && IS_LINE_COMMENT(ch)) || ch=='/' || IS_LINE_SEPERATOR(ch)) {
287: (*unget)(ch);
288: goto flushchar;
289: }
290: (*unget)(ch);
291: if(state==0 || state==2) {
292: state++;
293: return ' ';
294: } else goto flushchar;
295:
296: case '/':
297: ch=(*get)();
298: if(ch=='*') {
299: for(;;) {
300: do {
301: ch=(*get)();
302: if(ch=='\n')
303: add_newlines++;
304: } while(ch!=EOF && ch!='*');
305: ch=(*get)();
306: if(ch==EOF || ch=='/')
307: break;
308: (*unget)(ch);
309: }
310: if(ch==EOF)
311: as_warn("End of file in '/' '*' string: */ inserted");
312:
313: (*unget)(' ');
314: goto flushchar;
315: } else {
316: #if defined(I860) || defined(M88K) || defined(M98K) || defined(I386) || \
317: defined(HPPA) || defined (SPARC)
318: if (ch == '/') {
319: do {
320: ch=(*get)();
321: } while (ch != EOF && (ch != '\n'));
322: if (ch == EOF)
323: as_warn("End of file before newline in // comment");
324: if ( ch == '\n' ) /* Push NL back so we can complete state */
325: (*unget)(ch);
326: goto flushchar;
327: }
328: #endif
329: if(IS_COMMENT('/') || (state==0 && IS_LINE_COMMENT('/'))) {
330: (*unget)(ch);
331: ch='/';
332: goto deal_misc;
333: }
334: if(ch!=EOF)
335: (*unget)(ch);
336: return '/';
337: }
338: break;
339:
340: case '"':
341: old_state=state;
342: state=5;
343: return '"';
344: break;
345:
346: case '\'':
347: ch=(*get)();
348: if(ch==EOF) {
349: as_warn("End-of-file after a ': \\000 inserted");
350: ch=0;
351: }
352: sprintf(out_buf,"(%d)",ch&0xff);
353: old_state=state;
354: state= -1;
355: out_string=out_buf;
356: return *out_string++;
357:
358: case ':':
359: if(state!=3)
360: state=0;
361: return ch;
362:
363: case '\n':
364: if(add_newlines) {
365: --add_newlines;
366: (*unget)(ch);
367: }
368: /* Fall through. */
369: #if defined(M88K) || defined(M98K) || defined(HPPA)
370: case '@':
371: #else
372: case ';':
373: #endif
374: state=0;
375: return ch;
376:
377: default:
378: deal_misc:
379: if(state==0 && IS_LINE_COMMENT(ch)) {
380: do ch=(*get)();
381: while(ch!=EOF && IS_WHITESPACE(ch));
382: if(ch==EOF) {
383: as_warn("EOF in comment: Newline inserted");
384: return '\n';
385: }
386: if(ch<'0' || ch>'9') {
387: do ch=(*get)();
388: while(ch!=EOF && ch!='\n');
389: if(ch==EOF)
390: as_warn("EOF in Comment: Newline inserted");
391: state=0;
392: return '\n';
393: }
394: (*unget)(ch);
395: old_state=4;
396: state= -1;
397: out_string=".line ";
398: return *out_string++;
399:
400: } else if(IS_COMMENT(ch)) {
401: do ch=(*get)();
402: while(ch!=EOF && ch!='\n');
403: if(ch==EOF)
404: as_warn("EOF in comment: Newline inserted");
405: state=0;
406: return '\n';
407:
408: } else if(state==0) {
409: state=2;
410: return ch;
411: } else if(state==1) {
412: state=2;
413: return ch;
414: } else {
415: return ch;
416:
417: }
418: case EOF:
419: if(state==0)
420: return ch;
421: as_warn("End-of-File not at end of a line");
422: }
423: return -1;
424: }
425:
426: #ifdef NeXT /* .include feature */
427: void
428: save_scrub_context(
429: scrub_context_data *save_buffer_ptr)
430: {
431: save_buffer_ptr->last_scrub_file = scrub_file;
432: save_buffer_ptr->last_state = state;
433: save_buffer_ptr->last_old_state = old_state;
434: save_buffer_ptr->last_out_string = out_string;
435: memcpy(save_buffer_ptr->last_out_buf, out_buf, sizeof(out_buf));
436: save_buffer_ptr->last_add_newlines = add_newlines;
437:
438: state = 0;
439: old_state = 0;
440: out_string = NULL;
441: memset(out_buf, '\0', sizeof(out_buf));
442: add_newlines = 0;
443: }
444:
445: void
446: restore_scrub_context(
447: scrub_context_data *save_buffer_ptr)
448: {
449: scrub_file = save_buffer_ptr->last_scrub_file;
450: state = save_buffer_ptr->last_state;
451: old_state = save_buffer_ptr->last_old_state;
452: out_string = save_buffer_ptr->last_out_string;
453: memcpy(out_buf, save_buffer_ptr->last_out_buf, sizeof(out_buf));
454: add_newlines = save_buffer_ptr->last_add_newlines;
455: }
456: #endif /* NeXT .include feature */
457:
458: #ifdef TEST
459:
460: const char md_comment_chars[] = "|";
461: const char md_line_comment_chars[] = "#";
462:
463: int
464: get(
465: void)
466: {
467: return(getc(stdin));
468: }
469:
470: void
471: unget(
472: int ch)
473: {
474: ungetc(ch, stdin);
475: }
476:
477: void
478: main(
479: int argc,
480: char *argv[],
481: char *envp[])
482: {
483: int ch;
484:
485: while((ch = do_scrub_next_char(get, unget)) != EOF)
486: putc(ch, stdout);
487: }
488:
489: void
490: as_warn(
491: const char *format,
492: ...)
493: {
494: va_list ap;
495:
496: va_start(ap, format);
497: vfprintf(stderr, format, ap);
498: fprintf(stderr, "\n");
499: va_end(ap);
500: }
501: #endif /* TEST */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.