/* Lexical analyzer for C and Objective C.
- Copyright (C) 1987, 88, 89, 92, 94-96, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1989, 1992, 1994, 1995, 1996, 1997
+ 1998, 1999, 2000 Free Software Foundation, Inc.
This file is part of GNU CC.
Boston, MA 02111-1307, USA. */
#include "config.h"
-
-#include <stdio.h>
-#include <errno.h>
-#include <setjmp.h>
+#include "system.h"
#include "rtl.h"
#include "tree.h"
#include "input.h"
+#include "output.h"
#include "c-lex.h"
#include "c-tree.h"
#include "flags.h"
#include "c-parse.h"
#include "c-pragma.h"
-
-#include <ctype.h>
+#include "toplev.h"
+#include "intl.h"
+#include "ggc.h"
+#include "tm_p.h"
/* MULTIBYTE_CHARS support only works for native compilers.
??? Ideally what we want is to model widechar support after
#endif
#ifdef MULTIBYTE_CHARS
-#include <stdlib.h>
+#include "mbchar.h"
#include <locale.h>
-#endif
-
-#ifndef errno
-extern int errno;
+#endif /* MULTIBYTE_CHARS */
+#ifndef GET_ENVIRONMENT
+#define GET_ENVIRONMENT(ENV_VALUE,ENV_NAME) ((ENV_VALUE) = getenv (ENV_NAME))
#endif
#if USE_CPPLIB
#include "cpplib.h"
-cpp_reader parse_in;
-cpp_options parse_options;
-static enum cpp_token cpp_token;
+extern cpp_reader parse_in;
+extern cpp_options parse_options;
+#else
+/* Stream for reading from the input file. */
+FILE *finput;
#endif
+extern void yyprint PARAMS ((FILE *, int, YYSTYPE));
+
/* The elements of `ridpointers' are identifier nodes
for the reserved type names and storage classes.
It is indexed by a RID_... value. */
#define YYDEBUG 1
#if USE_CPPLIB
-static unsigned char *yy_cur, *yy_lim;
+extern unsigned char *yy_cur, *yy_lim;
+extern enum cpp_token cpp_token;
-int
-yy_get_token ()
+extern int yy_get_token ();
+
+#define GETC() (yy_cur < yy_lim ? *yy_cur++ : yy_get_token ())
+#define UNGETC(c) ((c) == EOF ? 0 : yy_cur--)
+
+#else /* ! USE_CPPLIB */
+
+#define GETC() getch ()
+#define UNGETC(c) put_back (c)
+
+struct putback_buffer {
+ unsigned char *buffer;
+ int buffer_size;
+ int index;
+};
+
+static struct putback_buffer putback = {NULL, 0, -1};
+
+static inline int getch PARAMS ((void));
+
+static inline int
+getch ()
{
- for (;;)
+ if (putback.index != -1)
{
- parse_in.limit = parse_in.token_buffer;
- cpp_token = cpp_get_token (&parse_in);
- if (cpp_token == CPP_EOF)
- return -1;
- yy_lim = CPP_PWRITTEN (&parse_in);
- yy_cur = parse_in.token_buffer;
- if (yy_cur < yy_lim)
- return *yy_cur++;
+ int ch = putback.buffer[putback.index];
+ --putback.index;
+ return ch;
}
+ return getc (finput);
}
-#define GETC() (yy_cur < yy_lim ? *yy_cur++ : yy_get_token ())
-#define UNGETC(c) ((c), yy_cur--)
-#else
-#define GETC() getc (finput)
-#define UNGETC(c) ungetc (c, finput)
-#endif
+static inline void put_back PARAMS ((int));
+
+static inline void
+put_back (ch)
+ int ch;
+{
+ if (ch != EOF)
+ {
+ if (putback.index == putback.buffer_size - 1)
+ {
+ putback.buffer_size += 16;
+ putback.buffer = xrealloc (putback.buffer, putback.buffer_size);
+ }
+ putback.buffer[++putback.index] = ch;
+ }
+}
+#endif /* ! USE_CPPLIB */
+
+int linemode;
/* the declaration found for the last IDENTIFIER token read in.
yylex must look this up to detect typedefs, which get token type TYPENAME,
int doing_objc_thang;
-extern tree is_class_name ();
-
extern int yydebug;
/* File used for outputting assembler code. */
extern FILE *asm_out_file;
-#ifndef WCHAR_TYPE_SIZE
-#ifdef INT_TYPE_SIZE
-#define WCHAR_TYPE_SIZE INT_TYPE_SIZE
-#else
-#define WCHAR_TYPE_SIZE BITS_PER_WORD
-#endif
-#endif
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE TYPE_PRECISION (wchar_type_node)
/* Number of bytes in a wide character. */
#define WCHAR_BYTES (WCHAR_TYPE_SIZE / BITS_PER_UNIT)
Actual allocated length is maxtoken + 2.
This is not static because objc-parse.y uses it. */
-static int indent_level = 0; /* Number of { minus number of }. */
+static int indent_level; /* Number of { minus number of }. */
+
+/* Nonzero tells yylex to ignore \ in string constants. */
+static int ignore_escape_flag;
/* Nonzero if end-of-file has been seen on input. */
static int end_of_file;
-#if !USE_CPPLIB
-/* Buffered-back input character; faster than using ungetc. */
-static int nextchar = -1;
-#endif
-
-static int skip_white_space PROTO((int));
-static char *extend_token_buffer PROTO((char *));
-static int readescape PROTO((int *));
-int check_newline ();
+#ifdef HANDLE_GENERIC_PRAGMAS
+static int handle_generic_pragma PARAMS ((int));
+#endif /* HANDLE_GENERIC_PRAGMAS */
+static int whitespace_cr PARAMS ((int));
+static int skip_white_space PARAMS ((int));
+static char *extend_token_buffer PARAMS ((const char *));
+static int readescape PARAMS ((int *));
+static void parse_float PARAMS ((PTR));
+static void extend_token_buffer_to PARAMS ((int));
+static int read_line_number PARAMS ((int *));
\f
/* Do not insert generated code into the source, instead, include it.
This allows us to build gcc automatically even for targets that
wordlist[i].name = "inout";
else if (wordlist[i].rid == RID_BYCOPY)
wordlist[i].name = "bycopy";
+ else if (wordlist[i].rid == RID_BYREF)
+ wordlist[i].name = "byref";
else if (wordlist[i].rid == RID_ONEWAY)
- wordlist[i].name = "oneway";
+ wordlist[i].name = "oneway";
}
\f
-#if USE_CPPLIB
-void
+char *
init_parse (filename)
char *filename;
{
- init_lex ();
- yy_cur = "\n";
- yy_lim = yy_cur+1;
+#if !USE_CPPLIB
+ /* Open input file. */
+ if (filename == 0 || !strcmp (filename, "-"))
+ {
+ finput = stdin;
+ filename = "stdin";
+ }
+ else
+ finput = fopen (filename, "r");
+ if (finput == 0)
+ pfatal_with_name (filename);
- cpp_reader_init (&parse_in);
- parse_in.data = &parse_options;
- cpp_options_init (&parse_options);
- cpp_handle_options (&parse_in, 0, NULL); /* FIXME */
+#ifdef IO_BUFFER_SIZE
+ setvbuf (finput, (char *) xmalloc (IO_BUFFER_SIZE), _IOFBF, IO_BUFFER_SIZE);
+#endif
+#else /* !USE_CPPLIB */
parse_in.show_column = 1;
if (! cpp_start_read (&parse_in, filename))
abort ();
+
+ if (filename == 0 || !strcmp (filename, "-"))
+ filename = "stdin";
+
+ /* cpp_start_read always puts at least one line directive into the
+ token buffer. We must arrange to read it out here. */
+ yy_cur = parse_in.token_buffer;
+ yy_lim = CPP_PWRITTEN (&parse_in);
+ cpp_token = CPP_DIRECTIVE;
+#endif
+
+ init_lex ();
+ init_pragma ();
+
+ return filename;
}
void
finish_parse ()
{
+#if USE_CPPLIB
cpp_finish (&parse_in);
-}
+ errorcount += parse_in.errors;
+#else
+ fclose (finput);
#endif
+}
void
init_lex ()
#ifdef MULTIBYTE_CHARS
/* Change to the native locale for multibyte conversions. */
setlocale (LC_CTYPE, "");
+ GET_ENVIRONMENT (literal_codeset, "LANG");
#endif
maxtoken = 40;
ridpointers[(int) RID_SIGNED] = get_identifier ("signed");
ridpointers[(int) RID_INLINE] = get_identifier ("inline");
ridpointers[(int) RID_CONST] = get_identifier ("const");
+ ridpointers[(int) RID_RESTRICT] = get_identifier ("restrict");
ridpointers[(int) RID_VOLATILE] = get_identifier ("volatile");
+ ridpointers[(int) RID_BOUNDED] = get_identifier ("__bounded");
+ ridpointers[(int) RID_UNBOUNDED] = get_identifier ("__unbounded");
ridpointers[(int) RID_AUTO] = get_identifier ("auto");
ridpointers[(int) RID_STATIC] = get_identifier ("static");
ridpointers[(int) RID_EXTERN] = get_identifier ("extern");
ridpointers[(int) RID_OUT] = get_identifier ("out");
ridpointers[(int) RID_INOUT] = get_identifier ("inout");
ridpointers[(int) RID_BYCOPY] = get_identifier ("bycopy");
+ ridpointers[(int) RID_BYREF] = get_identifier ("byref");
ridpointers[(int) RID_ONEWAY] = get_identifier ("oneway");
forget_protocol_qualifiers();
if (flag_traditional)
{
UNSET_RESERVED_WORD ("const");
+ UNSET_RESERVED_WORD ("restrict");
UNSET_RESERVED_WORD ("volatile");
UNSET_RESERVED_WORD ("typeof");
UNSET_RESERVED_WORD ("signed");
UNSET_RESERVED_WORD ("iterator");
UNSET_RESERVED_WORD ("complex");
}
+ else if (!flag_isoc99)
+ UNSET_RESERVED_WORD ("restrict");
+
if (flag_no_asm)
{
UNSET_RESERVED_WORD ("asm");
if (TREE_CODE (t) == INTEGER_CST)
fprintf (file,
#if HOST_BITS_PER_WIDE_INT == 64
-#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+ " 0x%x%016x",
+#else
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
" 0x%lx%016lx",
#else
- " 0x%x%016x",
+ " 0x%llx%016llx",
+#endif
#endif
#else
#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
\f
/* Iff C is a carriage return, warn about it - if appropriate -
and return nonzero. */
-int
+
+static int
whitespace_cr (c)
int c;
{
Also, there's no need, since cpp removes all comments. */
case '\n':
+ if (linemode)
+ {
+ UNGETC (c);
+ return EOF;
+ }
c = check_newline ();
break;
case '\f':
case '\v':
case '\b':
- c = GETC();
+#if USE_CPPLIB
+ /* While processing a # directive we don't get CPP_HSPACE
+ tokens, so we also need to handle whitespace the normal way. */
+ if (cpp_token == CPP_HSPACE)
+ c = yy_get_token ();
+ else
+#endif
+ c = GETC();
break;
case '\r':
}
}
-/* Skips all of the white space at the current location in the input file.
- Must use and reset nextchar if it has the next character. */
+/* Skips all of the white space at the current location in the input file. */
void
position_after_white_space ()
{
register int c;
-#if !USE_CPPLIB
- if (nextchar != -1)
- c = nextchar, nextchar = -1;
- else
-#endif
- c = GETC();
+ c = GETC();
UNGETC (skip_white_space (c));
}
-/* Like skip_white_space, but don't advance beyond the end of line.
- Moreover, we don't get passed a character to start with. */
-static int
-skip_white_space_on_line ()
-{
- register int c;
-
- while (1)
- {
- c = GETC();
- switch (c)
- {
- case '\n':
- default:
- break;
-
- case ' ':
- case '\t':
- case '\f':
- case '\v':
- case '\b':
- continue;
-
- case '\r':
- whitespace_cr (c);
- continue;
- }
- break;
- }
- return c;
-}
-
/* Make the token buffer longer, preserving the data in it.
P should point to just beyond the last valid character in the old buffer.
The value we return is a pointer to the new buffer
at a place corresponding to P. */
+static void
+extend_token_buffer_to (size)
+ int size;
+{
+ do
+ maxtoken = maxtoken * 2 + 10;
+ while (maxtoken < size);
+ token_buffer = (char *) xrealloc (token_buffer, maxtoken + 2);
+}
+
static char *
extend_token_buffer (p)
- char *p;
+ const char *p;
{
int offset = p - token_buffer;
-
- maxtoken = maxtoken * 2 + 10;
- token_buffer = (char *) xrealloc (token_buffer, maxtoken + 2);
-
+ extend_token_buffer_to (offset);
return token_buffer + offset;
}
\f
-#if !USE_CPPLIB
-#define GET_DIRECTIVE_LINE() get_directive_line (finput)
-#else /* USE_CPPLIB */
-/* Read the rest of a #-directive from input stream FINPUT.
- In normal use, the directive name and the white space after it
- have already been read, so they won't be included in the result.
- We allow for the fact that the directive line may contain
- a newline embedded within a character or string literal which forms
- a part of the directive.
-
- The value is a string in a reusable buffer. It remains valid
- only until the next time this function is called. */
+#if defined HANDLE_PRAGMA
+/* Local versions of these macros, that can be passed as function pointers. */
+static int
+pragma_getc ()
+{
+ return GETC ();
+}
-static char *
-GET_DIRECTIVE_LINE ()
+static void
+pragma_ungetc (arg)
+ int arg;
{
- static char *directive_buffer = NULL;
- static unsigned buffer_length = 0;
- register char *p;
- register char *buffer_limit;
- register int looking_for = 0;
- register int char_escaped = 0;
+ UNGETC (arg);
+}
+#endif
- if (buffer_length == 0)
+static int
+read_line_number (num)
+ int *num;
+{
+ register int token = yylex ();
+
+ if (token == CONSTANT
+ && TREE_CODE (yylval.ttype) == INTEGER_CST)
{
- directive_buffer = (char *)xmalloc (128);
- buffer_length = 128;
+ *num = TREE_INT_CST_LOW (yylval.ttype);
+ return 1;
}
-
- buffer_limit = &directive_buffer[buffer_length];
-
- for (p = directive_buffer; ; )
+ else
{
- int c;
-
- /* Make buffer bigger if it is full. */
- if (p >= buffer_limit)
- {
- register unsigned bytes_used = (p - directive_buffer);
-
- buffer_length *= 2;
- directive_buffer
- = (char *)xrealloc (directive_buffer, buffer_length);
- p = &directive_buffer[bytes_used];
- buffer_limit = &directive_buffer[buffer_length];
- }
-
- c = GETC ();
-
- /* Discard initial whitespace. */
- if ((c == ' ' || c == '\t') && p == directive_buffer)
- continue;
-
- /* Detect the end of the directive. */
- if (c == '\n' && looking_for == 0)
- {
- UNGETC (c);
- c = '\0';
- }
-
- *p++ = c;
-
- if (c == 0)
- return directive_buffer;
-
- /* Handle string and character constant syntax. */
- if (looking_for)
- {
- if (looking_for == c && !char_escaped)
- looking_for = 0; /* Found terminator... stop looking. */
- }
- else
- if (c == '\'' || c == '"')
- looking_for = c; /* Don't stop buffering until we see another
- another one of these (or an EOF). */
-
- /* Handle backslash. */
- char_escaped = (c == '\\' && ! char_escaped);
+ if (token != END_OF_LINE)
+ error ("invalid #-line");
+ return 0;
}
}
-#endif /* USE_CPPLIB */
-\f
+
/* At the beginning of a line, increment the line number
and process any #-directive on this line.
If the line is a #-directive, read the entire line and return a newline.
- Otherwise, return the line's first non-whitespace character. */
+ Otherwise, return the line's first non-whitespace character.
+
+ Note that in the case of USE_CPPLIB, we get the whole line as one
+ CPP_DIRECTIVE token. */
int
check_newline ()
{
register int c;
register int token;
+ int saw_line;
+ enum { act_none, act_push, act_pop } action;
+ int old_lineno, action_number, l;
- lineno++;
-
+ restart:
/* Read first nonwhite char on the line. */
- c = GETC();
- while (c == ' ' || c == '\t')
- c = GETC();
+#ifdef USE_CPPLIB
+ c = GETC ();
+ /* In some cases where we're leaving an include file, we can get multiple
+ CPP_HSPACE tokens in a row, so we need to loop. */
+ while (cpp_token == CPP_HSPACE)
+ c = yy_get_token ();
+#else
+ do
+ c = GETC ();
+ while (c == ' ' || c == '\t');
+#endif
+
+ lineno++;
if (c != '#')
{
+ /* Sequences of multiple newlines are very common; optimize them. */
+ if (c == '\n')
+ goto restart;
+
/* If not #, return it so caller will use it. */
return c;
}
- /* Read first nonwhite char after the `#'. */
-
- c = GETC();
- while (c == ' ' || c == '\t')
- c = GETC();
+ /* Don't read beyond this line. */
+ saw_line = 0;
+ linemode = 1;
+
+#if USE_CPPLIB
+ if (cpp_token == CPP_VSPACE)
+ {
+ /* Format is "<space> <line number> <filename> <newline>".
+ Only the line number is interesting, and even that
+ we can get more efficiently than scanning the line. */
+ yy_cur = yy_lim - 1;
+ lineno = parse_in.lineno - 1;
+ goto skipline;
+ }
+#endif
- /* If a letter follows, then if the word here is `line', skip
- it and ignore it; otherwise, ignore the line, with an error
- if the word isn't `pragma', `ident', `define', or `undef'. */
+ token = yylex ();
- if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
+ if (token == IDENTIFIER)
{
- if (c == 'p')
+ /* If a letter follows, then if the word here is `line', skip
+ it and ignore it; otherwise, ignore the line, with an error
+ if the word isn't `pragma'. */
+
+ const char *name = IDENTIFIER_POINTER (yylval.ttype);
+
+ if (!strcmp (name, "pragma"))
{
- if (GETC() == 'r'
- && GETC() == 'a'
- && GETC() == 'g'
- && GETC() == 'm'
- && GETC() == 'a'
- && ((c = GETC()) == ' ' || c == '\t' || c == '\n'
- || whitespace_cr (c) ))
- {
- while (c == ' ' || c == '\t' || whitespace_cr (c))
- c = GETC ();
- if (c == '\n')
- return c;
-#ifdef HANDLE_SYSV_PRAGMA
- UNGETC (c);
- token = yylex ();
- if (token != IDENTIFIER)
- goto skipline;
- return handle_sysv_pragma (token);
-#else /* !HANDLE_SYSV_PRAGMA */
+ token = yylex ();
+ if (token != IDENTIFIER
+ || TREE_CODE (yylval.ttype) != IDENTIFIER_NODE)
+ goto skipline;
+
#ifdef HANDLE_PRAGMA
-#if !USE_CPPLIB
- UNGETC (c);
- token = yylex ();
- if (token != IDENTIFIER)
- goto skipline;
- if (HANDLE_PRAGMA (finput, yylval.ttype))
- {
- c = GETC ();
- return c;
- }
-#else
- ??? do not know what to do ???;
-#endif /* !USE_CPPLIB */
+ /* We invoke HANDLE_PRAGMA before HANDLE_GENERIC_PRAGMAS
+ (if both are defined), in order to give the back
+ end a chance to override the interpretation of
+ SYSV style pragmas. */
+ if (HANDLE_PRAGMA (pragma_getc, pragma_ungetc,
+ IDENTIFIER_POINTER (yylval.ttype)))
+ goto skipline;
#endif /* HANDLE_PRAGMA */
-#endif /* !HANDLE_SYSV_PRAGMA */
- goto skipline;
- }
- }
+
+#ifdef HANDLE_GENERIC_PRAGMAS
+ if (handle_generic_pragma (token))
+ goto skipline;
+#endif /* HANDLE_GENERIC_PRAGMAS */
+
+ /* Issue a warning message if we have been asked to do so.
+ Ignoring unknown pragmas in system header file unless
+ an explcit -Wunknown-pragmas has been given. */
+ if (warn_unknown_pragmas > 1
+ || (warn_unknown_pragmas && ! in_system_header))
+ warning ("ignoring pragma: %s", token_buffer);
- else if (c == 'd')
+ goto skipline;
+ }
+ else if (!strcmp (name, "define"))
{
- if (GETC() == 'e'
- && GETC() == 'f'
- && GETC() == 'i'
- && GETC() == 'n'
- && GETC() == 'e'
- && ((c = GETC()) == ' ' || c == '\t' || c == '\n'))
- {
- if (c != '\n')
- debug_define (lineno, GET_DIRECTIVE_LINE ());
- goto skipline;
- }
+ debug_define (lineno, GET_DIRECTIVE_LINE ());
+ goto skipline;
}
- else if (c == 'u')
+ else if (!strcmp (name, "undef"))
{
- if (GETC() == 'n'
- && GETC() == 'd'
- && GETC() == 'e'
- && GETC() == 'f'
- && ((c = GETC()) == ' ' || c == '\t' || c == '\n'))
- {
- if (c != '\n')
- debug_undef (lineno, GET_DIRECTIVE_LINE ());
- goto skipline;
- }
+ debug_undef (lineno, GET_DIRECTIVE_LINE ());
+ goto skipline;
}
- else if (c == 'l')
+ else if (!strcmp (name, "line"))
{
- if (GETC() == 'i'
- && GETC() == 'n'
- && GETC() == 'e'
- && ((c = GETC()) == ' ' || c == '\t'))
- goto linenum;
+ saw_line = 1;
+ token = yylex ();
+ goto linenum;
}
- else if (c == 'i')
+ else if (!strcmp (name, "ident"))
{
- if (GETC() == 'd'
- && GETC() == 'e'
- && GETC() == 'n'
- && GETC() == 't'
- && ((c = GETC()) == ' ' || c == '\t'))
- {
- /* #ident. The pedantic warning is now in cccp.c. */
-
- /* Here we have just seen `#ident '.
- A string constant should follow. */
+ /* #ident. The pedantic warning is now in cccp.c. */
- c = skip_white_space_on_line ();
+ /* Here we have just seen `#ident '.
+ A string constant should follow. */
- /* If no argument, ignore the line. */
- if (c == '\n')
- return c;
-
- UNGETC (c);
- token = yylex ();
- if (token != STRING
- || TREE_CODE (yylval.ttype) != STRING_CST)
- {
- error ("invalid #ident");
- goto skipline;
- }
+ token = yylex ();
+ if (token == END_OF_LINE)
+ goto skipline;
+ if (token != STRING
+ || TREE_CODE (yylval.ttype) != STRING_CST)
+ {
+ error ("invalid #ident");
+ goto skipline;
+ }
- if (!flag_no_ident)
- {
+ if (! flag_no_ident)
+ {
#ifdef ASM_OUTPUT_IDENT
- ASM_OUTPUT_IDENT (asm_out_file, TREE_STRING_POINTER (yylval.ttype));
+ ASM_OUTPUT_IDENT (asm_out_file,
+ TREE_STRING_POINTER (yylval.ttype));
#endif
- }
-
- /* Skip the rest of this line. */
- goto skipline;
}
+
+ /* Skip the rest of this line. */
+ goto skipline;
}
- error ("undefined or invalid # directive");
+ error ("undefined or invalid # directive `%s'", name);
goto skipline;
}
+ /* If the # is the only nonwhite char on the line,
+ just ignore it. Check the new newline. */
+ if (token == END_OF_LINE)
+ goto skipline;
+
linenum:
/* Here we have either `#line' or `# <nonletter>'.
In either case, it should be a line number; a digit should follow. */
- /* Can't use skip_white_space here, but must handle all whitespace
- that is not '\n', lest we get a recursion for '\r' '\n' when
- calling yylex. */
- UNGETC (c);
- c = skip_white_space_on_line ();
+ if (token != CONSTANT
+ || TREE_CODE (yylval.ttype) != INTEGER_CST)
+ {
+ error ("invalid #-line");
+ goto skipline;
+ }
- /* If the # is the only nonwhite char on the line,
- just ignore it. Check the new newline. */
- if (c == '\n')
- return c;
+ /* subtract one, because it is the following line that
+ gets the specified number */
- /* Something follows the #; read a token. */
+ l = TREE_INT_CST_LOW (yylval.ttype) - 1;
- UNGETC (c);
- token = yylex ();
+ /* More follows: it must be a string constant (filename).
+ It would be neat to use cpplib to quickly process the string, but
+ (1) we don't have a handy tokenization of the string, and
+ (2) I don't know how well that would work in the presense
+ of filenames that contain wide characters. */
- if (token == CONSTANT
- && TREE_CODE (yylval.ttype) == INTEGER_CST)
+ if (saw_line)
{
- int old_lineno = lineno;
- int used_up = 0;
- /* subtract one, because it is the following line that
- gets the specified number */
-
- int l = TREE_INT_CST_LOW (yylval.ttype) - 1;
-
- /* Is this the last nonwhite stuff on the line? */
- c = skip_white_space_on_line ();
- if (c == '\n')
- {
- /* No more: store the line number and check following line. */
- lineno = l;
- return c;
- }
- UNGETC (c);
-
- /* More follows: it must be a string constant (filename). */
+ /* Don't treat \ as special if we are processing #line 1 "...".
+ If you want it to be treated specially, use # 1 "...". */
+ ignore_escape_flag = 1;
+ }
- /* Read the string constant. */
- token = yylex ();
+ /* Read the string constant. */
+ token = yylex ();
- if (token != STRING || TREE_CODE (yylval.ttype) != STRING_CST)
- {
- error ("invalid #line");
- goto skipline;
- }
+ ignore_escape_flag = 0;
- input_filename
- = (char *) permalloc (TREE_STRING_LENGTH (yylval.ttype) + 1);
- strcpy (input_filename, TREE_STRING_POINTER (yylval.ttype));
+ if (token == END_OF_LINE)
+ {
+ /* No more: store the line number and check following line. */
lineno = l;
+ goto skipline;
+ }
- /* Each change of file name
- reinitializes whether we are now in a system header. */
- in_system_header = 0;
-
- if (main_input_filename == 0)
- main_input_filename = input_filename;
+ if (token != STRING || TREE_CODE (yylval.ttype) != STRING_CST)
+ {
+ error ("invalid #line");
+ goto skipline;
+ }
- /* Is this the last nonwhite stuff on the line? */
- c = skip_white_space_on_line ();
- if (c == '\n')
- {
- /* Update the name in the top element of input_file_stack. */
- if (input_file_stack)
- input_file_stack->name = input_filename;
+ input_filename = TREE_STRING_POINTER (yylval.ttype);
- return c;
- }
- UNGETC (c);
+ if (main_input_filename == 0)
+ main_input_filename = input_filename;
- token = yylex ();
- used_up = 0;
+ old_lineno = lineno;
+ action = act_none;
+ action_number = 0;
+ lineno = l;
- /* `1' after file name means entering new file.
- `2' after file name means just left a file. */
+ /* Each change of file name
+ reinitializes whether we are now in a system header. */
+ in_system_header = 0;
- if (token == CONSTANT
- && TREE_CODE (yylval.ttype) == INTEGER_CST)
- {
- if (TREE_INT_CST_LOW (yylval.ttype) == 1)
- {
- /* Pushing to a new file. */
- struct file_stack *p
- = (struct file_stack *) xmalloc (sizeof (struct file_stack));
- input_file_stack->line = old_lineno;
- p->next = input_file_stack;
- p->name = input_filename;
- p->indent_level = indent_level;
- input_file_stack = p;
- input_file_stack_tick++;
- debug_start_source_file (input_filename);
- used_up = 1;
- }
- else if (TREE_INT_CST_LOW (yylval.ttype) == 2)
- {
- /* Popping out of a file. */
- if (input_file_stack->next)
- {
- struct file_stack *p = input_file_stack;
- if (indent_level != p->indent_level)
- {
- warning_with_file_and_line
- (p->name, old_lineno,
- "This file contains more `%c's than `%c's.",
- indent_level > p->indent_level ? '{' : '}',
- indent_level > p->indent_level ? '}' : '{');
- }
- input_file_stack = p->next;
- free (p);
- input_file_stack_tick++;
- debug_end_source_file (input_file_stack->line);
- }
- else
- error ("#-lines for entering and leaving files don't match");
-
- used_up = 1;
- }
- }
-
- /* Now that we've pushed or popped the input stack,
- update the name in the top element. */
+ if (!read_line_number (&action_number))
+ {
+ /* Update the name in the top element of input_file_stack. */
if (input_file_stack)
input_file_stack->name = input_filename;
+ }
- /* If we have handled a `1' or a `2',
- see if there is another number to read. */
- if (used_up)
- {
- /* Is this the last nonwhite stuff on the line? */
- c = skip_white_space_on_line ();
- if (c == '\n')
- return c;
- UNGETC (c);
-
- token = yylex ();
- used_up = 0;
- }
+ /* `1' after file name means entering new file.
+ `2' after file name means just left a file. */
+ if (action_number == 1)
+ {
+ action = act_push;
+ read_line_number (&action_number);
+ }
+ else if (action_number == 2)
+ {
+ action = act_pop;
+ read_line_number (&action_number);
+ }
+ if (action_number == 3)
+ {
/* `3' after file name means this is a system header file. */
+ in_system_header = 1;
+ read_line_number (&action_number);
+ }
- if (token == CONSTANT
- && TREE_CODE (yylval.ttype) == INTEGER_CST
- && TREE_INT_CST_LOW (yylval.ttype) == 3)
- in_system_header = 1, used_up = 1;
+ /* Do the actions implied by the preceding numbers. */
- if (used_up)
+ if (action == act_push)
+ {
+ /* Pushing to a new file. */
+ struct file_stack *p
+ = (struct file_stack *) xmalloc (sizeof (struct file_stack));
+ input_file_stack->line = old_lineno;
+ p->next = input_file_stack;
+ p->name = input_filename;
+ p->indent_level = indent_level;
+ input_file_stack = p;
+ input_file_stack_tick++;
+ debug_start_source_file (input_filename);
+ }
+ else if (action == act_pop)
+ {
+ /* Popping out of a file. */
+ if (input_file_stack->next)
{
- /* Is this the last nonwhite stuff on the line? */
- c = skip_white_space_on_line ();
- if (c == '\n')
- return c;
- UNGETC (c);
+ struct file_stack *p = input_file_stack;
+ if (indent_level != p->indent_level)
+ {
+ warning_with_file_and_line
+ (p->name, old_lineno,
+ "This file contains more `%c's than `%c's.",
+ indent_level > p->indent_level ? '{' : '}',
+ indent_level > p->indent_level ? '}' : '{');
+ }
+ input_file_stack = p->next;
+ free (p);
+ input_file_stack_tick++;
+ debug_end_source_file (input_file_stack->line);
}
-
- warning ("unrecognized text at end of #line");
+ else
+ error ("#-lines for entering and leaving files don't match");
}
- else
- error ("invalid #-line");
+
+ /* Now that we've pushed or popped the input stack,
+ update the name in the top element. */
+ if (input_file_stack)
+ input_file_stack->name = input_filename;
/* skip the rest of this line. */
skipline:
-#if !USE_CPPLIB
- if (c != '\n' && c != EOF && nextchar >= 0)
- c = nextchar, nextchar = -1;
-#endif
- while (c != '\n' && c != EOF)
+ linemode = 0;
+ end_of_file = 0;
+
+ do
c = GETC();
+ while (c != '\n' && c != EOF);
return c;
}
\f
-#ifdef HANDLE_SYSV_PRAGMA
+#ifdef HANDLE_GENERIC_PRAGMAS
/* Handle a #pragma directive.
TOKEN is the token we read after `#pragma'. Processes the entire input
- line and returns a character for the caller to reread: either \n or EOF. */
+ line and return non-zero iff the pragma has been successfully parsed. */
/* This function has to be in this file, in order to get at
the token types. */
-int
-handle_sysv_pragma (token)
+static int
+handle_generic_pragma (token)
register int token;
{
- register int c;
-
for (;;)
{
switch (token)
case CONSTANT:
handle_pragma_token (token_buffer, yylval.ttype);
break;
+
+ case END_OF_LINE:
+ return handle_pragma_token (NULL_PTR, NULL_TREE);
+
default:
- handle_pragma_token (token_buffer, 0);
+ handle_pragma_token (token_buffer, NULL);
}
-#if !USE_CPPLIB
- if (nextchar >= 0)
- c = nextchar, nextchar = -1;
- else
-#endif
- c = GETC ();
- while (c == ' ' || c == '\t')
- c = GETC ();
- if (c == '\n' || c == EOF)
- {
- handle_pragma_token (0, 0);
- return c;
- }
- UNGETC (c);
token = yylex ();
}
}
-#endif /* HANDLE_SYSV_PRAGMA */
+#endif /* HANDLE_GENERIC_PRAGMAS */
\f
#define ENDFILE -1 /* token that represents end-of-file */
while (1)
{
c = GETC();
- if (!(c >= 'a' && c <= 'f')
- && !(c >= 'A' && c <= 'F')
- && !(c >= '0' && c <= '9'))
+ if (! ISXDIGIT (c))
{
UNGETC (c);
break;
nonnull = 1;
}
if (! nonnull)
- error ("\\x used with no following hex digits");
+ {
+ warning ("\\x used with no following hex digits");
+ return 'x';
+ }
else if (count == 0)
/* Digits are all 0's. Ok. */
;
else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node)
|| (count > 1
- && ((1 << (TYPE_PRECISION (integer_type_node) - (count - 1) * 4))
+ && (((unsigned)1
+ << (TYPE_PRECISION (integer_type_node)
+ - (count - 1) * 4))
<= firstdig)))
pedwarn ("hex escape out of range");
return code;
case 'E':
if (pedantic)
pedwarn ("non-ANSI-standard escape sequence, `\\%c'", c);
- return 033;
+ return TARGET_ESC;
case '?':
return c;
/* `\%' is used to prevent SCCS from getting confused. */
case '%':
if (pedantic)
- pedwarn ("non-ANSI escape sequence `\\%c'", c);
+ pedwarn ("unknown escape sequence `\\%c'", c);
return c;
}
- if (c >= 040 && c < 0177)
+ if (ISGRAPH (c))
pedwarn ("unknown escape sequence `\\%c'", c);
else
- pedwarn ("unknown escape sequence: `\\' followed by char code 0x%x", c);
- return c;
+ pedwarn ("unknown escape sequence: `\\' followed by char code 0x%x", c);
+ return c;
+}
+\f
+void
+yyerror (msgid)
+ const char *msgid;
+{
+ const char *string = _(msgid);
+
+ /* We can't print string and character constants well
+ because the token_buffer contains the result of processing escapes. */
+ if (end_of_file)
+ error ("%s at end of input", string);
+ else if (token_buffer[0] == 0)
+ error ("%s at null character", string);
+ else if (token_buffer[0] == '"')
+ error ("%s before string constant", string);
+ else if (token_buffer[0] == '\'')
+ error ("%s before character constant", string);
+ else if (!ISGRAPH(token_buffer[0]))
+ error ("%s before character 0%o", string, (unsigned char) token_buffer[0]);
+ else
+ error ("%s before `%s'", string, token_buffer);
+}
+
+#if 0
+
+struct try_type
+{
+ tree *node_var;
+ char unsigned_flag;
+ char long_flag;
+ char long_long_flag;
+};
+
+struct try_type type_sequence[] =
+{
+ { &integer_type_node, 0, 0, 0},
+ { &unsigned_type_node, 1, 0, 0},
+ { &long_integer_type_node, 0, 1, 0},
+ { &long_unsigned_type_node, 1, 1, 0},
+ { &long_long_integer_type_node, 0, 1, 1},
+ { &long_long_unsigned_type_node, 1, 1, 1}
+};
+#endif /* 0 */
+\f
+struct pf_args
+{
+ /* Input */
+ int base;
+ char * p;
+ /* I/O */
+ int c;
+ /* Output */
+ int imag;
+ tree type;
+ int conversion_errno;
+ REAL_VALUE_TYPE value;
+};
+
+static void
+parse_float (data)
+ PTR data;
+{
+ struct pf_args * args = (struct pf_args *) data;
+ int fflag = 0, lflag = 0;
+ /* Copy token_buffer now, while it has just the number
+ and not the suffixes; once we add `f' or `i',
+ REAL_VALUE_ATOF may not work any more. */
+ char *copy = (char *) alloca (args->p - token_buffer + 1);
+ bcopy (token_buffer, copy, args->p - token_buffer + 1);
+ args->imag = 0;
+ args->conversion_errno = 0;
+ args->type = double_type_node;
+
+ while (1)
+ {
+ int lose = 0;
+
+ /* Read the suffixes to choose a data type. */
+ switch (args->c)
+ {
+ case 'f': case 'F':
+ if (fflag)
+ error ("more than one `f' in numeric constant");
+ fflag = 1;
+ break;
+
+ case 'l': case 'L':
+ if (lflag)
+ error ("more than one `l' in numeric constant");
+ lflag = 1;
+ break;
+
+ case 'i': case 'I':
+ if (args->imag)
+ error ("more than one `i' or `j' in numeric constant");
+ else if (pedantic)
+ pedwarn ("ANSI C forbids imaginary numeric constants");
+ args->imag = 1;
+ break;
+
+ default:
+ lose = 1;
+ }
+
+ if (lose)
+ break;
+
+ if (args->p >= token_buffer + maxtoken - 3)
+ args->p = extend_token_buffer (args->p);
+ *(args->p++) = args->c;
+ *(args->p) = 0;
+ args->c = GETC();
+ }
+
+ /* The second argument, machine_mode, of REAL_VALUE_ATOF
+ tells the desired precision of the binary result
+ of decimal-to-binary conversion. */
+
+ if (fflag)
+ {
+ if (lflag)
+ error ("both `f' and `l' in floating constant");
+
+ args->type = float_type_node;
+ errno = 0;
+ if (args->base == 16)
+ args->value = REAL_VALUE_HTOF (copy, TYPE_MODE (args->type));
+ else
+ args->value = REAL_VALUE_ATOF (copy, TYPE_MODE (args->type));
+ args->conversion_errno = errno;
+ /* A diagnostic is required here by some ANSI C testsuites.
+ This is not pedwarn, because some people don't want
+ an error for this. */
+ if (REAL_VALUE_ISINF (args->value) && pedantic)
+ warning ("floating point number exceeds range of `float'");
+ }
+ else if (lflag)
+ {
+ args->type = long_double_type_node;
+ errno = 0;
+ if (args->base == 16)
+ args->value = REAL_VALUE_HTOF (copy, TYPE_MODE (args->type));
+ else
+ args->value = REAL_VALUE_ATOF (copy, TYPE_MODE (args->type));
+ args->conversion_errno = errno;
+ if (REAL_VALUE_ISINF (args->value) && pedantic)
+ warning ("floating point number exceeds range of `long double'");
+ }
+ else
+ {
+ errno = 0;
+ if (args->base == 16)
+ args->value = REAL_VALUE_HTOF (copy, TYPE_MODE (args->type));
+ else
+ args->value = REAL_VALUE_ATOF (copy, TYPE_MODE (args->type));
+ args->conversion_errno = errno;
+ if (REAL_VALUE_ISINF (args->value) && pedantic)
+ warning ("floating point number exceeds range of `double'");
+ }
}
-\f
-void
-yyerror (string)
- char *string;
-{
- char buf[200];
+
+/* Get the next character, staying within the current token if possible.
+ If we're lexing a token, we don't want to look beyond the end of the
+ token cpplib has prepared for us; otherwise, we end up reading in the
+ next token, which screws up feed_input. So just return a null
+ character. */
- strcpy (buf, string);
-
- /* We can't print string and character constants well
- because the token_buffer contains the result of processing escapes. */
- if (end_of_file)
- strcat (buf, " at end of input");
- else if (token_buffer[0] == 0)
- strcat (buf, " at null character");
- else if (token_buffer[0] == '"')
- strcat (buf, " before string constant");
- else if (token_buffer[0] == '\'')
- strcat (buf, " before character constant");
- else if (token_buffer[0] < 040 || (unsigned char) token_buffer[0] >= 0177)
- sprintf (buf + strlen (buf), " before character 0%o",
- (unsigned char) token_buffer[0]);
- else
- strcat (buf, " before `%s'");
+static inline int token_getch PARAMS ((void));
- error (buf, token_buffer);
+static inline int
+token_getch ()
+{
+#if USE_CPPLIB
+ if (yy_cur == yy_lim)
+ return '\0';
+#endif
+ return GETC ();
}
-#if 0
+static inline void token_put_back PARAMS ((int));
-struct try_type
+static inline void
+token_put_back (ch)
+ int ch;
{
- tree *node_var;
- char unsigned_flag;
- char long_flag;
- char long_long_flag;
-};
+#if USE_CPPLIB
+ if (ch == '\0')
+ return;
+#endif
+ UNGETC (ch);
+}
+
+/* Read a single token from the input stream, and assign it lexical
+ semantics. */
-struct try_type type_sequence[] =
-{
- { &integer_type_node, 0, 0, 0},
- { &unsigned_type_node, 1, 0, 0},
- { &long_integer_type_node, 0, 1, 0},
- { &long_unsigned_type_node, 1, 1, 0},
- { &long_long_integer_type_node, 0, 1, 1},
- { &long_long_unsigned_type_node, 1, 1, 1}
-};
-#endif /* 0 */
-\f
int
yylex ()
{
int wide_flag = 0;
int objc_flag = 0;
-#if !USE_CPPLIB
- if (nextchar >= 0)
- c = nextchar, nextchar = -1;
- else
-#endif
- c = GETC();
+ c = GETC();
/* Effectively do c = skip_white_space (c)
but do it faster in the usual cases. */
case '\f':
case '\v':
case '\b':
- c = GETC();
+#if USE_CPPLIB
+ if (cpp_token == CPP_HSPACE)
+ c = yy_get_token ();
+ else
+#endif
+ c = GETC();
break;
case '\r':
case EOF:
end_of_file = 1;
token_buffer[0] = 0;
- value = ENDFILE;
+ if (linemode)
+ value = END_OF_LINE;
+ else
+ value = ENDFILE;
break;
case 'L':
+#if USE_CPPLIB
+ if (cpp_token == CPP_NAME)
+ goto letter;
+#endif
/* Capital L may start a wide-string or wide-character constant. */
{
- register int c = GETC();
+ register int c = token_getch();
if (c == '\'')
{
wide_flag = 1;
wide_flag = 1;
goto string_constant;
}
- UNGETC (c);
+ token_put_back (c);
}
goto letter;
else
{
/* '@' may start a constant string object. */
- register int c = GETC ();
+ register int c = token_getch ();
if (c == '"')
{
objc_flag = 1;
goto string_constant;
}
- UNGETC (c);
+ token_put_back (c);
/* Fall through to treat '@' as the start of an identifier. */
}
case '_':
case '$':
letter:
- p = token_buffer;
- while (isalnum (c) || c == '_' || c == '$' || c == '@')
+#if USE_CPPLIB
+ if (cpp_token == CPP_NAME)
{
- /* Make sure this char really belongs in an identifier. */
- if (c == '@' && ! doing_objc_thang)
- break;
- if (c == '$')
+ /* Note that one character has already been read from
+ yy_cur into token_buffer. Also, cpplib complains about
+ $ in identifiers, so we don't have to. */
+
+ int len = yy_lim - yy_cur + 1;
+ if (len >= maxtoken)
+ extend_token_buffer_to (len + 1);
+ memcpy (token_buffer + 1, yy_cur, len);
+ p = token_buffer + len;
+ yy_cur = yy_lim;
+ }
+ else
+#endif
+ {
+ p = token_buffer;
+ while (ISALNUM (c) || c == '_' || c == '$' || c == '@')
{
- if (! dollars_in_ident)
- error ("`$' in identifier");
- else if (pedantic)
- pedwarn ("`$' in identifier");
- }
+ /* Make sure this char really belongs in an identifier. */
+ if (c == '$')
+ {
+ if (! dollars_in_ident)
+ error ("`$' in identifier");
+ else if (pedantic)
+ pedwarn ("`$' in identifier");
+ }
- if (p >= token_buffer + maxtoken)
- p = extend_token_buffer (p);
+ if (p >= token_buffer + maxtoken)
+ p = extend_token_buffer (p);
- *p++ = c;
- c = GETC();
- }
+ *p++ = c;
+ c = token_getch();
+ }
- *p = 0;
-#if USE_CPPLIB
- UNGETC (c);
-#else
- nextchar = c;
-#endif
+ *p = 0;
+ token_put_back (c);
+ }
value = IDENTIFIER;
yylval.itype = 0;
{
register struct resword *ptr;
- if (ptr = is_reserved_word (token_buffer, p - token_buffer))
+ if ((ptr = is_reserved_word (token_buffer, p - token_buffer)))
{
if (ptr->rid)
yylval.ttype = ridpointers[(int) ptr->rid];
&& TREE_CODE (DECL_INITIAL (lastiddecl)) == STRING_CST)
{
tree stringval = DECL_INITIAL (lastiddecl);
-
+
/* Copy the string value so that we won't clobber anything
if we put something in the TREE_CHAIN of this one. */
yylval.ttype = build_string (TREE_STRING_LENGTH (stringval),
break;
+ case '.':
+#if USE_CPPLIB
+ if (yy_cur < yy_lim)
+#endif
+ {
+ /* It's hard to preserve tokenization on '.' because
+ it could be a symbol by itself, or it could be the
+ start of a floating point number and cpp won't tell us. */
+ register int c1 = token_getch ();
+ token_buffer[1] = c1;
+ if (c1 == '.')
+ {
+ c1 = token_getch ();
+ if (c1 == '.')
+ {
+ token_buffer[2] = c1;
+ token_buffer[3] = 0;
+ value = ELLIPSIS;
+ goto done;
+ }
+ error ("parse error at `..'");
+ }
+ if (ISDIGIT (c1))
+ {
+ token_put_back (c1);
+ goto number;
+ }
+ token_put_back (c1);
+ }
+ value = '.';
+ token_buffer[1] = 0;
+ break;
+
case '0': case '1':
+ /* Optimize for most frequent case. */
{
- int next_c;
- /* Check first for common special case: single-digit 0 or 1. */
+ register int cond;
- next_c = GETC ();
- UNGETC (next_c); /* Always undo this lookahead. */
- if (!isalnum (next_c) && next_c != '.')
+#if USE_CPPLIB
+ cond = (yy_cur == yy_lim);
+#else
+ register int c1 = token_getch ();
+ token_put_back (c1);
+ cond = (! ISALNUM (c1) && c1 != '.');
+#endif
+ if (cond)
{
- token_buffer[0] = (char)c, token_buffer[1] = '\0';
yylval.ttype = (c == '0') ? integer_zero_node : integer_one_node;
value = CONSTANT;
break;
}
case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- case '.':
+ number:
{
int base = 10;
int count = 0;
int largest_digit = 0;
int numdigits = 0;
- /* for multi-precision arithmetic,
- we actually store only HOST_BITS_PER_CHAR bits in each part.
- The number of parts is chosen so as to be sufficient to hold
- the enough bits to fit into the two HOST_WIDE_INTs that contain
- the integer value (this is always at least as many bits as are
- in a target `long long' value, but may be wider). */
-#define TOTAL_PARTS ((HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR) * 2 + 2)
- int parts[TOTAL_PARTS];
int overflow = 0;
- enum anon1 { NOT_FLOAT, AFTER_POINT, TOO_MANY_POINTS} floatflag
- = NOT_FLOAT;
+ /* We actually store only HOST_BITS_PER_CHAR bits in each part.
+ The code below which fills the parts array assumes that a host
+ int is at least twice as wide as a host char, and that
+ HOST_BITS_PER_WIDE_INT is an even multiple of HOST_BITS_PER_CHAR.
+ Two HOST_WIDE_INTs is the largest int literal we can store.
+ In order to detect overflow below, the number of parts (TOTAL_PARTS)
+ must be exactly the number of parts needed to hold the bits
+ of two HOST_WIDE_INTs. */
+#define TOTAL_PARTS ((HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR) * 2)
+ unsigned int parts[TOTAL_PARTS];
+
+ enum anon1 { NOT_FLOAT, AFTER_POINT, TOO_MANY_POINTS, AFTER_EXPON}
+ floatflag = NOT_FLOAT;
for (count = 0; count < TOTAL_PARTS; count++)
parts[count] = 0;
if (c == '0')
{
- *p++ = (c = GETC());
+ *p++ = (c = token_getch());
if ((c == 'x') || (c == 'X'))
{
base = 16;
- *p++ = (c = GETC());
+ *p++ = (c = token_getch());
}
/* Leading 0 forces octal unless the 0 is the only digit. */
else if (c >= '0' && c <= '9')
/* Read all the digits-and-decimal-points. */
while (c == '.'
- || (isalnum (c) && c != 'l' && c != 'L'
+ || (ISALNUM (c) && c != 'l' && c != 'L'
&& c != 'u' && c != 'U'
&& c != 'i' && c != 'I' && c != 'j' && c != 'J'
- && (floatflag == NOT_FLOAT || ((c != 'f') && (c != 'F')))))
+ && (floatflag == NOT_FLOAT
+ || ((base != 16) && (c != 'f') && (c != 'F'))
+ || base == 16)))
{
if (c == '.')
{
- if (base == 16)
- error ("floating constant may not be in radix 16");
+ if (base == 16 && pedantic)
+ pedwarn ("floating constant may not be in radix 16");
if (floatflag == TOO_MANY_POINTS)
/* We have already emitted an error. Don't need another. */
;
- else if (floatflag == AFTER_POINT)
+ else if (floatflag == AFTER_POINT || floatflag == AFTER_EXPON)
{
error ("malformed floating constant");
floatflag = TOO_MANY_POINTS;
else
floatflag = AFTER_POINT;
- base = 10;
- *p++ = c = GETC();
+ if (base == 8)
+ base = 10;
+ *p++ = c = token_getch();
/* Accept '.' as the start of a floating-point number
- only when it is followed by a digit.
- Otherwise, unread the following non-digit
- and use the '.' as a structural token. */
- if (p == token_buffer + 2 && !isdigit (c))
- {
- if (c == '.')
- {
- c = GETC();
- if (c == '.')
- {
- *p++ = c;
- *p = 0;
- return ELLIPSIS;
- }
- error ("parse error at `..'");
- }
- UNGETC (c);
- token_buffer[1] = 0;
- value = '.';
- goto done;
- }
+ only when it is followed by a digit. */
+ if (p == token_buffer + 2 && !ISDIGIT (c))
+ abort ();
}
else
{
/* It is not a decimal point.
It should be a digit (perhaps a hex digit). */
- if (isdigit (c))
+ if (ISDIGIT (c))
{
c = c - '0';
}
if (c == 'e' || c == 'E')
{
base = 10;
- floatflag = AFTER_POINT;
+ floatflag = AFTER_EXPON;
break; /* start of exponent */
}
error ("nondigits in number and not hexadecimal");
c = 0;
}
+ else if (base == 16 && (c == 'p' || c == 'P'))
+ {
+ floatflag = AFTER_EXPON;
+ break; /* start of exponent */
+ }
else if (c >= 'a')
{
c = c - 'a' + 10;
parts[0] += c;
}
- /* If the extra highest-order part ever gets anything in it,
- the number is certainly too big. */
- if (parts[TOTAL_PARTS - 1] != 0)
- overflow = 1;
+ /* If the highest-order part overflows (gets larger than
+ a host char will hold) then the whole number has
+ overflowed. Record this and truncate the highest-order
+ part. */
+ if (parts[TOTAL_PARTS - 1] >> HOST_BITS_PER_CHAR)
+ {
+ overflow = 1;
+ parts[TOTAL_PARTS - 1] &= (1 << HOST_BITS_PER_CHAR) - 1;
+ }
if (p >= token_buffer + maxtoken - 3)
p = extend_token_buffer (p);
- *p++ = (c = GETC());
+ *p++ = (c = token_getch());
}
}
+ /* This can happen on input like `int i = 0x;' */
if (numdigits == 0)
error ("numeric constant with no digits");
if (largest_digit >= base)
error ("numeric constant contains digits beyond the radix");
- /* Remove terminating char from the token buffer and delimit the string */
+ /* Remove terminating char from the token buffer and delimit the
+ string. */
*--p = 0;
if (floatflag != NOT_FLOAT)
{
- tree type = double_type_node;
- int exceeds_double = 0;
- int imag = 0;
+ tree type;
+ int imag, conversion_errno;
REAL_VALUE_TYPE value;
- jmp_buf handler;
+ struct pf_args args;
/* Read explicit exponent if any, and put it in tokenbuf. */
- if ((c == 'e') || (c == 'E'))
+ if ((base == 10 && ((c == 'e') || (c == 'E')))
+ || (base == 16 && (c == 'p' || c == 'P')))
{
if (p >= token_buffer + maxtoken - 3)
p = extend_token_buffer (p);
*p++ = c;
- c = GETC();
+ c = token_getch();
if ((c == '+') || (c == '-'))
{
*p++ = c;
- c = GETC();
+ c = token_getch();
}
- if (! isdigit (c))
+ /* Exponent is decimal, even if string is a hex float. */
+ if (! ISDIGIT (c))
error ("floating constant exponent has no digits");
- while (isdigit (c))
+ while (ISDIGIT (c))
{
if (p >= token_buffer + maxtoken - 3)
p = extend_token_buffer (p);
*p++ = c;
- c = GETC();
+ c = token_getch ();
}
}
+ if (base == 16 && floatflag != AFTER_EXPON)
+ error ("hexadecimal floating constant has no exponent");
*p = 0;
- errno = 0;
+
+ /* Setup input for parse_float() */
+ args.base = base;
+ args.p = p;
+ args.c = c;
/* Convert string to a double, checking for overflow. */
- if (setjmp (handler))
+ if (do_float_handler (parse_float, (PTR) &args))
{
- error ("floating constant out of range");
- value = dconst0;
+ /* Receive output from parse_float() */
+ value = args.value;
}
else
{
- int fflag = 0, lflag = 0;
- /* Copy token_buffer now, while it has just the number
- and not the suffixes; once we add `f' or `i',
- REAL_VALUE_ATOF may not work any more. */
- char *copy = (char *) alloca (p - token_buffer + 1);
- bcopy (token_buffer, copy, p - token_buffer + 1);
-
- set_float_handler (handler);
-
- while (1)
- {
- int lose = 0;
-
- /* Read the suffixes to choose a data type. */
- switch (c)
- {
- case 'f': case 'F':
- if (fflag)
- error ("more than one `f' in numeric constant");
- fflag = 1;
- break;
-
- case 'l': case 'L':
- if (lflag)
- error ("more than one `l' in numeric constant");
- lflag = 1;
- break;
-
- case 'i': case 'I':
- if (imag)
- error ("more than one `i' or `j' in numeric constant");
- else if (pedantic)
- pedwarn ("ANSI C forbids imaginary numeric constants");
- imag = 1;
- break;
-
- default:
- lose = 1;
- }
-
- if (lose)
- break;
-
- if (p >= token_buffer + maxtoken - 3)
- p = extend_token_buffer (p);
- *p++ = c;
- *p = 0;
- c = GETC();
- }
-
- /* The second argument, machine_mode, of REAL_VALUE_ATOF
- tells the desired precision of the binary result
- of decimal-to-binary conversion. */
-
- if (fflag)
- {
- if (lflag)
- error ("both `f' and `l' in floating constant");
-
- type = float_type_node;
- value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
- /* A diagnostic is required here by some ANSI C testsuites.
- This is not pedwarn, become some people don't want
- an error for this. */
- if (REAL_VALUE_ISINF (value) && pedantic)
- warning ("floating point number exceeds range of `float'");
- }
- else if (lflag)
- {
- type = long_double_type_node;
- value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
- if (REAL_VALUE_ISINF (value) && pedantic)
- warning ("floating point number exceeds range of `long double'");
- }
- else
- {
- value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
- if (REAL_VALUE_ISINF (value) && pedantic)
- warning ("floating point number exceeds range of `double'");
- }
+ /* We got an exception from parse_float() */
+ error ("floating constant out of range");
+ value = dconst0;
+ }
- set_float_handler (NULL_PTR);
- }
+ /* Receive output from parse_float() */
+ c = args.c;
+ imag = args.imag;
+ type = args.type;
+ conversion_errno = args.conversion_errno;
+
#ifdef ERANGE
- if (errno == ERANGE && !flag_traditional && pedantic)
- {
- /* ERANGE is also reported for underflow,
- so test the value to distinguish overflow from that. */
- if (REAL_VALUES_LESS (dconst1, value)
- || REAL_VALUES_LESS (value, dconstm1))
- {
- warning ("floating point number exceeds range of `double'");
- exceeds_double = 1;
- }
- }
+ /* ERANGE is also reported for underflow,
+ so test the value to distinguish overflow from that. */
+ if (conversion_errno == ERANGE && !flag_traditional && pedantic
+ && (REAL_VALUES_LESS (dconst1, value)
+ || REAL_VALUES_LESS (value, dconstm1)))
+ warning ("floating point number exceeds range of `double'");
#endif
/* If the result is not a number, assume it must have been
int spec_long = 0;
int spec_long_long = 0;
int spec_imag = 0;
- int bytes, warn, i;
+ int warn = 0, i;
+ traditional_type = ansi_type = type = NULL_TREE;
while (1)
{
if (c == 'u' || c == 'U')
{
if (spec_long_long)
error ("three `l's in integer constant");
- else if (pedantic)
+ else if (pedantic && ! in_system_header && warn_long_long)
pedwarn ("ANSI C forbids long long integer constants");
spec_long_long = 1;
}
if (p >= token_buffer + maxtoken - 3)
p = extend_token_buffer (p);
*p++ = c;
- c = GETC();
+ c = token_getch();
}
- /* If the constant won't fit in an unsigned long long,
- then warn that the constant is out of range. */
-
- /* ??? This assumes that long long and long integer types are
- a multiple of 8 bits. This better than the original code
- though which assumed that long was exactly 32 bits and long
- long was exactly 64 bits. */
-
- bytes = TYPE_PRECISION (long_long_integer_type_node) / 8;
-
- warn = overflow;
- for (i = bytes; i < TOTAL_PARTS; i++)
- if (parts[i])
+ /* If the literal overflowed, pedwarn about it now. */
+ if (overflow)
+ {
warn = 1;
- if (warn)
- pedwarn ("integer constant out of range");
+ pedwarn ("integer constant is too large for this configuration of the compiler - truncated to %d bits", HOST_BITS_PER_WIDE_INT * 2);
+ }
/* This is simplified by the fact that our constant
is always positive. */
<< (i * HOST_BITS_PER_CHAR));
low |= (HOST_WIDE_INT) parts[i] << (i * HOST_BITS_PER_CHAR);
}
-
+
yylval.ttype = build_int_2 (low, high);
TREE_TYPE (yylval.ttype) = long_long_unsigned_type_node;
else if (! spec_long_long)
traditional_type = (spec_unsigned ? long_unsigned_type_node
: long_integer_type_node);
- else
+ else if (int_fits_type_p (yylval.ttype,
+ spec_unsigned
+ ? long_long_unsigned_type_node
+ : long_long_integer_type_node))
traditional_type = (spec_unsigned
? long_long_unsigned_type_node
: long_long_integer_type_node);
+ else
+ traditional_type = (spec_unsigned
+ ? widest_unsigned_literal_type_node
+ : widest_integer_literal_type_node);
}
if (warn_traditional || ! flag_traditional)
{
&& int_fits_type_p (yylval.ttype,
long_long_integer_type_node))
ansi_type = long_long_integer_type_node;
- else
+ else if (int_fits_type_p (yylval.ttype,
+ long_long_unsigned_type_node))
ansi_type = long_long_unsigned_type_node;
+ else if (! spec_unsigned
+ && int_fits_type_p (yylval.ttype,
+ widest_integer_literal_type_node))
+ ansi_type = widest_integer_literal_type_node;
+ else
+ ansi_type = widest_unsigned_literal_type_node;
}
type = flag_traditional ? traditional_type : ansi_type;
- if (warn_traditional && traditional_type != ansi_type)
+ /* We assume that constants specified in a non-decimal
+ base are bit patterns, and that the programmer really
+ meant what they wrote. */
+ if (warn_traditional && base == 10
+ && traditional_type != ansi_type)
{
if (TYPE_PRECISION (traditional_type)
!= TYPE_PRECISION (ansi_type))
if (pedantic && !flag_traditional && !spec_long_long && !warn
&& (TYPE_PRECISION (long_integer_type_node)
< TYPE_PRECISION (type)))
- pedwarn ("integer constant out of range");
+ {
+ warn = 1;
+ pedwarn ("integer constant larger than the maximum value of an unsigned long int");
+ }
if (base == 10 && ! spec_unsigned && TREE_UNSIGNED (type))
warning ("decimal constant is so large that it is unsigned");
}
else
TREE_TYPE (yylval.ttype) = type;
+
+
+ /* If it's still an integer (not a complex), and it doesn't
+ fit in the type we choose for it, then pedwarn. */
+
+ if (! warn
+ && TREE_CODE (TREE_TYPE (yylval.ttype)) == INTEGER_TYPE
+ && ! int_fits_type_p (yylval.ttype, TREE_TYPE (yylval.ttype)))
+ pedwarn ("integer constant is larger than the maximum value for its type");
}
- UNGETC (c);
+ token_put_back (c);
*p = 0;
- if (isalnum (c) || c == '.' || c == '_' || c == '$'
+ if (ISALNUM (c) || c == '.' || c == '_' || c == '$'
|| (!flag_traditional && (c == '-' || c == '+')
&& (p[-1] == 'e' || p[-1] == 'E')))
error ("missing white space after number `%s'", token_buffer);
{
register int result = 0;
register int num_chars = 0;
+ int chars_seen = 0;
unsigned width = TYPE_PRECISION (char_type_node);
int max_chars;
-
- if (wide_flag)
- {
- width = WCHAR_TYPE_SIZE;
#ifdef MULTIBYTE_CHARS
- max_chars = MB_CUR_MAX;
-#else
- max_chars = 1;
+ int longest_char = local_mb_cur_max ();
+ (void) local_mbtowc (NULL_PTR, NULL_PTR, 0);
#endif
- }
- else
- max_chars = TYPE_PRECISION (integer_type_node) / width;
+
+ max_chars = TYPE_PRECISION (integer_type_node) / width;
+ if (wide_flag)
+ width = WCHAR_TYPE_SIZE;
while (1)
{
tryagain:
-
- c = GETC();
+ c = token_getch();
if (c == '\'' || c == EOF)
break;
+ ++chars_seen;
if (c == '\\')
{
int ignore = 0;
if (ignore)
goto tryagain;
if (width < HOST_BITS_PER_INT
- && (unsigned) c >= (1 << width))
+ && (unsigned) c >= ((unsigned)1 << width))
pedwarn ("escape sequence out of range for character");
#ifdef MAP_CHARACTER
- if (isprint (c))
+ if (ISPRINT (c))
c = MAP_CHARACTER (c);
#endif
}
pedwarn ("ANSI C forbids newline in character constant");
lineno++;
}
-#ifdef MAP_CHARACTER
else
- c = MAP_CHARACTER (c);
+ {
+#ifdef MULTIBYTE_CHARS
+ wchar_t wc;
+ int i;
+ int char_len = -1;
+ for (i = 1; i <= longest_char; ++i)
+ {
+ if (i > maxtoken - 4)
+ extend_token_buffer (token_buffer);
+
+ token_buffer[i] = c;
+ char_len = local_mbtowc (& wc,
+ token_buffer + 1,
+ i);
+ if (char_len != -1)
+ break;
+ c = token_getch ();
+ }
+ if (char_len > 1)
+ {
+ /* mbtowc sometimes needs an extra char before accepting */
+ if (char_len < i)
+ token_put_back (c);
+ if (! wide_flag)
+ {
+ /* Merge character into result; ignore excess chars. */
+ for (i = 1; i <= char_len; ++i)
+ {
+ if (i > max_chars)
+ break;
+ if (width < HOST_BITS_PER_INT)
+ result = (result << width)
+ | (token_buffer[i]
+ & ((1 << width) - 1));
+ else
+ result = token_buffer[i];
+ }
+ num_chars += char_len;
+ goto tryagain;
+ }
+ c = wc;
+ }
+ else
+ {
+ if (char_len == -1)
+ {
+ warning ("Ignoring invalid multibyte character");
+ /* Replace all but the first byte. */
+ for (--i; i > 1; --i)
+ token_put_back (token_buffer[i]);
+ wc = token_buffer[1];
+ }
+#ifdef MAP_CHARACTER
+ c = MAP_CHARACTER (wc);
+#else
+ c = wc;
#endif
+ }
+#else /* ! MULTIBYTE_CHARS */
+#ifdef MAP_CHARACTER
+ c = MAP_CHARACTER (c);
+#endif
+#endif /* ! MULTIBYTE_CHARS */
+ }
- num_chars++;
- if (num_chars > maxtoken - 4)
- extend_token_buffer (token_buffer);
-
- token_buffer[num_chars] = c;
+ if (wide_flag)
+ {
+ if (chars_seen == 1) /* only keep the first one */
+ result = c;
+ goto tryagain;
+ }
/* Merge character into result; ignore excess chars. */
+ num_chars += (width / TYPE_PRECISION (char_type_node));
if (num_chars < max_chars + 1)
{
if (width < HOST_BITS_PER_INT)
}
}
- token_buffer[num_chars + 1] = '\'';
- token_buffer[num_chars + 2] = 0;
-
if (c != '\'')
- error ("malformatted character constant");
- else if (num_chars == 0)
+ error ("malformed character constant");
+ else if (chars_seen == 0)
error ("empty character constant");
else if (num_chars > max_chars)
{
num_chars = max_chars;
error ("character constant too long");
}
- else if (num_chars != 1 && ! flag_traditional)
+ else if (chars_seen != 1 && ! flag_traditional && warn_multichar)
warning ("multi-character character constant");
/* If char type is signed, sign-extend the constant. */
else if (TREE_UNSIGNED (char_type_node)
|| ((result >> (num_bits - 1)) & 1) == 0)
yylval.ttype
- = build_int_2 (result & ((unsigned HOST_WIDE_INT) ~0
+ = build_int_2 (result & (~(unsigned HOST_WIDE_INT) 0
>> (HOST_BITS_PER_WIDE_INT - num_bits)),
0);
else
yylval.ttype
- = build_int_2 (result | ~((unsigned HOST_WIDE_INT) ~0
+ = build_int_2 (result | ~(~(unsigned HOST_WIDE_INT) 0
>> (HOST_BITS_PER_WIDE_INT - num_bits)),
-1);
TREE_TYPE (yylval.ttype) = integer_type_node;
}
else
{
-#ifdef MULTIBYTE_CHARS
- /* Set the initial shift state and convert the next sequence. */
- result = 0;
- /* In all locales L'\0' is zero and mbtowc will return zero,
- so don't use it. */
- if (num_chars > 1
- || (num_chars == 1 && token_buffer[1] != '\0'))
- {
- wchar_t wc;
- (void) mbtowc (NULL_PTR, NULL_PTR, 0);
- if (mbtowc (& wc, token_buffer + 1, num_chars) == num_chars)
- result = wc;
- else
- warning ("Ignoring invalid multibyte character");
- }
-#endif
yylval.ttype = build_int_2 (result, 0);
TREE_TYPE (yylval.ttype) = wchar_type_node;
}
case '"':
string_constant:
{
- c = GETC();
+ unsigned width = wide_flag ? WCHAR_TYPE_SIZE
+ : TYPE_PRECISION (char_type_node);
+#ifdef MULTIBYTE_CHARS
+ int longest_char = local_mb_cur_max ();
+ (void) local_mbtowc (NULL_PTR, NULL_PTR, 0);
+#endif
+ c = token_getch ();
p = token_buffer + 1;
- while (c != '"' && c >= 0)
+ while (c != '"' && c != EOF)
{
- if (c == '\\')
+ /* ignore_escape_flag is set for reading the filename in #line. */
+ if (!ignore_escape_flag && c == '\\')
{
int ignore = 0;
c = readescape (&ignore);
if (ignore)
goto skipnewline;
- if (!wide_flag
- && TYPE_PRECISION (char_type_node) < HOST_BITS_PER_INT
- && c >= (1 << TYPE_PRECISION (char_type_node)))
+ if (width < HOST_BITS_PER_INT
+ && (unsigned) c >= ((unsigned)1 << width))
pedwarn ("escape sequence out of range for character");
}
else if (c == '\n')
pedwarn ("ANSI C forbids newline in string constant");
lineno++;
}
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ wchar_t wc;
+ int i;
+ int char_len = -1;
+ for (i = 0; i < longest_char; ++i)
+ {
+ if (p + i >= token_buffer + maxtoken)
+ p = extend_token_buffer (p);
+ p[i] = c;
+
+ char_len = local_mbtowc (& wc, p, i + 1);
+ if (char_len != -1)
+ break;
+ c = token_getch ();
+ }
+ if (char_len == -1)
+ {
+ warning ("Ignoring invalid multibyte character");
+ /* Replace all except the first byte. */
+ token_put_back (c);
+ for (--i; i > 0; --i)
+ token_put_back (p[i]);
+ char_len = 1;
+ }
+ /* mbtowc sometimes needs an extra char before accepting */
+ if (char_len <= i)
+ token_put_back (c);
+ if (! wide_flag)
+ {
+ p += (i + 1);
+ c = token_getch ();
+ continue;
+ }
+ c = wc;
+#endif /* MULTIBYTE_CHARS */
+ }
- if (p == token_buffer + maxtoken)
- p = extend_token_buffer (p);
- *p++ = c;
+ /* Add this single character into the buffer either as a wchar_t
+ or as a single byte. */
+ if (wide_flag)
+ {
+ unsigned width = TYPE_PRECISION (char_type_node);
+ unsigned bytemask = (1 << width) - 1;
+ int byte;
+
+ if (p + WCHAR_BYTES > token_buffer + maxtoken)
+ p = extend_token_buffer (p);
+
+ for (byte = 0; byte < WCHAR_BYTES; ++byte)
+ {
+ int value;
+ if (byte >= (int) sizeof (c))
+ value = 0;
+ else
+ value = (c >> (byte * width)) & bytemask;
+ if (BYTES_BIG_ENDIAN)
+ p[WCHAR_BYTES - byte - 1] = value;
+ else
+ p[byte] = value;
+ }
+ p += WCHAR_BYTES;
+ }
+ else
+ {
+ if (p >= token_buffer + maxtoken)
+ p = extend_token_buffer (p);
+ *p++ = c;
+ }
skipnewline:
- c = GETC();
+ c = token_getch ();
+ }
+
+ /* Terminate the string value, either with a single byte zero
+ or with a wide zero. */
+ if (wide_flag)
+ {
+ if (p + WCHAR_BYTES > token_buffer + maxtoken)
+ p = extend_token_buffer (p);
+ bzero (p, WCHAR_BYTES);
+ p += WCHAR_BYTES;
+ }
+ else
+ {
+ if (p >= token_buffer + maxtoken)
+ p = extend_token_buffer (p);
+ *p++ = 0;
}
- *p = 0;
- if (c < 0)
+ if (c == EOF)
error ("Unterminated string constant");
/* We have read the entire constant.
if (wide_flag)
{
- /* If this is a L"..." wide-string, convert the multibyte string
- to a wide character string. */
- char *widep = (char *) alloca ((p - token_buffer) * WCHAR_BYTES);
- int len;
-
-#ifdef MULTIBYTE_CHARS
- len = mbstowcs ((wchar_t *) widep, token_buffer + 1, p - token_buffer);
- if (len < 0 || len >= (p - token_buffer))
- {
- warning ("Ignoring invalid multibyte string");
- len = 0;
- }
- bzero (widep + (len * WCHAR_BYTES), WCHAR_BYTES);
-#else
- {
- char *wp, *cp;
-
- wp = widep + (BYTES_BIG_ENDIAN ? WCHAR_BYTES - 1 : 0);
- bzero (widep, (p - token_buffer) * WCHAR_BYTES);
- for (cp = token_buffer + 1; cp < p; cp++)
- *wp = *cp, wp += WCHAR_BYTES;
- len = p - token_buffer - 1;
- }
-#endif
- yylval.ttype = build_string ((len + 1) * WCHAR_BYTES, widep);
+ yylval.ttype = build_string (p - (token_buffer + 1),
+ token_buffer + 1);
TREE_TYPE (yylval.ttype) = wchar_array_type_node;
value = STRING;
}
else if (objc_flag)
{
- extern tree build_objc_string();
/* Return an Objective-C @"..." constant string object. */
- yylval.ttype = build_objc_string (p - token_buffer,
+ yylval.ttype = build_objc_string (p - (token_buffer + 1),
token_buffer + 1);
TREE_TYPE (yylval.ttype) = char_array_type_node;
value = OBJC_STRING;
}
else
{
- yylval.ttype = build_string (p - token_buffer, token_buffer + 1);
+ yylval.ttype = build_string (p - (token_buffer + 1),
+ token_buffer + 1);
TREE_TYPE (yylval.ttype) = char_array_type_node;
value = STRING;
}
- *p++ = '"';
- *p = 0;
-
break;
}
yylval.code = GT_EXPR; break;
}
- token_buffer[1] = c1 = GETC();
+ token_buffer[1] = c1 = token_getch();
token_buffer[2] = 0;
if (c1 == '=')
if (c1 == '>')
{ value = POINTSAT; goto done; }
break;
+
+ /* digraphs */
case ':':
if (c1 == '>')
{ value = ']'; goto done; }
{ value = '}'; indent_level--; goto done; }
break;
}
- UNGETC (c1);
+
+ token_put_back (c1);
token_buffer[1] = 0;
if ((c == '<') || (c == '>'))
value = ARITHCOMPARE;
else value = c;
- goto done;
+ break;
}
case 0: