Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / gnu / usr.bin / as / app.c
1 /* This is the Assembler Pre-Processor
2    Copyright (C) 1987, 1990, 1991, 1992, 1994 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 2, 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 /* Modified by Allen Wirfs-Brock, Instantiations Inc 2/90 */
21 /* App, the assembler pre-processor.  This pre-processor strips out excess
22    spaces, turns single-quoted characters into a decimal constant, and turns
23    # <number> <filename> <garbage> into a .line <number>\n.file <filename>
24    pair.  This needs better error-handling.  */
25
26 /*
27  * $FreeBSD: src/gnu/usr.bin/as/app.c,v 1.7 1999/08/27 23:34:10 peter Exp $
28  * $DragonFly: src/gnu/usr.bin/as/Attic/app.c,v 1.2 2003/06/17 04:25:44 dillon Exp $
29  */
30 #include <stdio.h>
31 #include "as.h"                 /* For BAD_CASE() only */
32
33 #if (__STDC__ != 1)
34 #ifndef const
35 #define const  /* empty */
36 #endif
37 #endif
38
39 static char lex[256];
40 static const char symbol_chars[] =
41 "$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
42
43 #define LEX_IS_SYMBOL_COMPONENT         1
44 #define LEX_IS_WHITESPACE               2
45 #define LEX_IS_LINE_SEPARATOR           3
46 #define LEX_IS_COMMENT_START            4
47 #define LEX_IS_LINE_COMMENT_START       5
48 #define LEX_IS_TWOCHAR_COMMENT_1ST      6
49 #define LEX_IS_TWOCHAR_COMMENT_2ND      7
50 #define LEX_IS_STRINGQUOTE              8
51 #define LEX_IS_COLON                    9
52 #define LEX_IS_NEWLINE                  10
53 #define LEX_IS_ONECHAR_QUOTE            11
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_SEPARATOR(c)            (lex[c] == LEX_IS_LINE_SEPARATOR)
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 #define IS_NEWLINE(c)                   (lex[c] == LEX_IS_NEWLINE)
60
61 static int process_escape PARAMS ((int));
62
63 /* FIXME-soon: The entire lexer/parser thingy should be
64    built statically at compile time rather than dynamically
65    each and every time the assembler is run.  xoxorich. */
66
67 void
68 do_scrub_begin ()
69 {
70   const char *p;
71
72   lex[' '] = LEX_IS_WHITESPACE;
73   lex['\t'] = LEX_IS_WHITESPACE;
74   lex['\n'] = LEX_IS_NEWLINE;
75   lex[';'] = LEX_IS_LINE_SEPARATOR;
76   lex['"'] = LEX_IS_STRINGQUOTE;
77 #ifndef TC_HPPA
78   lex['\''] = LEX_IS_ONECHAR_QUOTE;
79 #endif
80   lex[':'] = LEX_IS_COLON;
81
82
83
84 #ifdef SINGLE_QUOTE_STRINGS
85   lex['\''] = LEX_IS_STRINGQUOTE;
86 #endif
87
88   /* Note that these override the previous defaults, e.g. if ';' is a
89      comment char, then it isn't a line separator.  */
90   for (p = symbol_chars; *p; ++p)
91     {
92       lex[(unsigned char) *p] = LEX_IS_SYMBOL_COMPONENT;
93     }                           /* declare symbol characters */
94
95   for (p = comment_chars; *p; p++)
96     {
97       lex[(unsigned char) *p] = LEX_IS_COMMENT_START;
98     }                           /* declare comment chars */
99
100   for (p = line_comment_chars; *p; p++)
101     {
102       lex[(unsigned char) *p] = LEX_IS_LINE_COMMENT_START;
103     }                           /* declare line comment chars */
104
105   for (p = line_separator_chars; *p; p++)
106     {
107       lex[(unsigned char) *p] = LEX_IS_LINE_SEPARATOR;
108     }                           /* declare line separators */
109
110   /* Only allow slash-star comments if slash is not in use */
111   if (lex['/'] == 0)
112     {
113       lex['/'] = LEX_IS_TWOCHAR_COMMENT_1ST;
114     }
115   /* FIXME-soon.  This is a bad hack but otherwise, we can't do
116      c-style comments when '/' is a line comment char. xoxorich. */
117   if (lex['*'] == 0)
118     {
119       lex['*'] = LEX_IS_TWOCHAR_COMMENT_2ND;
120     }
121 }                               /* do_scrub_begin() */
122
123 FILE *scrub_file;
124
125 int
126 scrub_from_file ()
127 {
128   return getc (scrub_file);
129 }
130
131 void
132 scrub_to_file (ch)
133      int ch;
134 {
135   ungetc (ch, scrub_file);
136 }                               /* scrub_to_file() */
137
138 char *scrub_string;
139 char *scrub_last_string;
140
141 int
142 scrub_from_string ()
143 {
144   return scrub_string == scrub_last_string ? EOF : *scrub_string++;
145 }                               /* scrub_from_string() */
146
147 void
148 scrub_to_string (ch)
149      int ch;
150 {
151   *--scrub_string = ch;
152 }                               /* scrub_to_string() */
153
154 /* Saved state of the scrubber */
155 static int state;
156 static int old_state;
157 static char *out_string;
158 static char out_buf[20];
159 static int add_newlines = 0;
160
161 /* Data structure for saving the state of app across #include's.  Note that
162    app is called asynchronously to the parsing of the .include's, so our
163    state at the time .include is interpreted is completely unrelated.
164    That's why we have to save it all.  */
165
166 struct app_save
167   {
168     int state;
169     int old_state;
170     char *out_string;
171     char out_buf[sizeof (out_buf)];
172     int add_newlines;
173     char *scrub_string;
174     char *scrub_last_string;
175     FILE *scrub_file;
176   };
177
178 char *
179 app_push ()
180 {
181   register struct app_save *saved;
182
183   saved = (struct app_save *) xmalloc (sizeof (*saved));
184   saved->state = state;
185   saved->old_state = old_state;
186   saved->out_string = out_string;
187   memcpy (saved->out_buf, out_buf, sizeof (out_buf));
188   saved->add_newlines = add_newlines;
189   saved->scrub_string = scrub_string;
190   saved->scrub_last_string = scrub_last_string;
191   saved->scrub_file = scrub_file;
192
193   /* do_scrub_begin() is not useful, just wastes time. */
194   return (char *) saved;
195 }
196
197 void
198 app_pop (arg)
199      char *arg;
200 {
201   register struct app_save *saved = (struct app_save *) arg;
202
203   /* There is no do_scrub_end (). */
204   state = saved->state;
205   old_state = saved->old_state;
206   out_string = saved->out_string;
207   memcpy (out_buf, saved->out_buf, sizeof (out_buf));
208   add_newlines = saved->add_newlines;
209   scrub_string = saved->scrub_string;
210   scrub_last_string = saved->scrub_last_string;
211   scrub_file = saved->scrub_file;
212
213   free (arg);
214 }                               /* app_pop() */
215
216 /* @@ This assumes that \n &c are the same on host and target.  This is not
217    necessarily true.  */
218 static int
219 process_escape (ch)
220      int ch;
221 {
222   switch (ch)
223     {
224     case 'b':
225       return '\b';
226     case 'f':
227       return '\f';
228     case 'n':
229       return '\n';
230     case 'r':
231       return '\r';
232     case 't':
233       return '\t';
234     case '\'':
235       return '\'';
236     case '"':
237       return '\"';
238     default:
239       return ch;
240     }
241 }
242 int
243 do_scrub_next_char (get, unget)
244      int (*get) ();
245      void (*unget) ();
246 {
247   /*State 0: beginning of normal line
248           1: After first whitespace on line (flush more white)
249           2: After first non-white (opcode) on line (keep 1white)
250           3: after second white on line (into operands) (flush white)
251           4: after putting out a .line, put out digits
252           5: parsing a string, then go to old-state
253           6: putting out \ escape in a "d string.
254           7: After putting out a .appfile, put out string.
255           8: After putting out a .appfile string, flush until newline.
256           9: After seeing symbol char in state 3 (keep 1white after symchar)
257          10: After seeing whitespace in state 9 (keep white before symchar)
258          11: After seeing a symbol character in state 0 (eg a label definition)
259          -1: output string in out_string and go to the state in old_state
260          -2: flush text until a '*' '/' is seen, then go to state old_state
261           */
262
263   /* I added states 9 and 10 because the MIPS ECOFF assembler uses
264      constructs like ``.loc 1 20''.  This was turning into ``.loc
265      120''.  States 9 and 10 ensure that a space is never dropped in
266      between characters which could appear in a identifier.  Ian
267      Taylor, ian@cygnus.com.
268
269      I added state 11 so that something like "Lfoo add %r25,%r26,%r27" works
270      correctly on the PA (and any other target where colons are optional).
271      Jeff Law, law@cs.utah.edu.  */
272
273   register int ch, ch2 = 0;
274   int not_cpp_line = 0;
275
276   switch (state)
277     {
278     case -1:
279       ch = *out_string++;
280       if (*out_string == 0)
281         {
282           state = old_state;
283           old_state = 3;
284         }
285       return ch;
286
287     case -2:
288       for (;;)
289         {
290           do
291             {
292               ch = (*get) ();
293             }
294           while (ch != EOF && ch != '\n' && ch != '*');
295           if (ch == '\n' || ch == EOF)
296             return ch;
297
298           /* At this point, ch must be a '*' */
299           while ((ch = (*get) ()) == '*')
300             {
301               ;
302             }
303           if (ch == EOF || ch == '/')
304             break;
305           (*unget) (ch);
306         }
307       state = old_state;
308       return ' ';
309
310     case 4:
311       ch = (*get) ();
312       if (ch == EOF || (ch >= '0' && ch <= '9'))
313         return ch;
314       else
315         {
316           while (ch != EOF && IS_WHITESPACE (ch))
317             ch = (*get) ();
318           if (ch == '"')
319             {
320               (*unget) (ch);
321               out_string = "\n\t.appfile ";
322               old_state = 7;
323               state = -1;
324               return *out_string++;
325             }
326           else
327             {
328               while (ch != EOF && ch != '\n')
329                 ch = (*get) ();
330               state = 0;
331               return ch;
332             }
333         }
334
335     case 5:
336       ch = (*get) ();
337       if (lex[ch] == LEX_IS_STRINGQUOTE)
338         {
339           state = old_state;
340           return ch;
341         }
342 #ifndef NO_STRING_ESCAPES
343       else if (ch == '\\')
344         {
345           state = 6;
346           return ch;
347         }
348 #endif
349       else if (ch == EOF)
350         {
351           as_warn ("End of file in string: inserted '\"'");
352           state = old_state;
353           (*unget) ('\n');
354           return '"';
355         }
356       else
357         {
358           return ch;
359         }
360
361     case 6:
362       state = 5;
363       ch = (*get) ();
364       switch (ch)
365         {
366           /* Handle strings broken across lines, by turning '\n' into
367              '\\' and 'n'.  */
368         case '\n':
369           (*unget) ('n');
370           add_newlines++;
371           return '\\';
372
373         case '"':
374         case '\\':
375         case 'b':
376         case 'f':
377         case 'n':
378         case 'r':
379         case 't':
380 #ifdef BACKSLASH_V
381         case 'v':
382 #endif /* BACKSLASH_V */
383         case 'x':
384         case 'X':
385         case '0':
386         case '1':
387         case '2':
388         case '3':
389         case '4':
390         case '5':
391         case '6':
392         case '7':
393           break;
394 #if defined(IGNORE_NONSTANDARD_ESCAPES) | defined(ONLY_STANDARD_ESCAPES)
395         default:
396           as_warn ("Unknown escape '\\%c' in string: Ignored", ch);
397           break;
398 #else /* ONLY_STANDARD_ESCAPES */
399         default:
400           /* Accept \x as x for any x */
401           break;
402 #endif /* ONLY_STANDARD_ESCAPES */
403
404         case EOF:
405           as_warn ("End of file in string: '\"' inserted");
406           return '"';
407         }
408       return ch;
409
410     case 7:
411       ch = (*get) ();
412       state = 5;
413       old_state = 8;
414       return ch;
415
416     case 8:
417       do
418         ch = (*get) ();
419       while (ch != '\n');
420       state = 0;
421       return ch;
422     }
423
424   /* OK, we are somewhere in states 0 through 4 or 9 through 11 */
425
426   /* flushchar: */
427   ch = (*get) ();
428 recycle:
429   if (ch == EOF)
430     {
431       if (state != 0)
432         as_warn ("End of file not at end of a line: Newline inserted.");
433       return ch;
434     }
435
436   switch (lex[ch])
437     {
438     case LEX_IS_WHITESPACE:
439       do
440         /* Preserve a single whitespace character at the beginning of
441            a line.  */
442         if (state == 0)
443           {
444             state = 1;
445             return ch;
446           }
447         else
448           ch = (*get) ();
449       while (ch != EOF && IS_WHITESPACE (ch));
450       if (ch == EOF)
451         return ch;
452
453       if (IS_COMMENT (ch)
454           || (state == 0 && IS_LINE_COMMENT (ch))
455           || ch == '/'
456           || IS_LINE_SEPARATOR (ch))
457         {
458           /* cpp never outputs a leading space before the #, so try to
459              avoid being confused.  */
460           not_cpp_line = 1;
461           goto recycle;
462         }
463 #ifdef MRI
464       (*unget) (ch);            /* Put back */
465       return ' ';               /* Always return one space at start of line */
466 #endif
467
468       /* If we're in state 2 or 11, we've seen a non-white character
469          followed by whitespace.  If the next character is ':', this
470          is whitespace after a label name which we *must* ignore.  */
471       if ((state == 2 || state == 11) && lex[ch] == LEX_IS_COLON)
472         {
473           state = 1;
474           return ch;
475         }
476
477       switch (state)
478         {
479         case 0:
480           state++;
481           goto recycle;         /* Punted leading sp */
482         case 1:
483           /* We can arrive here if we leave a leading whitespace character
484              at the beginning of a line.  */
485           goto recycle;
486         case 2:
487           state = 3;
488           (*unget) (ch);
489           return ' ';           /* Sp after opco */
490         case 3:
491           goto recycle;         /* Sp in operands */
492         case 9:
493         case 10:
494           state = 10;           /* Sp after symbol char */
495           goto recycle;
496         case 11:
497           state = 1;
498           (*unget) (ch);
499           return ' ';           /* Sp after label definition.  */
500         default:
501           BAD_CASE (state);
502         }
503       break;
504
505     case LEX_IS_TWOCHAR_COMMENT_1ST:
506       ch2 = (*get) ();
507       if (ch2 != EOF && lex[ch2] == LEX_IS_TWOCHAR_COMMENT_2ND)
508         {
509           for (;;)
510             {
511               do
512                 {
513                   ch2 = (*get) ();
514                   if (ch2 != EOF && IS_NEWLINE (ch2))
515                     add_newlines++;
516                 }
517               while (ch2 != EOF &&
518                      (lex[ch2] != LEX_IS_TWOCHAR_COMMENT_2ND));
519
520               while (ch2 != EOF &&
521                      (lex[ch2] == LEX_IS_TWOCHAR_COMMENT_2ND))
522                 {
523                   ch2 = (*get) ();
524                 }
525
526               if (ch2 == EOF
527                   || lex[ch2] == LEX_IS_TWOCHAR_COMMENT_1ST)
528                 break;
529               (*unget) (ch);
530             }
531           if (ch2 == EOF)
532             as_warn ("End of file in multiline comment");
533
534           ch = ' ';
535           goto recycle;
536         }
537       else
538         {
539           if (ch2 != EOF)
540             (*unget) (ch2);
541           if (state == 9 || state == 10)
542             state = 3;
543           return ch;
544         }
545       break;
546
547     case LEX_IS_STRINGQUOTE:
548       if (state == 9 || state == 10)
549         old_state = 3;
550       else
551         old_state = state;
552       state = 5;
553       return ch;
554 #ifndef MRI
555 #ifndef IEEE_STYLE
556     case LEX_IS_ONECHAR_QUOTE:
557       ch = (*get) ();
558       if (ch == EOF)
559         {
560           as_warn ("End-of-file after a one-character quote; \\000 inserted");
561           ch = 0;
562         }
563       if (ch == '\\')
564         {
565           ch = (*get) ();
566           ch = process_escape (ch);
567         }
568       sprintf (out_buf, "%d", (int) (unsigned char) ch);
569
570
571       /* None of these 'x constants for us.  We want 'x'.  */
572       if ((ch = (*get) ()) != '\'')
573         {
574 #ifdef REQUIRE_CHAR_CLOSE_QUOTE
575           as_warn ("Missing close quote: (assumed)");
576 #else
577           (*unget) (ch);
578 #endif
579         }
580       if (strlen (out_buf) == 1)
581         {
582           return out_buf[0];
583         }
584       if (state == 9 || state == 10)
585         old_state = 3;
586       else
587         old_state = state;
588       state = -1;
589       out_string = out_buf;
590       return *out_string++;
591 #endif
592 #endif
593     case LEX_IS_COLON:
594       if (state == 9 || state == 10)
595         state = 3;
596       else if (state != 3)
597         state = 1;
598       return ch;
599
600     case LEX_IS_NEWLINE:
601       /* Roll out a bunch of newlines from inside comments, etc.  */
602       if (add_newlines)
603         {
604           --add_newlines;
605           (*unget) (ch);
606         }
607       /* fall thru into... */
608
609     case LEX_IS_LINE_SEPARATOR:
610       state = 0;
611       return ch;
612
613     case LEX_IS_LINE_COMMENT_START:
614       if (state == 0)           /* Only comment at start of line.  */
615         {
616           /* FIXME-someday: The two character comment stuff was badly
617              thought out.  On i386, we want '/' as line comment start
618              AND we want C style comments.  hence this hack.  The
619              whole lexical process should be reworked.  xoxorich.  */
620           if (ch == '/')
621             {
622               ch2 = (*get) ();
623               if (ch2 == '*')
624                 {
625                   state = -2;
626                   return (do_scrub_next_char (get, unget));
627                 }
628               else
629                 {
630                   (*unget) (ch2);
631                 }
632             }                   /* bad hack */
633
634           if (ch != '#')
635             not_cpp_line = 1;
636
637           do
638             ch = (*get) ();
639           while (ch != EOF && IS_WHITESPACE (ch));
640           if (ch == EOF)
641             {
642               as_warn ("EOF in comment:  Newline inserted");
643               return '\n';
644             }
645           if (ch < '0' || ch > '9' || not_cpp_line)
646             {
647               /* Non-numerics:  Eat whole comment line */
648               while (ch != EOF && !IS_NEWLINE (ch))
649                 ch = (*get) ();
650               if (ch == EOF)
651                 as_warn ("EOF in Comment: Newline inserted");
652               state = 0;
653               return '\n';
654             }
655           /* Numerics begin comment.  Perhaps CPP `# 123 "filename"' */
656           (*unget) (ch);
657           old_state = 4;
658           state = -1;
659           out_string = "\t.appline ";
660           return *out_string++;
661         }
662
663       /* We have a line comment character which is not at the start of
664          a line.  If this is also a normal comment character, fall
665          through.  Otherwise treat it as a default character.  */
666       if (strchr (comment_chars, ch) == NULL)
667         goto de_fault;
668       /* Fall through.  */
669     case LEX_IS_COMMENT_START:
670       do
671         ch = (*get) ();
672       while (ch != EOF && !IS_NEWLINE (ch));
673       if (ch == EOF)
674         as_warn ("EOF in comment:  Newline inserted");
675       state = 0;
676       return '\n';
677
678     case LEX_IS_SYMBOL_COMPONENT:
679       if (state == 10)
680         {
681           /* This is a symbol character following another symbol
682              character, with whitespace in between.  We skipped the
683              whitespace earlier, so output it now.  */
684           (*unget) (ch);
685           state = 3;
686           return ' ';
687         }
688       if (state == 3)
689         state = 9;
690       /* Fall through.  */
691     default:
692     de_fault:
693       /* Some relatively `normal' character.  */
694       if (state == 0)
695         {
696           state = 11;           /* Now seeing label definition */
697           return ch;
698         }
699       else if (state == 1)
700         {
701           state = 2;            /* Ditto */
702           return ch;
703         }
704       else if (state == 9)
705         {
706           if (lex[ch] != LEX_IS_SYMBOL_COMPONENT)
707             state = 3;
708           return ch;
709         }
710       else if (state == 10)
711         {
712           state = 3;
713           return ch;
714         }
715       else
716         {
717           return ch;            /* Opcode or operands already */
718         }
719     }
720   return -1;
721 }
722
723 #ifdef TEST
724
725 const char comment_chars[] = "|";
726 const char line_comment_chars[] = "#";
727
728 main ()
729 {
730   int ch;
731
732   app_begin ();
733   while ((ch = do_scrub_next_char (stdin)) != EOF)
734     putc (ch, stdout);
735 }
736
737 as_warn (str)
738      char *str;
739 {
740   fputs (str, stderr);
741   putc ('\n', stderr);
742 }
743
744 #endif
745
746 /* end of app.c */