static size_t no_cr_read (FILE *, char *, size_t);
#define YY_INPUT(buf, result, size) ((result) = no_cr_read (yyin, buf, size))
+#define ROLLBACK_CURRENT_TOKEN \
+ do { \
+ scanner_cursor.column -= mbsnwidth (yytext, yyleng, 0); \
+ yyless (0); \
+ } while (0)
+
/* A string representing the most recently saved token. */
static char *last_string;
+/* Bracketed identifier. */
+static uniqstr bracketed_id_str = 0;
+static location bracketed_id_loc;
+static boundary bracketed_id_start;
+static int bracketed_id_context_state = 0;
+
void
gram_scanner_last_string_free (void)
{
%x SC_COMMENT SC_LINE_COMMENT
/* Strings and characters in code. */
%x SC_STRING SC_CHARACTER
+ /* 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]+
| Scanning white space. |
`-----------------------*/
-<INITIAL,SC_AFTER_IDENTIFIER>
+<INITIAL,SC_AFTER_IDENTIFIER,SC_BRACKETED_ID,SC_RETURN_BRACKETED_ID>
{
/* Comments and white space. */
"," warn_at (*loc, _("stray `,' treated as white space"));
<INITIAL>
{
- "%binary" return PERCENT_NONASSOC;
+ "%binary" return PERCENT_NONASSOC;
"%code" return PERCENT_CODE;
- "%debug" return PERCENT_DEBUG;
- "%default"[-_]"prec" return PERCENT_DEFAULT_PREC;
- "%define" return PERCENT_DEFINE;
- "%defines" return PERCENT_DEFINES;
- "%destructor" return PERCENT_DESTRUCTOR;
- "%dprec" return PERCENT_DPREC;
- "%error"[-_]"verbose" return PERCENT_ERROR_VERBOSE;
- "%expect" return PERCENT_EXPECT;
- "%expect"[-_]"rr" return PERCENT_EXPECT_RR;
- "%file-prefix" return PERCENT_FILE_PREFIX;
+ "%debug" return PERCENT_DEBUG;
+ "%default"[-_]"prec" return PERCENT_DEFAULT_PREC;
+ "%define" return PERCENT_DEFINE;
+ "%defines" return PERCENT_DEFINES;
+ "%destructor" return PERCENT_DESTRUCTOR;
+ "%dprec" return PERCENT_DPREC;
+ "%error"[-_]"verbose" return PERCENT_ERROR_VERBOSE;
+ "%expect" return PERCENT_EXPECT;
+ "%expect"[-_]"rr" return PERCENT_EXPECT_RR;
+ "%file-prefix" return PERCENT_FILE_PREFIX;
"%fixed"[-_]"output"[-_]"files" return PERCENT_YACC;
- "%initial-action" return PERCENT_INITIAL_ACTION;
- "%glr-parser" return PERCENT_GLR_PARSER;
- "%language" return PERCENT_LANGUAGE;
- "%left" return PERCENT_LEFT;
- "%lex-param" return PERCENT_LEX_PARAM;
- "%locations" return PERCENT_LOCATIONS;
- "%merge" return PERCENT_MERGE;
- "%name"[-_]"prefix" return PERCENT_NAME_PREFIX;
- "%no"[-_]"default"[-_]"prec" return PERCENT_NO_DEFAULT_PREC;
- "%no"[-_]"lines" return PERCENT_NO_LINES;
- "%nonassoc" return PERCENT_NONASSOC;
- "%nondeterministic-parser" return PERCENT_NONDETERMINISTIC_PARSER;
- "%nterm" return PERCENT_NTERM;
- "%output" return PERCENT_OUTPUT;
- "%parse-param" return PERCENT_PARSE_PARAM;
- "%prec" return PERCENT_PREC;
- "%printer" return PERCENT_PRINTER;
- "%pure"[-_]"parser" return PERCENT_PURE_PARSER;
- "%require" return PERCENT_REQUIRE;
- "%right" return PERCENT_RIGHT;
- "%skeleton" return PERCENT_SKELETON;
- "%start" return PERCENT_START;
- "%term" return PERCENT_TOKEN;
- "%token" return PERCENT_TOKEN;
- "%token"[-_]"table" return PERCENT_TOKEN_TABLE;
- "%type" return PERCENT_TYPE;
- "%union" return PERCENT_UNION;
- "%verbose" return PERCENT_VERBOSE;
- "%yacc" return PERCENT_YACC;
+ "%initial-action" return PERCENT_INITIAL_ACTION;
+ "%glr-parser" return PERCENT_GLR_PARSER;
+ "%language" return PERCENT_LANGUAGE;
+ "%left" return PERCENT_LEFT;
+ "%lex-param" return PERCENT_LEX_PARAM;
+ "%locations" return PERCENT_LOCATIONS;
+ "%merge" return PERCENT_MERGE;
+ "%name"[-_]"prefix" return PERCENT_NAME_PREFIX;
+ "%no"[-_]"default"[-_]"prec" return PERCENT_NO_DEFAULT_PREC;
+ "%no"[-_]"lines" return PERCENT_NO_LINES;
+ "%nonassoc" return PERCENT_NONASSOC;
+ "%nondeterministic-parser" return PERCENT_NONDETERMINISTIC_PARSER;
+ "%nterm" return PERCENT_NTERM;
+ "%output" return PERCENT_OUTPUT;
+ "%parse-param" return PERCENT_PARSE_PARAM;
+ "%prec" return PERCENT_PREC;
+ "%printer" return PERCENT_PRINTER;
+ "%pure"[-_]"parser" return PERCENT_PURE_PARSER;
+ "%require" return PERCENT_REQUIRE;
+ "%right" return PERCENT_RIGHT;
+ "%skeleton" return PERCENT_SKELETON;
+ "%start" return PERCENT_START;
+ "%term" return PERCENT_TOKEN;
+ "%token" return PERCENT_TOKEN;
+ "%token"[-_]"table" return PERCENT_TOKEN_TABLE;
+ "%type" return PERCENT_TYPE;
+ "%union" return PERCENT_UNION;
+ "%verbose" return PERCENT_VERBOSE;
+ "%yacc" return PERCENT_YACC;
{directive} {
complain_at (*loc, _("invalid directive: %s"), quote (yytext));
{id} {
val->uniqstr = uniqstr_new (yytext);
id_loc = *loc;
+ bracketed_id_str = NULL;
BEGIN SC_AFTER_IDENTIFIER;
}
return INT;
}
- /* Characters. We don't check there is only one. */
+ /* Identifiers may not start with a digit. Yet, don't silently
+ accept "1FOO" as "1 FOO". */
+ {int}{id} {
+ complain_at (*loc, _("invalid identifier: %s"), quote (yytext));
+ }
+
+ /* Characters. */
"'" STRING_GROW; token_start = loc->start; BEGIN SC_ESCAPED_CHARACTER;
/* Strings. */
return PERCENT_PERCENT;
}
+ "[" {
+ bracketed_id_str = NULL;
+ bracketed_id_start = loc->start;
+ bracketed_id_context_state = YY_START;
+ BEGIN SC_BRACKETED_ID;
+ }
+
. {
complain_at (*loc, _("invalid character: %s"), quote (yytext));
}
<SC_AFTER_IDENTIFIER>
{
+ "[" {
+ 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);
*loc = id_loc;
- BEGIN INITIAL;
return ID_COLON;
}
. {
- scanner_cursor.column -= mbsnwidth (yytext, yyleng, 0);
- yyless (0);
+ ROLLBACK_CURRENT_TOKEN;
+ BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
*loc = id_loc;
- BEGIN INITIAL;
return ID;
}
<<EOF>> {
+ BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
*loc = id_loc;
- BEGIN INITIAL;
return ID;
}
}
+ /*--------------------------------.
+ | Scanning bracketed identifiers. |
+ `--------------------------------*/
+
+<SC_BRACKETED_ID>
+{
+ {id} {
+ if (bracketed_id_str)
+ {
+ complain_at (*loc, _("unexpected identifier in bracketed name: %s"),
+ quote (yytext));
+ }
+ else
+ {
+ bracketed_id_str = uniqstr_new (yytext);
+ bracketed_id_loc = *loc;
+ }
+ }
+ "]" {
+ BEGIN bracketed_id_context_state;
+ if (bracketed_id_str)
+ {
+ if (INITIAL == bracketed_id_context_state)
+ {
+ val->uniqstr = bracketed_id_str;
+ bracketed_id_str = 0;
+ *loc = bracketed_id_loc;
+ return BRACKETED_ID;
+ }
+ }
+ else
+ complain_at (*loc, _("an identifier expected"));
+ }
+ . {
+ complain_at (*loc, _("invalid character in bracketed name: %s"),
+ quote (yytext));
+ }
+ <<EOF>> {
+ BEGIN bracketed_id_context_state;
+ unexpected_eof (bracketed_id_start, "]");
+ }
+}
+
+<SC_RETURN_BRACKETED_ID>
+{
+ . {
+ ROLLBACK_CURRENT_TOKEN;
+ val->uniqstr = bracketed_id_str;
+ bracketed_id_str = 0;
+ *loc = bracketed_id_loc;
+ BEGIN INITIAL;
+ return BRACKETED_ID;
+ }
+}
+
/*---------------------------------------------------------------.
| Scanning a Yacc comment. The initial `/ *' is already eaten. |
<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];
+ {
+ /* FIXME: Eventually, make these errors. */
+ size_t length = strlen (last_string);
+ if (strlen (last_string) < 3)
+ warn_at (*loc, _("empty character literal"));
+ else if (strlen (last_string) > 3)
+ 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];
+ {
+ size_t length = strlen (last_string);
+ /* FIXME: Eventually, make these errors. */
+ if (length < 2)
+ warn_at (*loc, _("empty character literal"));
+ else if (length > 2)
+ warn_at (*loc, _("extra characters in character literal"));
+ if (length > 1)
+ val->character = last_string[1];
+ else
+ val->character = last_string[0];
+ }
+ unexpected_eof (token_start, "'");
STRING_FREE;
BEGIN INITIAL;
return CHAR;