/* This is the Assembler Pre-Processor
Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2002, 2003
+ 1999, 2000, 2001, 2002, 2003, 2006, 2007
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
- GAS is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ GAS is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to the Free
- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
-/* Modified by Allen Wirfs-Brock, Instantiations Inc 2/90 */
-/* App, the assembler pre-processor. This pre-processor strips out excess
- spaces, turns single-quoted characters into a decimal constant, and turns
- # <number> <filename> <garbage> into a .line <number>\n.file <filename>
- pair. This needs better error-handling. */
+/* Modified by Allen Wirfs-Brock, Instantiations Inc 2/90. */
+/* App, the assembler pre-processor. This pre-processor strips out
+ excess spaces, turns single-quoted characters into a decimal
+ constant, and turns the # in # <number> <filename> <garbage> into a
+ .linefile. This needs better error-handling. */
-#include <stdio.h>
-#include "as.h" /* For BAD_CASE() only */
+#include "as.h"
#if (__STDC__ != 1)
#ifndef const
#endif
#endif
+#ifdef H_TICK_HEX
+int enable_h_tick_hex = 0;
+#endif
+
#ifdef TC_M68K
/* Whether we are scrubbing in m68k MRI mode. This is different from
flag_m68k_mri, because the two flags will be affected by the .mri
#define LEX_IS_DOUBLEBAR_1ST 13
#endif
#define LEX_IS_PARALLEL_SEPARATOR 14
+#ifdef H_TICK_HEX
+#define LEX_IS_H 15
+#endif
#define IS_SYMBOL_COMPONENT(c) (lex[c] == LEX_IS_SYMBOL_COMPONENT)
#define IS_WHITESPACE(c) (lex[c] == LEX_IS_WHITESPACE)
#define IS_LINE_SEPARATOR(c) (lex[c] == LEX_IS_LINE_SEPARATOR)
#define IS_LINE_COMMENT(c) (lex[c] == LEX_IS_LINE_COMMENT_START)
#define IS_NEWLINE(c) (lex[c] == LEX_IS_NEWLINE)
-static int process_escape PARAMS ((int));
+static int process_escape (int);
/* FIXME-soon: The entire lexer/parser thingy should be
built statically at compile time rather than dynamically
each and every time the assembler is run. xoxorich. */
void
-do_scrub_begin (m68k_mri)
- int m68k_mri ATTRIBUTE_UNUSED;
+do_scrub_begin (int m68k_mri ATTRIBUTE_UNUSED)
{
const char *p;
int c;
lex['"'] = LEX_IS_STRINGQUOTE;
#if ! defined (TC_HPPA) && ! defined (TC_I370)
- /* I370 uses single-quotes to delimit integer, float constants */
+ /* I370 uses single-quotes to delimit integer, float constants. */
lex['\''] = LEX_IS_ONECHAR_QUOTE;
#endif
/* Note that these override the previous defaults, e.g. if ';' is a
comment char, then it isn't a line separator. */
for (p = symbol_chars; *p; ++p)
- {
- lex[(unsigned char) *p] = LEX_IS_SYMBOL_COMPONENT;
- } /* declare symbol characters */
+ lex[(unsigned char) *p] = LEX_IS_SYMBOL_COMPONENT;
for (c = 128; c < 256; ++c)
lex[c] = LEX_IS_SYMBOL_COMPONENT;
#define tc_comment_chars comment_chars
#endif
for (p = tc_comment_chars; *p; p++)
- {
- lex[(unsigned char) *p] = LEX_IS_COMMENT_START;
- } /* declare comment chars */
+ lex[(unsigned char) *p] = LEX_IS_COMMENT_START;
for (p = line_comment_chars; *p; p++)
- {
- lex[(unsigned char) *p] = LEX_IS_LINE_COMMENT_START;
- } /* declare line comment chars */
+ lex[(unsigned char) *p] = LEX_IS_LINE_COMMENT_START;
for (p = line_separator_chars; *p; p++)
- {
- lex[(unsigned char) *p] = LEX_IS_LINE_SEPARATOR;
- } /* declare line separators */
+ lex[(unsigned char) *p] = LEX_IS_LINE_SEPARATOR;
#ifdef tc_parallel_separator_chars
/* This macro permits the processor to specify all characters which
separate parallel insns on the same line. */
for (p = tc_parallel_separator_chars; *p; p++)
- {
- lex[(unsigned char) *p] = LEX_IS_PARALLEL_SEPARATOR;
- } /* declare parallel separators */
+ lex[(unsigned char) *p] = LEX_IS_PARALLEL_SEPARATOR;
#endif
/* Only allow slash-star comments if slash is not in use.
FIXME: This isn't right. We should always permit them. */
if (lex['/'] == 0)
- {
- lex['/'] = LEX_IS_TWOCHAR_COMMENT_1ST;
- }
+ lex['/'] = LEX_IS_TWOCHAR_COMMENT_1ST;
#ifdef TC_M68K
if (m68k_mri)
lex['|'] = LEX_IS_DOUBLEBAR_1ST;
#endif
#ifdef TC_D30V
- /* must do this is we want VLIW instruction with "->" or "<-" */
+ /* Must do this is we want VLIW instruction with "->" or "<-". */
lex['-'] = LEX_IS_SYMBOL_COMPONENT;
#endif
-} /* do_scrub_begin() */
-/* Saved state of the scrubber */
+#ifdef H_TICK_HEX
+ if (enable_h_tick_hex)
+ {
+ lex['h'] = LEX_IS_H;
+ lex['H'] = LEX_IS_H;
+ }
+#endif
+}
+
+/* Saved state of the scrubber. */
static int state;
static int old_state;
static char *out_string;
state at the time .include is interpreted is completely unrelated.
That's why we have to save it all. */
-struct app_save {
+struct app_save
+{
int state;
int old_state;
char * out_string;
};
char *
-app_push ()
+app_push (void)
{
register struct app_save *saved;
}
void
-app_pop (arg)
- char *arg;
+app_pop (char *arg)
{
register struct app_save *saved = (struct app_save *) arg;
#endif
free (arg);
-} /* app_pop() */
+}
/* @@ This assumes that \n &c are the same on host and target. This is not
necessarily true. */
+
static int
-process_escape (ch)
- int ch;
+process_escape (int ch)
{
switch (ch)
{
This is the way the old code used to work. */
int
-do_scrub_chars (get, tostart, tolen)
- int (*get) PARAMS ((char *, int));
- char *tostart;
- int tolen;
+do_scrub_chars (int (*get) (char *, int), char *tostart, int tolen)
{
char *to = tostart;
char *toend = tostart + tolen;
char *fromend;
int fromlen;
register int ch, ch2 = 0;
+ /* Character that started the string we're working on. */
+ static char quotechar;
/*State 0: beginning of normal line
1: After first whitespace on line (flush more white)
2: After first non-white (opcode) on line (keep 1white)
3: after second white on line (into operands) (flush white)
- 4: after putting out a .line, put out digits
+ 4: after putting out a .linefile, put out digits
5: parsing a string, then go to old-state
6: putting out \ escape in a "d string.
- 7: After putting out a .appfile, put out string.
- 8: After putting out a .appfile string, flush until newline.
+ 7: no longer used
+ 8: no longer used
9: After seeing symbol char in state 3 (keep 1white after symchar)
10: After seeing whitespace in state 9 (keep white before symchar)
11: After seeing a symbol character in state 0 (eg a label definition)
#ifdef DOUBLEBAR_PARALLEL
13: After seeing a vertical bar, looking for a second
vertical bar as a parallel expression separator.
+#endif
+#ifdef TC_IA64
+ 14: After seeing a `(' at state 0, looking for a `)' as
+ predicate.
+ 15: After seeing a `(' at state 1, looking for a `)' as
+ predicate.
+#endif
+#ifdef TC_Z80
+ 16: After seeing an 'a' or an 'A' at the start of a symbol
+ 17: After seeing an 'f' or an 'F' in state 16
#endif
*/
ch = GET ();
if (ch == '"')
{
- UNGET (ch);
- if (scrub_m68k_mri)
- out_string = "\n\tappfile ";
- else
- out_string = "\n\t.appfile ";
- old_state = 7;
- state = -1;
- PUT (*out_string++);
+ quotechar = ch;
+ state = 5;
+ old_state = 3;
+ PUT (ch);
}
else
{
for (s = from; s < fromend; s++)
{
ch = *s;
- /* This condition must be changed if the type of any
- other character can be LEX_IS_STRINGQUOTE. */
if (ch == '\\'
- || ch == '"'
- || ch == '\''
+ || ch == quotechar
|| ch == '\n')
break;
}
memcpy (to, from, len);
to += len;
from += len;
+ if (to >= toend)
+ goto tofull;
}
}
ch = GET ();
if (ch == EOF)
{
- as_warn (_("end of file in string; inserted '\"'"));
+ /* This buffer is here specifically so
+ that the UNGET below will work. */
+ static char one_char_buf[1];
+
+ as_warn (_("end of file in string; '%c' inserted"), quotechar);
state = old_state;
+ from = fromend = one_char_buf + 1;
+ fromlen = 1;
UNGET ('\n');
- PUT ('"');
+ PUT (quotechar);
}
- else if (lex[ch] == LEX_IS_STRINGQUOTE)
+ else if (ch == quotechar)
{
state = old_state;
PUT (ch);
else if (scrub_m68k_mri && ch == '\n')
{
/* Just quietly terminate the string. This permits lines like
- bne label loop if we haven't reach end yet
- */
+ bne label loop if we haven't reach end yet. */
state = old_state;
UNGET (ch);
PUT ('\'');
continue;
case EOF:
- as_warn (_("end of file in string; '\"' inserted"));
- PUT ('"');
+ as_warn (_("end of file in string; '%c' inserted"), quotechar);
+ PUT (quotechar);
continue;
case '"':
PUT (ch);
continue;
- case 7:
- ch = GET ();
- state = 5;
- old_state = 8;
- if (ch == EOF)
- goto fromeof;
- PUT (ch);
- continue;
-
- case 8:
- do
- ch = GET ();
- while (ch != '\n' && ch != EOF);
- if (ch == EOF)
- goto fromeof;
- state = 0;
- PUT (ch);
- continue;
-
#ifdef DOUBLEBAR_PARALLEL
case 13:
ch = GET ();
state = 1;
PUT ('|');
continue;
+#endif
+#ifdef TC_Z80
+ case 16:
+ /* We have seen an 'a' at the start of a symbol, look for an 'f'. */
+ ch = GET ();
+ if (ch == 'f' || ch == 'F')
+ {
+ state = 17;
+ PUT (ch);
+ }
+ else
+ {
+ state = 9;
+ break;
+ }
+ case 17:
+ /* We have seen "af" at the start of a symbol,
+ a ' here is a part of that symbol. */
+ ch = GET ();
+ state = 9;
+ if (ch == '\'')
+ /* Change to avoid warning about unclosed string. */
+ PUT ('`');
+ else if (ch != EOF)
+ UNGET (ch);
+ break;
#endif
}
- /* OK, we are somewhere in states 0 through 4 or 9 through 11 */
+ /* OK, we are somewhere in states 0 through 4 or 9 through 11. */
/* flushchar: */
ch = GET ();
+#ifdef TC_IA64
+ if (ch == '(' && (state == 0 || state == 1))
+ {
+ state += 14;
+ PUT (ch);
+ continue;
+ }
+ else if (state == 14 || state == 15)
+ {
+ if (ch == ')')
+ {
+ state -= 14;
+ PUT (ch);
+ ch = GET ();
+ }
+ else
+ {
+ PUT (ch);
+ continue;
+ }
+ }
+#endif
+
recycle:
#if defined TC_ARM && defined OBJ_ELF
/* Only keep this white if there's no white *after* the
colon. */
ch2 = GET ();
- UNGET (ch2);
+ if (ch2 != EOF)
+ UNGET (ch2);
if (!IS_WHITESPACE (ch2))
{
state = 9;
switch (state)
{
- case 0:
- state++;
- goto recycle; /* Punted leading sp */
case 1:
/* We can arrive here if we leave a leading whitespace
character at the beginning of a line. */
break;
case LEX_IS_STRINGQUOTE:
+ quotechar = ch;
if (state == 10)
{
- /* Preserve the whitespace in foo "bar" */
+ /* Preserve the whitespace in foo "bar". */
UNGET (ch);
state = 3;
PUT (' ');
#ifndef IEEE_STYLE
case LEX_IS_ONECHAR_QUOTE:
+#ifdef H_TICK_HEX
+ if (state == 9 && enable_h_tick_hex)
+ {
+ char c;
+
+ c = GET ();
+ as_warn ("'%c found after symbol", c);
+ UNGET (c);
+ }
+#endif
if (state == 10)
{
- /* Preserve the whitespace in foo 'b' */
+ /* Preserve the whitespace in foo 'b'. */
UNGET (ch);
state = 3;
PUT (' ');
ch2 = GET ();
if (ch2 != '-')
{
- UNGET (ch2);
+ if (ch2 != EOF)
+ UNGET (ch2);
goto de_fault;
}
/* Read and skip to end of line. */
ch = GET ();
}
while (ch != EOF && ch != '\n');
+
if (ch == EOF)
- {
- as_warn (_("end of file in comment; newline inserted"));
- }
+ as_warn (_("end of file in comment; newline inserted"));
+
state = 0;
PUT ('\n');
break;
#ifdef DOUBLEBAR_PARALLEL
case LEX_IS_DOUBLEBAR_1ST:
ch2 = GET ();
- UNGET (ch2);
+ if (ch2 != EOF)
+ UNGET (ch2);
if (ch2 != '|')
- {
- goto de_fault;
- }
+ goto de_fault;
+
/* Handle '||' in two states as invoking PUT twice might
result in the first one jumping out of this loop. We'd
then lose track of the state and one '|' char. */
{
UNGET (ch2);
}
- } /* bad hack */
+ }
if (state == 0 || state == 1) /* Only comment at start of line. */
{
ch = GET ();
}
while (ch != EOF && IS_WHITESPACE (ch));
+
if (ch == EOF)
{
as_warn (_("end of file in comment; newline inserted"));
PUT ('\n');
break;
}
+
if (ch < '0' || ch > '9' || state != 0 || startch != '#')
{
/* Not a cpp line. */
old_state = 4;
state = -1;
if (scrub_m68k_mri)
- out_string = "\tappline ";
+ out_string = "\tlinefile ";
else
- out_string = "\t.appline ";
+ out_string = "\t.linefile ";
PUT (*out_string++);
break;
}
if ((symver_state != NULL) && (*symver_state == 0))
goto de_fault;
#endif
+
+#ifdef TC_ARM
+ /* For the ARM, care is needed not to damage occurrences of \@
+ by stripping the @ onwards. Yuck. */
+ if (to > tostart && *(to - 1) == '\\')
+ /* Do not treat the @ as a start-of-comment. */
+ goto de_fault;
+#endif
+
#ifdef WARN_COMMENTS
if (!found_comment)
as_where (&found_comment_file, &found_comment);
PUT ('\n');
break;
+#ifdef H_TICK_HEX
+ case LEX_IS_H:
+ /* Look for strings like H'[0-9A-Fa-f] and if found, replace
+ the H' with 0x to make them gas-style hex characters. */
+ if (enable_h_tick_hex)
+ {
+ char quot;
+
+ quot = GET ();
+ if (quot == '\'')
+ {
+ UNGET ('x');
+ ch = '0';
+ }
+ else
+ UNGET (quot);
+ }
+ /* FALL THROUGH */
+#endif
+
case LEX_IS_SYMBOL_COMPONENT:
if (state == 10)
{
break;
}
+#ifdef TC_Z80
+ /* "af'" is a symbol containing '\''. */
+ if (state == 3 && (ch == 'a' || ch == 'A'))
+ {
+ state = 16;
+ PUT (ch);
+ ch = GET ();
+ if (ch == 'f' || ch == 'F')
+ {
+ state = 17;
+ PUT (ch);
+ break;
+ }
+ else
+ {
+ state = 9;
+ if (!IS_SYMBOL_COMPONENT (ch))
+ {
+ if (ch != EOF)
+ UNGET (ch);
+ break;
+ }
+ }
+ }
+#endif
if (state == 3)
state = 9;
&& type != LEX_IS_SYMBOL_COMPONENT)
break;
}
+
if (s > from)
- {
- /* Handle the last character normally, for
- simplicity. */
- --s;
- }
+ /* Handle the last character normally, for
+ simplicity. */
+ --s;
+
len = s - from;
+
if (len > (toend - to) - 1)
len = (toend - to) - 1;
+
if (len > 0)
{
PUT (ch);
- if (len > 8)
- {
- memcpy (to, from, len);
- to += len;
- from += len;
- }
- else
- {
- switch (len)
- {
- case 8: *to++ = *from++;
- case 7: *to++ = *from++;
- case 6: *to++ = *from++;
- case 5: *to++ = *from++;
- case 4: *to++ = *from++;
- case 3: *to++ = *from++;
- case 2: *to++ = *from++;
- case 1: *to++ = *from++;
- }
- }
+ memcpy (to, from, len);
+ to += len;
+ from += len;
+ if (to >= toend)
+ goto tofull;
ch = GET ();
}
}
/* Some relatively `normal' character. */
if (state == 0)
{
- state = 11; /* Now seeing label definition */
+ state = 11; /* Now seeing label definition. */
}
else if (state == 1)
{
- state = 2; /* Ditto */
+ state = 2; /* Ditto. */
}
else if (state == 9)
{
- if (lex[ch] != LEX_IS_SYMBOL_COMPONENT)
+ if (!IS_SYMBOL_COMPONENT (ch))
state = 3;
}
else if (state == 10)
the space. We don't have enough information to
make the right choice, so here we are making the
choice which is more likely to be correct. */
- PUT (' ');
+ if (to + 1 >= toend)
+ {
+ /* If we're near the end of the buffer, save the
+ character for the next time round. Otherwise
+ we'll lose our state. */
+ UNGET (ch);
+ goto tofull;
+ }
+ *to++ = ' ';
}
state = 3;
return to - tostart;
}
-
-/* end of app.c */