1 /* Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
3 Modified by Allen Wirfs-Brock, Instantiations Inc 2/90
5 /* This is the Assembler Pre-Processor
6 Copyright (C) 1987 Free Software Foundation, Inc.
8 This file is part of GAS, the GNU Assembler.
10 GAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 1, or (at your option)
15 GAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with GAS; see the file COPYING. If not, write to
22 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
24 /* App, the assembler pre-processor. This pre-processor strips out excess
25 spaces, turns single-quoted characters into a decimal constant, and turns
26 # <number> <filename> <garbage> into a .line <number>\n.app-file <filename> pair.
27 This needs better error-handling.
30 /* static const char rcsid[] = "$Id$"; */
33 #include "as.h" /* For BAD_CASE() only */
35 #if !defined(__STDC__) && !defined(const)
36 #define const /* Nothing */
39 static char lex [256];
40 static char symbol_chars[] =
41 "$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
43 /* These will go in BSS if not defined elsewhere, producing empty strings. */
44 extern const char comment_chars[];
45 extern const char line_comment_chars[];
46 extern const char line_separator_chars[];
48 #define LEX_IS_SYMBOL_COMPONENT 1
49 #define LEX_IS_WHITESPACE 2
50 #define LEX_IS_LINE_SEPARATOR 3
51 #define LEX_IS_COMMENT_START 4
52 #define LEX_IS_LINE_COMMENT_START 5
53 #define LEX_IS_TWOCHAR_COMMENT_1ST 6
54 #define LEX_IS_TWOCHAR_COMMENT_2ND 7
55 #define LEX_IS_STRINGQUOTE 8
56 #define LEX_IS_COLON 9
57 #define LEX_IS_NEWLINE 10
58 #define LEX_IS_ONECHAR_QUOTE 11
59 #define IS_SYMBOL_COMPONENT(c) (lex [c] == LEX_IS_SYMBOL_COMPONENT)
60 #define IS_WHITESPACE(c) (lex [c] == LEX_IS_WHITESPACE)
61 #define IS_LINE_SEPARATOR(c) (lex [c] == LEX_IS_LINE_SEPARATOR)
62 #define IS_COMMENT(c) (lex [c] == LEX_IS_COMMENT_START)
63 #define IS_LINE_COMMENT(c) (lex [c] == LEX_IS_LINE_COMMENT_START)
64 #define IS_NEWLINE(c) (lex [c] == LEX_IS_NEWLINE)
66 void do_scrub_begin() {
69 lex [' '] = LEX_IS_WHITESPACE;
70 lex ['\t'] = LEX_IS_WHITESPACE;
71 lex ['\n'] = LEX_IS_NEWLINE;
72 lex [';'] = LEX_IS_LINE_SEPARATOR;
73 lex ['"'] = LEX_IS_STRINGQUOTE;
74 lex ['\''] = LEX_IS_ONECHAR_QUOTE;
75 lex [':'] = LEX_IS_COLON;
77 /* Note that these override the previous defaults, e.g. if ';'
78 is a comment char, then it isn't a line separator. */
79 for (p =symbol_chars;*p;++p)
80 lex[*p] = LEX_IS_SYMBOL_COMPONENT;
81 for (p=comment_chars;*p;p++)
82 lex[*p] = LEX_IS_COMMENT_START;
83 for (p=line_comment_chars;*p;p++)
84 lex[*p] = LEX_IS_LINE_COMMENT_START;
85 for (p=line_separator_chars;*p;p++)
86 lex[*p] = LEX_IS_LINE_SEPARATOR;
88 /* Only allow slash-star comments if slash is not in use */
90 lex ['/'] = LEX_IS_TWOCHAR_COMMENT_1ST;
91 lex ['*'] = LEX_IS_TWOCHAR_COMMENT_2ND;
97 int scrub_from_file() {
98 return getc(scrub_file);
101 void scrub_to_file(ch)
104 ungetc(ch,scrub_file);
105 } /* scrub_to_file() */
108 char *scrub_last_string;
110 int scrub_from_string() {
111 return scrub_string == scrub_last_string ? EOF : *scrub_string++;
112 } /* scrub_from_string() */
114 void scrub_to_string(ch)
118 } /* scrub_to_string() */
120 /* Saved state of the scrubber */
122 static int old_state;
123 static char *out_string;
124 static char out_buf[20];
125 static int add_newlines = 0;
127 /* Data structure for saving the state of app across #include's. Note that
128 app is called asynchronously to the parsing of the .include's, so our
129 state at the time .include is interpreted is completely unrelated.
130 That's why we have to save it all. */
136 char out_buf[sizeof (out_buf)];
139 char *scrub_last_string;
144 register struct app_save *saved;
146 saved = (struct app_save *) xmalloc(sizeof (*saved));
147 saved->state = state;
148 saved->old_state = old_state;
149 saved->out_string = out_string;
150 bcopy(saved->out_buf, out_buf, sizeof(out_buf));
151 saved->add_newlines = add_newlines;
152 saved->scrub_string = scrub_string;
153 saved->scrub_last_string = scrub_last_string;
154 saved->scrub_file = scrub_file;
156 /* do_scrub_begin() is not useful, just wastes time. */
157 return (char *)saved;
163 register struct app_save *saved = (struct app_save *)arg;
165 /* There is no do_scrub_end (). */
166 state = saved->state;
167 old_state = saved->old_state;
168 out_string = saved->out_string;
169 bcopy (out_buf, saved->out_buf, sizeof (out_buf));
170 add_newlines = saved->add_newlines;
171 scrub_string = saved->scrub_string;
172 scrub_last_string = saved->scrub_last_string;
173 scrub_file = saved->scrub_file;
178 int do_scrub_next_char(get,unget)
182 /*State 0: beginning of normal line
183 1: After first whitespace on line (flush more white)
184 2: After first non-white (opcode) on line (keep 1white)
185 3: after second white on line (into operands) (flush white)
186 4: after putting out a .line, put out digits
187 5: parsing a string, then go to old-state
188 6: putting out \ escape in a "d string.
189 7: After putting out a .app-file, put out string.
190 8: After putting out a .app-file string, flush until newline.
191 -1: output string in out_string and go to the state in old_state
192 -2: flush text until a '*' '/' is seen, then go to state old_state
195 register int ch, ch2;
210 } while(ch!=EOF && ch!='\n' && ch!='*');
211 if(ch=='\n' || ch==EOF)
214 /* At this point, ch must be a '*' */
215 while ( (ch=(*get)()) == '*' ){
218 if(ch==EOF || ch=='/')
227 if(ch==EOF || (ch>='0' && ch<='9'))
230 while(ch!=EOF && IS_WHITESPACE(ch))
234 out_string="\n.app-file ";
237 return *out_string++;
239 while(ch!=EOF && ch!='\n')
250 } else if(ch=='\\') {
254 as_warn("End of file in string: inserted '\"'");
266 /* This is neet. Turn "string
267 more string" into "string\n more string"
283 #endif /* BACKSLASH_V */
294 #ifdef ONLY_STANDARD_ESCAPES
296 as_warn("Unknown escape '\\%c' in string: Ignored",ch);
298 #else /* ONLY_STANDARD_ESCAPES */
300 /* Accept \x as x for any x */
302 #endif /* ONLY_STANDARD_ESCAPES */
305 as_warn("End of file in string: '\"' inserted");
323 /* OK, we are somewhere in states 0 through 4 */
330 as_warn("End of file not at end of a line: Newline inserted.");
335 case LEX_IS_WHITESPACE:
337 while(ch!=EOF && IS_WHITESPACE(ch));
340 if(IS_COMMENT(ch) || (state==0 && IS_LINE_COMMENT(ch)) || ch=='/' || IS_LINE_SEPARATOR(ch)) {
344 case 0: state++; goto recycle; /* Punted leading sp */
345 case 1: BAD_CASE(state); /* We can't get here */
346 case 2: state++; (*unget)(ch); return ' '; /* Sp after opco */
347 case 3: goto recycle; /* Sp in operands */
348 default: BAD_CASE(state);
352 case LEX_IS_TWOCHAR_COMMENT_1ST:
354 if (ch2 != EOF && lex[ch2] == LEX_IS_TWOCHAR_COMMENT_2ND) {
358 if(ch2 != EOF && IS_NEWLINE(ch2))
361 (lex[ch2] != LEX_IS_TWOCHAR_COMMENT_2ND));
364 (lex[ch2] == LEX_IS_TWOCHAR_COMMENT_2ND)){
369 || lex[ch2] == LEX_IS_TWOCHAR_COMMENT_1ST)
374 as_warn("End of file in multiline comment");
385 case LEX_IS_STRINGQUOTE:
390 case LEX_IS_ONECHAR_QUOTE:
393 as_warn("End-of-file after a one-character quote; \000 inserted");
396 sprintf(out_buf,"%d", (int)(unsigned char)ch);
398 /* None of these 'x constants for us. We want 'x'.
400 if ( (ch=(*get)()) != '\'' ) {
401 #ifdef REQUIRE_CHAR_CLOSE_QUOTE
402 as_warn("Missing close quote: (assumed)");
411 return *out_string++;
419 /* Roll out a bunch of newlines from inside comments, etc. */
424 /* fall thru into... */
426 case LEX_IS_LINE_SEPARATOR:
430 case LEX_IS_LINE_COMMENT_START:
431 if (state != 0) /* Not at start of line, act normal */
434 while(ch!=EOF && IS_WHITESPACE(ch));
436 as_warn("EOF in comment: Newline inserted");
439 if(ch<'0' || ch>'9') {
440 /* Non-numerics: Eat whole comment line */
441 while(ch!=EOF && !IS_NEWLINE(ch))
444 as_warn("EOF in Comment: Newline inserted");
448 /* Numerics begin comment. Perhaps CPP `# 123 "filename"' */
453 return *out_string++;
455 case LEX_IS_COMMENT_START:
457 while(ch!=EOF && !IS_NEWLINE(ch));
459 as_warn("EOF in comment: Newline inserted");
465 /* Some relatively `normal' character. */
467 state=2; /* Now seeing opcode */
469 } else if(state==1) {
473 return ch; /* Opcode or operands already */
481 char comment_chars[] = "|";
482 char line_comment_chars[] = "#";
489 while((ch=do_scrub_next_char(stdin))!=EOF)