Commit | Line | Data |
---|---|---|
515eb9d8 C |
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 | #ifdef USG | |
27 | #define bzero(s,n) memset(s,0,n) | |
28 | #endif | |
29 | #if !defined(__STDC__) && !defined(const) | |
30 | #define const /* Nothing */ | |
31 | #endif | |
32 | ||
33 | static char lex [256]; | |
34 | static const char symbol_chars[] = | |
35 | "$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; | |
36 | ||
37 | extern const char comment_chars[]; | |
38 | extern const char line_comment_chars[]; | |
39 | ||
40 | #define LEX_IS_SYMBOL_COMPONENT (1) | |
41 | #define LEX_IS_WHITESPACE (2) | |
42 | #define LEX_IS_LINE_SEPERATOR (4) | |
43 | #define LEX_IS_COMMENT_START (8) /* JF added these two */ | |
44 | #define LEX_IS_LINE_COMMENT_START (16) | |
45 | #define IS_SYMBOL_COMPONENT(c) (lex [c] & LEX_IS_SYMBOL_COMPONENT) | |
46 | #define IS_WHITESPACE(c) (lex [c] & LEX_IS_WHITESPACE) | |
47 | #define IS_LINE_SEPERATOR(c) (lex [c] & LEX_IS_LINE_SEPERATOR) | |
48 | #define IS_COMMENT(c) (lex [c] & LEX_IS_COMMENT_START) | |
49 | #define IS_LINE_COMMENT(c) (lex [c] & LEX_IS_LINE_COMMENT_START) | |
50 | ||
51 | void | |
52 | do_scrub_begin() | |
53 | { | |
54 | const char *p; | |
55 | ||
56 | bzero (lex, sizeof(lex)); /* Trust NOBODY! */ | |
57 | lex [' '] |= LEX_IS_WHITESPACE; | |
58 | lex ['\t'] |= LEX_IS_WHITESPACE; | |
59 | for (p =symbol_chars;*p;++p) | |
60 | lex [*p] |= LEX_IS_SYMBOL_COMPONENT; | |
61 | lex ['\n'] |= LEX_IS_LINE_SEPERATOR; | |
62 | #ifdef DONTDEF | |
63 | lex [':'] |= LEX_IS_LINE_SEPERATOR; | |
64 | #endif | |
65 | lex [';'] |= LEX_IS_LINE_SEPERATOR; | |
66 | for (p=comment_chars;*p;p++) | |
67 | lex[*p] |= LEX_IS_COMMENT_START; | |
68 | for (p=line_comment_chars;*p;p++) | |
69 | lex[*p] |= LEX_IS_LINE_COMMENT_START; | |
70 | } | |
71 | ||
72 | FILE *scrub_file; | |
73 | ||
74 | int | |
75 | scrub_from_file() | |
76 | { | |
77 | return getc(scrub_file); | |
78 | } | |
79 | ||
80 | void | |
81 | scrub_to_file(ch) | |
82 | int ch; | |
83 | { | |
84 | ungetc(ch,scrub_file); | |
85 | } | |
86 | ||
87 | char *scrub_string; | |
88 | char *scrub_last_string; | |
89 | ||
90 | int | |
91 | scrub_from_string() | |
92 | { | |
93 | return scrub_string == scrub_last_string ? EOF : *scrub_string++; | |
94 | } | |
95 | ||
96 | void | |
97 | scrub_to_string(ch) | |
98 | int ch; | |
99 | { | |
100 | *--scrub_string=ch; | |
101 | } | |
102 | ||
103 | int | |
104 | do_scrub_next_char(get,unget) | |
105 | int (*get)(); | |
106 | void (*unget)(); | |
107 | /* FILE *fp; */ | |
108 | { | |
109 | /* State 0: beginning of normal line | |
110 | 1: After first whitespace on normal line (flush more white) | |
111 | 2: After first non-white on normal line (keep 1white) | |
112 | 3: after second white on normal line (flush white) | |
113 | 4: after putting out a .line, put out digits | |
114 | 5: parsing a string, then go to old-state | |
115 | 6: putting out \ escape in a "d string. | |
116 | 7: After putting out a .file, put out string. | |
117 | 8: After putting out a .file string, flush until newline. | |
118 | -1: output string in out_string and go to the state in old_state | |
119 | -2: flush text until a '*' '/' is seen, then go to state old_state | |
120 | */ | |
121 | ||
122 | static state; | |
123 | static old_state; | |
124 | static char *out_string; | |
125 | static char out_buf[20]; | |
126 | static add_newlines; | |
127 | int ch; | |
128 | ||
129 | if(state==-1) { | |
130 | ch= *out_string++; | |
131 | if(*out_string==0) { | |
132 | state=old_state; | |
133 | old_state=3; | |
134 | } | |
135 | return ch; | |
136 | } | |
137 | if(state==-2) { | |
138 | for(;;) { | |
139 | do ch=(*get)(); | |
140 | while(ch!=EOF && ch!='\n' && ch!='*'); | |
141 | if(ch=='\n' || ch==EOF) | |
142 | return ch; | |
143 | ch=(*get)(); | |
144 | if(ch==EOF || ch=='/') | |
145 | break; | |
146 | (*unget)(ch); | |
147 | } | |
148 | state=old_state; | |
149 | return ' '; | |
150 | } | |
151 | if(state==4) { | |
152 | ch=(*get)(); | |
153 | if(ch==EOF || (ch>='0' && ch<='9')) | |
154 | return ch; | |
155 | else { | |
156 | while(ch!=EOF && IS_WHITESPACE(ch)) | |
157 | ch=(*get)(); | |
158 | if(ch=='"') { | |
159 | (*unget)(ch); | |
160 | out_string="; .file "; | |
161 | old_state=7; | |
162 | state= -1; | |
163 | return *out_string++; | |
164 | } else { | |
165 | while(ch!=EOF && ch!='\n') | |
166 | ch=(*get)(); | |
167 | return ch; | |
168 | } | |
169 | } | |
170 | } | |
171 | if(state==5) { | |
172 | ch=(*get)(); | |
173 | if(ch=='"') { | |
174 | state=old_state; | |
175 | return '"'; | |
176 | } else if(ch=='\\') { | |
177 | state=6; | |
178 | return ch; | |
179 | } else if(ch==EOF) { | |
180 | as_warn("End of file in string: inserted '\"'"); | |
181 | state=old_state; | |
182 | (*unget)('\n'); | |
183 | return '"'; | |
184 | } else { | |
185 | return ch; | |
186 | } | |
187 | } | |
188 | if(state==6) { | |
189 | state=5; | |
190 | ch=(*get)(); | |
191 | switch(ch) { | |
192 | /* This is neet. Turn "string | |
193 | more string" into "string\n more string" | |
194 | */ | |
195 | case '\n': | |
196 | (*unget)('n'); | |
197 | add_newlines++; | |
198 | return '\\'; | |
199 | ||
200 | case '"': | |
201 | case '\\': | |
202 | case 'b': | |
203 | case 'f': | |
204 | case 'n': | |
205 | case 'r': | |
206 | case 't': | |
207 | case '0': | |
208 | case '1': | |
209 | case '2': | |
210 | case '3': | |
211 | case '4': | |
212 | case '5': | |
213 | case '6': | |
214 | case '7': | |
215 | break; | |
216 | default: | |
217 | as_warn("Unknown escape '\\%c' in string: Ignored",ch); | |
218 | break; | |
219 | ||
220 | case EOF: | |
221 | as_warn("End of file in string: '\"' inserted"); | |
222 | return '"'; | |
223 | } | |
224 | return ch; | |
225 | } | |
226 | ||
227 | if(state==7) { | |
228 | ch=(*get)(); | |
229 | state=5; | |
230 | old_state=8; | |
231 | return ch; | |
232 | } | |
233 | ||
234 | if(state==8) { | |
235 | do ch= (*get)(); | |
236 | while(ch!='\n'); | |
237 | state=0; | |
238 | return ch; | |
239 | } | |
240 | ||
241 | flushchar: | |
242 | ch=(*get)(); | |
243 | switch(ch) { | |
244 | case ' ': | |
245 | case '\t': | |
246 | do ch=(*get)(); | |
247 | while(ch!=EOF && IS_WHITESPACE(ch)); | |
248 | if(ch==EOF) | |
249 | return ch; | |
250 | if(IS_COMMENT(ch) || (state==0 && IS_LINE_COMMENT(ch)) || ch=='/' || IS_LINE_SEPERATOR(ch)) { | |
251 | (*unget)(ch); | |
252 | goto flushchar; | |
253 | } | |
254 | (*unget)(ch); | |
255 | if(state==0 || state==2) { | |
256 | state++; | |
257 | return ' '; | |
258 | } else goto flushchar; | |
259 | ||
260 | case '/': | |
261 | ch=(*get)(); | |
262 | if(ch=='*') { | |
263 | for(;;) { | |
264 | do { | |
265 | ch=(*get)(); | |
266 | if(ch=='\n') | |
267 | add_newlines++; | |
268 | } while(ch!=EOF && ch!='*'); | |
269 | ch=(*get)(); | |
270 | if(ch==EOF || ch=='/') | |
271 | break; | |
272 | (*unget)(ch); | |
273 | } | |
274 | if(ch==EOF) | |
275 | as_warn("End of file in '/' '*' string: */ inserted"); | |
276 | ||
277 | (*unget)(' '); | |
278 | goto flushchar; | |
279 | } else { | |
280 | if(IS_COMMENT('/') || (state==0 && IS_LINE_COMMENT('/'))) { | |
281 | (*unget)(ch); | |
282 | ch='/'; | |
283 | goto deal_misc; | |
284 | } | |
285 | if(ch!=EOF) | |
286 | (*unget)(ch); | |
287 | return '/'; | |
288 | } | |
289 | break; | |
290 | ||
291 | case '"': | |
292 | old_state=state; | |
293 | state=5; | |
294 | return '"'; | |
295 | break; | |
296 | ||
297 | case '\'': | |
298 | ch=(*get)(); | |
299 | if(ch==EOF) { | |
300 | as_warn("End-of-file after a ': \000 inserted"); | |
301 | ch=0; | |
302 | } | |
303 | sprintf(out_buf,"(%d)",ch&0xff); | |
304 | old_state=state; | |
305 | state= -1; | |
306 | out_string=out_buf; | |
307 | return *out_string++; | |
308 | ||
309 | case ':': | |
310 | if(state!=3) | |
311 | state=0; | |
312 | return ch; | |
313 | ||
314 | case '\n': | |
315 | if(add_newlines) { | |
316 | --add_newlines; | |
317 | (*unget)(ch); | |
318 | } | |
319 | case ';': | |
320 | state=0; | |
321 | return ch; | |
322 | ||
323 | default: | |
324 | deal_misc: | |
325 | if(state==0 && IS_LINE_COMMENT(ch)) { | |
326 | do ch=(*get)(); | |
327 | while(ch!=EOF && IS_WHITESPACE(ch)); | |
328 | if(ch==EOF) { | |
329 | as_warn("EOF in comment: Newline inserted"); | |
330 | return '\n'; | |
331 | } | |
332 | if(ch<'0' || ch>'9') { | |
333 | while(ch!=EOF && ch!='\n') | |
334 | ch=(*get)(); | |
335 | if(ch==EOF) | |
336 | as_warn("EOF in Comment: Newline inserted"); | |
337 | state=0; | |
338 | return '\n'; | |
339 | } | |
340 | (*unget)(ch); | |
341 | old_state=4; | |
342 | state= -1; | |
343 | out_string=".line "; | |
344 | return *out_string++; | |
345 | ||
346 | } else if(IS_COMMENT(ch)) { | |
347 | do ch=(*get)(); | |
348 | while(ch!=EOF && ch!='\n'); | |
349 | if(ch==EOF) | |
350 | as_warn("EOF in comment: Newline inserted"); | |
351 | state=0; | |
352 | return '\n'; | |
353 | ||
354 | } else if(state==0) { | |
355 | state=2; | |
356 | return ch; | |
357 | } else if(state==1) { | |
358 | state=2; | |
359 | return ch; | |
360 | } else { | |
361 | return ch; | |
362 | ||
363 | } | |
364 | case EOF: | |
365 | if(state==0) | |
366 | return ch; | |
367 | as_warn("End-of-File not at end of a line"); | |
368 | } | |
369 | return -1; | |
370 | } | |
371 | ||
372 | #ifdef TEST | |
373 | ||
374 | char comment_chars[] = "|"; | |
375 | char line_comment_chars[] = "#"; | |
376 | ||
377 | main() | |
378 | { | |
379 | int ch; | |
380 | ||
381 | app_begin(); | |
382 | while((ch=do_scrub_next_char(stdin))!=EOF) | |
383 | putc(ch,stdout); | |
384 | } | |
385 | ||
386 | as_warn(str) | |
387 | char *str; | |
388 | { | |
389 | fputs(str,stderr); | |
390 | putc('\n',stderr); | |
391 | } | |
392 | #endif |