X-Git-Url: https://git.saurik.com/bison.git/blobdiff_plain/c046698e6e98aefa7f234b8035fe4cf20ce5d05d..fc28638e1c4ef0c41ad52b832b547305ea8c1784:/src/scan-gram.l diff --git a/src/scan-gram.l b/src/scan-gram.l index b37b29b0..5e78cb9b 100644 --- a/src/scan-gram.l +++ b/src/scan-gram.l @@ -1,7 +1,6 @@ /* Bison Grammar Scanner -*- C -*- - Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free - Software Foundation, Inc. + Copyright (C) 2002-2012 Free Software Foundation, Inc. This file is part of Bison, the GNU Compiler Compiler. @@ -18,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -%option debug nodefault nounput noyywrap never-interactive +%option debug nodefault noinput nounput noyywrap never-interactive %option prefix="gram_" outfile="lex.yy.c" %{ @@ -37,6 +36,7 @@ #include "reader.h" #include "uniqstr.h" +#include #include #include @@ -55,9 +55,21 @@ static boundary scanner_cursor; 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) { @@ -76,11 +88,11 @@ static void unexpected_newline (boundary, char const *); /* Strings and characters in directives/rules. */ %x SC_ESCAPED_STRING SC_ESCAPED_CHARACTER /* A identifier was just read in directives/rules. Special state - to capture the sequence `identifier :'. */ + to capture the sequence 'identifier :'. */ %x SC_AFTER_IDENTIFIER /* Three types of user code: - - prologue (code between `%{' `%}' in the first section, before %%); + - 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 @@ -88,10 +100,12 @@ static void unexpected_newline (boundary, char const *); %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])* -directive %{id} +letter [.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_] +notletter [^.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]{-}[%\{] +id {letter}({letter}|[-0-9])* int [0-9]+ /* POSIX says that a tag must be both an id and a C union member, but @@ -106,13 +120,13 @@ splice (\\[ \f\t\v]*\n)* %% %{ /* Nesting level of the current code in braces. */ - int braces_level IF_LINT (= 0); + int braces_level PACIFY_CC (= 0); /* Parent context state, when applicable. */ - int context_state IF_LINT (= 0); + int context_state PACIFY_CC (= 0); /* Location of most recent identifier, when applicable. */ - location id_loc IF_LINT (= empty_location); + location id_loc PACIFY_CC (= empty_location); /* Where containing code started, when applicable. Its initial value is relevant only when yylex is invoked in the SC_EPILOGUE @@ -121,7 +135,7 @@ splice (\\[ \f\t\v]*\n)* /* Where containing comment or string or character literal started, when applicable. */ - boundary token_start IF_LINT (= scanner_cursor); + boundary token_start PACIFY_CC (= scanner_cursor); %} @@ -129,12 +143,12 @@ splice (\\[ \f\t\v]*\n)* | Scanning white space. | `-----------------------*/ - + { /* Comments and white space. */ - "," warn_at (*loc, _("stray `,' treated as white space")); + "," warn_at (*loc, _("stray ',' treated as white space")); [ \f\n\t\v] | - "//".* ; + "//".* continue; "/*" { token_start = loc->start; context_state = YY_START; @@ -143,7 +157,7 @@ splice (\\[ \f\t\v]*\n)* /* #line directives are not documented, and may be withdrawn or modified in future versions of Bison. */ - ^"#line "{int}" \"".*"\"\n" { + ^"#line "{int}(" \"".*"\"")?"\n" { handle_syncline (yytext + sizeof "#line " - 1, *loc); } } @@ -161,50 +175,50 @@ splice (\\[ \f\t\v]*\n)* { - "%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; - - {directive} { + "%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; + + "%"{id}|"%"{notletter}([[:graph:]])+ { complain_at (*loc, _("invalid directive: %s"), quote (yytext)); } @@ -217,6 +231,7 @@ splice (\\[ \f\t\v]*\n)* {id} { val->uniqstr = uniqstr_new (yytext); id_loc = *loc; + bracketed_id_str = NULL; BEGIN SC_AFTER_IDENTIFIER; } @@ -229,8 +244,14 @@ splice (\\[ \f\t\v]*\n)* return INT; } - /* Characters. We don't check there is only one. */ - "'" STRING_GROW; token_start = loc->start; BEGIN SC_ESCAPED_CHARACTER; + /* 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. */ + "'" token_start = loc->start; BEGIN SC_ESCAPED_CHARACTER; /* Strings. */ "\"" token_start = loc->start; BEGIN SC_ESCAPED_STRING; @@ -262,8 +283,17 @@ splice (\\[ \f\t\v]*\n)* return PERCENT_PERCENT; } - . { - complain_at (*loc, _("invalid character: %s"), quote (yytext)); + "[" { + bracketed_id_str = NULL; + bracketed_id_start = loc->start; + bracketed_id_context_state = YY_START; + BEGIN SC_BRACKETED_ID; + } + + [^\[%A-Za-z0-9_<>{}\"\'*;|=/, \f\n\t\v]+|. { + complain_at (*loc, "%s: %s", + ngettext ("invalid character", "invalid characters", yyleng), + quote_mem (yytext, yyleng)); } <> { @@ -279,40 +309,113 @@ splice (\\[ \f\t\v]*\n)* { + "[" { + 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; } <> { + BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL); *loc = id_loc; - BEGIN INITIAL; return ID; } } + /*--------------------------------. + | Scanning bracketed identifiers. | + `--------------------------------*/ + + +{ + {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")); + } + + [^\].A-Za-z0-9_/ \f\n\t\v]+|. { + complain_at (*loc, "%s: %s", + ngettext ("invalid character in bracketed name", + "invalid characters in bracketed name", yyleng), + quote_mem (yytext, yyleng)); + } + + <> { + BEGIN bracketed_id_context_state; + unexpected_eof (bracketed_id_start, "]"); + } +} + + +{ + . { + 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. | + | Scanning a Yacc comment. The initial '/ *' is already eaten. | `---------------------------------------------------------------*/ { "*/" BEGIN context_state; - .|\n ; + .|\n continue; <> unexpected_eof (token_start, "*/"); BEGIN context_state; } /*------------------------------------------------------------. - | Scanning a C comment. The initial `/ *' is already eaten. | + | Scanning a C comment. The initial '/ *' is already eaten. | `------------------------------------------------------------*/ @@ -323,7 +426,7 @@ splice (\\[ \f\t\v]*\n)* /*--------------------------------------------------------------. - | Scanning a line comment. The initial `//' is already eaten. | + | Scanning a line comment. The initial '//' is already eaten. | `--------------------------------------------------------------*/ @@ -368,24 +471,42 @@ splice (\\[ \f\t\v]*\n)* { "'"|"\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; } <> { - 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; @@ -406,10 +527,9 @@ splice (\\[ \f\t\v]*\n)* { \\[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); } @@ -417,10 +537,9 @@ splice (\\[ \f\t\v]*\n)* \\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); } @@ -438,16 +557,20 @@ splice (\\[ \f\t\v]*\n)* \\(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 (c_isspace ((unsigned char) *p) && c_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); } } @@ -531,8 +654,8 @@ splice (\\[ \f\t\v]*\n)* } } - /* Tokenize `<<%' correctly (as `<<' `%') rather than incorrrectly - (as `<' `<%'). */ + /* Tokenize '<<%' correctly (as '<<' '%') rather than incorrrectly + (as '<' '<%'). */ "<"{splice}"<" STRING_GROW; <> { @@ -722,23 +845,27 @@ convert_ucn_to_byte (char const *ucn) } -/*----------------------------------------------------------------. -| Handle `#line INT "FILE"'. ARGS has already skipped `#line '. | -`----------------------------------------------------------------*/ +/*---------------------------------------------------------------------. +| Handle '#line INT( "FILE")?\n'. ARGS has already skipped '#line '. | +`---------------------------------------------------------------------*/ static void handle_syncline (char *args, location loc) { - char *after_num; - unsigned long int lineno = strtoul (args, &after_num, 10); - char *file = strchr (after_num, '"') + 1; - *strchr (file, '"') = '\0'; + char *file; + unsigned long int lineno = strtoul (args, &file, 10); if (INT_MAX <= lineno) { warn_at (loc, _("line number overflow")); lineno = INT_MAX; } - current_file = uniqstr_new (file); + + file = mbschr (file, '"'); + if (file) + { + *mbschr (file + 1, '"') = '\0'; + current_file = uniqstr_new (file + 1); + } boundary_set (&scanner_cursor, current_file, lineno, 1); } @@ -755,6 +882,10 @@ unexpected_end (boundary start, char const *msgid, char const *token_end) location loc; loc.start = start; loc.end = scanner_cursor; + token_end = quote (token_end); + // Instead of '\'', display "'". + if (!strcmp (token_end, "'\\''")) + token_end = "\"'\""; complain_at (loc, _(msgid), token_end); } @@ -767,7 +898,7 @@ unexpected_end (boundary start, char const *msgid, char const *token_end) static void unexpected_eof (boundary start, char const *token_end) { - unexpected_end (start, N_("missing `%s' at end of file"), token_end); + unexpected_end (start, N_("missing %s at end of file"), token_end); } @@ -778,7 +909,7 @@ unexpected_eof (boundary start, char const *token_end) static void unexpected_newline (boundary start, char const *token_end) { - unexpected_end (start, N_("missing `%s' at end of line"), token_end); + unexpected_end (start, N_("missing %s at end of line"), token_end); }