/* Bison Grammar Scanner -*- C -*-
- Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
- Free Software Foundation, Inc.
+ Copyright (C) 2002-2011 Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
-%option debug nodefault nounput noyywrap never-interactive
+%option debug nodefault noinput nounput noyywrap never-interactive
%option prefix="gram_" outfile="lex.yy.c"
%{
#include <src/reader.h>
#include <src/uniqstr.h>
+#include <ctype.h>
#include <mbswidth.h>
#include <quote.h>
static size_t no_cr_read (FILE *, char *, size_t);
#define YY_INPUT(buf, result, size) ((result) = no_cr_read (yyin, buf, size))
-#define RETURN_PERCENT_FLAG(Value) \
+#define RETURN_PERCENT_PARAM(Value) \
+ RETURN_VALUE(PERCENT_PARAM, param, param_ ## Value)
+
+#define RETURN_PERCENT_FLAG(Value) \
+ RETURN_VALUE(PERCENT_FLAG, uniqstr, uniqstr_new (Value))
+
+#define RETURN_VALUE(Token, Field, Value) \
do { \
- val->uniqstr = uniqstr_new (Value); \
- return PERCENT_FLAG; \
+ val->Field = Value; \
+ return Token; \
} while (0)
#define ROLLBACK_CURRENT_TOKEN \
/* A string representing the most recently saved token. */
static char *last_string;
-/* Bracketed identifier */
+/* Bracketed identifier. */
static uniqstr bracketed_id_str = 0;
static location bracketed_id_loc;
static boundary bracketed_id_start;
/* A complex tag, with nested angles brackets. */
%x SC_TAG
- /* Three types of user code:
+ /* Four types of user code:
- prologue (code between `%{' `%}' in the first section, before %%);
- actions, printers, union, etc, (between braced in the middle section);
- - epilogue (everything after the second %%). */
-%x SC_PROLOGUE SC_BRACED_CODE SC_EPILOGUE
+ - epilogue (everything after the second %%).
+ - predicate (code between `%?{' and `{' in middle section); */
+%x SC_PROLOGUE SC_BRACED_CODE SC_EPILOGUE SC_PREDICATE
/* C and C++ comments in code. */
%x SC_COMMENT SC_LINE_COMMENT
/* Strings and characters in code. */
%x SC_STRING SC_CHARACTER
- /* Bracketed identifiers support */
+ /* Bracketed identifiers support. */
%x SC_BRACKETED_ID SC_RETURN_BRACKETED_ID
-letter [-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]
-id {letter}({letter}|[0-9])*
+letter [.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]
+id {letter}({letter}|[-0-9])*
directive %{id}
int [0-9]+
"%glr-parser" return PERCENT_GLR_PARSER;
"%language" return PERCENT_LANGUAGE;
"%left" return PERCENT_LEFT;
- "%lex-param" return PERCENT_LEX_PARAM;
+ "%lex-param" RETURN_PERCENT_PARAM(lex);
"%locations" RETURN_PERCENT_FLAG("locations");
"%merge" return PERCENT_MERGE;
"%name"[-_]"prefix" return PERCENT_NAME_PREFIX;
"%nondeterministic-parser" return PERCENT_NONDETERMINISTIC_PARSER;
"%nterm" return PERCENT_NTERM;
"%output" return PERCENT_OUTPUT;
- "%parse-param" return PERCENT_PARSE_PARAM;
+ "%param" RETURN_PERCENT_PARAM(both);
+ "%parse-param" RETURN_PERCENT_PARAM(parse);
"%prec" return PERCENT_PREC;
"%precedence" return PERCENT_PRECEDENCE;
"%printer" return PERCENT_PRINTER;
complain_at (*loc, _("invalid identifier: %s"), quote (yytext));
}
- /* Characters. We don't check there is only one. */
- "'" STRING_GROW; token_start = loc->start; BEGIN SC_ESCAPED_CHARACTER;
+ /* Characters. */
+ "'" token_start = loc->start; BEGIN SC_ESCAPED_CHARACTER;
/* Strings. */
"\"" token_start = loc->start; BEGIN SC_ESCAPED_STRING;
BEGIN SC_BRACED_CODE;
}
+ /* Semantic predicate. */
+ "%?"[ \f\n\t\v]*"{" {
+ nesting = 0;
+ code_start = loc->start;
+ BEGIN SC_PREDICATE;
+ }
+
/* A type. */
"<*>" return TAG_ANY;
"<>" return TAG_NONE;
<SC_AFTER_IDENTIFIER>
{
"[" {
- if (!bracketed_id_str)
- {
- bracketed_id_start = loc->start;
- bracketed_id_context_state = YY_START;
- BEGIN SC_BRACKETED_ID;
- }
- else
+ if (bracketed_id_str)
{
ROLLBACK_CURRENT_TOKEN;
BEGIN SC_RETURN_BRACKETED_ID;
*loc = id_loc;
return ID;
}
+ else
+ {
+ bracketed_id_start = loc->start;
+ bracketed_id_context_state = YY_START;
+ BEGIN SC_BRACKETED_ID;
+ }
}
":" {
BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
<SC_BRACKETED_ID>
{
{id} {
- if (!bracketed_id_str)
+ if (bracketed_id_str)
{
- bracketed_id_str = uniqstr_new (yytext);
- bracketed_id_loc = *loc;
+ complain_at (*loc, _("unexpected identifier in bracketed name: %s"),
+ quote (yytext));
}
else
{
- complain_at (*loc, _("redundant identifier in bracketed name: %s"),
- quote (yytext));
+ bracketed_id_str = uniqstr_new (yytext);
+ bracketed_id_loc = *loc;
}
}
"]" {
}
}
else
- complain_at (*loc, _("a non empty identifier expected"));
+ complain_at (*loc, _("an identifier expected"));
}
. {
complain_at (*loc, _("invalid character in bracketed name: %s"),
<SC_ESCAPED_CHARACTER>
{
"'"|"\n" {
- if (yytext[0] == '\n')
- unexpected_newline (token_start, "'");
- STRING_GROW;
STRING_FINISH;
loc->start = token_start;
- val->character = last_string[1];
+ val->character = last_string[0];
+ {
+ /* FIXME: Eventually, make these errors. */
+ if (last_string[0] == '\0')
+ {
+ warn_at (*loc, _("empty character literal"));
+ /* '\0' seems dangerous even if we are about to complain. */
+ val->character = '\'';
+ }
+ else if (last_string[1] != '\0')
+ warn_at (*loc, _("extra characters in character literal"));
+ }
+ if (yytext[0] == '\n')
+ unexpected_newline (token_start, "'");
STRING_FREE;
BEGIN INITIAL;
return CHAR;
}
<<EOF>> {
- unexpected_eof (token_start, "'");
STRING_FINISH;
loc->start = token_start;
- if (strlen (last_string) > 1)
- val->character = last_string[1];
- else
- val->character = last_string[0];
+ val->character = last_string[0];
+ {
+ /* FIXME: Eventually, make these errors. */
+ if (last_string[0] == '\0')
+ {
+ warn_at (*loc, _("empty character literal"));
+ /* '\0' seems dangerous even if we are about to complain. */
+ val->character = '\'';
+ }
+ else if (last_string[1] != '\0')
+ warn_at (*loc, _("extra characters in character literal"));
+ }
+ unexpected_eof (token_start, "'");
STRING_FREE;
BEGIN INITIAL;
return CHAR;
{
\\[0-7]{1,3} {
unsigned long int c = strtoul (yytext + 1, NULL, 8);
- if (UCHAR_MAX < c)
- complain_at (*loc, _("invalid escape sequence: %s"), quote (yytext));
- else if (! c)
- complain_at (*loc, _("invalid null character: %s"), quote (yytext));
+ if (!c || UCHAR_MAX < c)
+ complain_at (*loc, _("invalid number after \\-escape: %s"),
+ yytext+1);
else
obstack_1grow (&obstack_for_string, c);
}
\\x[0-9abcdefABCDEF]+ {
verify (UCHAR_MAX < ULONG_MAX);
unsigned long int c = strtoul (yytext + 2, NULL, 16);
- if (UCHAR_MAX < c)
- complain_at (*loc, _("invalid escape sequence: %s"), quote (yytext));
- else if (! c)
- complain_at (*loc, _("invalid null character: %s"), quote (yytext));
+ if (!c || UCHAR_MAX < c)
+ complain_at (*loc, _("invalid number after \\-escape: %s"),
+ yytext+1);
else
obstack_1grow (&obstack_for_string, c);
}
\\(u|U[0-9abcdefABCDEF]{4})[0-9abcdefABCDEF]{4} {
int c = convert_ucn_to_byte (yytext);
- if (c < 0)
- complain_at (*loc, _("invalid escape sequence: %s"), quote (yytext));
- else if (! c)
- complain_at (*loc, _("invalid null character: %s"), quote (yytext));
+ if (c <= 0)
+ complain_at (*loc, _("invalid number after \\-escape: %s"),
+ yytext+1);
else
obstack_1grow (&obstack_for_string, c);
}
\\(.|\n) {
- complain_at (*loc, _("unrecognized escape sequence: %s"), quote (yytext));
- STRING_GROW;
+ char const *p = yytext + 1;
+ /* Quote only if escaping won't make the character visible. */
+ if (isspace ((unsigned char) *p) && isprint ((unsigned char) *p))
+ p = quote (p);
+ else
+ p = quotearg_style_mem (escape_quoting_style, p, 1);
+ complain_at (*loc, _("invalid character after \\-escape: %s"), p);
}
}
| Strings, comments etc. can be found in user code. |
`---------------------------------------------------*/
-<SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>
+<SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE,SC_PREDICATE>
{
"'" {
STRING_GROW;
/*-----------------------------------------------------------.
- | Scanning some code in braces (actions). The initial "{" is |
- | already eaten. |
+ | Scanning some code in braces (actions, predicates). The |
+ | initial "{" is already eaten. |
`-----------------------------------------------------------*/
-<SC_BRACED_CODE>
+<SC_BRACED_CODE,SC_PREDICATE>
{
"{"|"<"{splice}"%" STRING_GROW; nesting++;
"%"{splice}">" STRING_GROW; nesting--;
+
+ /* Tokenize `<<%' correctly (as `<<' `%') rather than incorrrectly
+ (as `<' `<%'). */
+ "<"{splice}"<" STRING_GROW;
+
+ <<EOF>> {
+ int token = (YY_START == SC_BRACED_CODE) ? BRACED_CODE : BRACED_PREDICATE;
+ unexpected_eof (code_start, "}");
+ STRING_FINISH;
+ loc->start = code_start;
+ val->code = last_string;
+ BEGIN INITIAL;
+ return token;
+ }
+}
+
+<SC_BRACED_CODE>
+{
"}" {
obstack_1grow (&obstack_for_string, '}');
return BRACED_CODE;
}
}
+}
- /* Tokenize `<<%' correctly (as `<<' `%') rather than incorrrectly
- (as `<' `<%'). */
- "<"{splice}"<" STRING_GROW;
-
- <<EOF>> {
- unexpected_eof (code_start, "}");
- STRING_FINISH;
- loc->start = code_start;
- val->code = last_string;
- BEGIN INITIAL;
- return BRACED_CODE;
+<SC_PREDICATE>
+{
+ "}" {
+ --nesting;
+ if (nesting < 0)
+ {
+ STRING_FINISH;
+ loc->start = code_start;
+ val->code = last_string;
+ BEGIN INITIAL;
+ return BRACED_PREDICATE;
+ }
+ else
+ obstack_1grow (&obstack_for_string, '}');
}
}
-
/*--------------------------------------------------------------.
| Scanning some prologue: from "%{" (already scanned) to "%}". |
`--------------------------------------------------------------*/
| By default, grow the string obstack with the input. |
`-----------------------------------------------------*/
-<SC_COMMENT,SC_LINE_COMMENT,SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE,SC_STRING,SC_CHARACTER,SC_ESCAPED_STRING,SC_ESCAPED_CHARACTER>. |
-<SC_COMMENT,SC_LINE_COMMENT,SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>\n STRING_GROW;
+<SC_COMMENT,SC_LINE_COMMENT,SC_BRACED_CODE,SC_PREDICATE,SC_PROLOGUE,SC_EPILOGUE,SC_STRING,SC_CHARACTER,SC_ESCAPED_STRING,SC_ESCAPED_CHARACTER>. |
+ <SC_COMMENT,SC_LINE_COMMENT,SC_BRACED_CODE,SC_PREDICATE,SC_PROLOGUE,SC_EPILOGUE>\n STRING_GROW;
%%