%option prefix="glcpp_"
%option stack
%option never-interactive
+%option warn nodefault
-%x DONE COMMENT HASH UNREACHABLE DEFINE NEWLINE_CATCHUP
+ /* Note: When adding any start conditions to this list, you must also
+ * update the "Internal compiler error" catch-all rule near the end of
+ * this file. */
+
+%x COMMENT DEFINE DONE HASH NEWLINE_CATCHUP UNREACHABLE
SPACE [[:space:]]
NONSPACE [^[:space:]]
-NEWLINE [\n]
HSPACE [ \t]
HASH #
IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]*
}
/* Single-line comments */
-"//"[^\n]* {
+<INITIAL,DEFINE,HASH>"//"[^\r\n]* {
}
/* Multi-line comments */
-<DEFINE,HASH,INITIAL>"/*" { yy_push_state(COMMENT, yyscanner); }
-<COMMENT>[^*\n]*
-<COMMENT>[^*\n]*\n { yylineno++; yycolumn = 0; parser->commented_newlines++; }
-<COMMENT>"*"+[^*/\n]*
-<COMMENT>"*"+[^*/\n]*\n { yylineno++; yycolumn = 0; parser->commented_newlines++; }
+<INITIAL,DEFINE,HASH>"/*" { yy_push_state(COMMENT, yyscanner); }
+<COMMENT>[^*\r\n]*
+<COMMENT>[^*\r\n]*[\r\n] { yylineno++; yycolumn = 0; parser->commented_newlines++; }
+<COMMENT>"*"+[^*/\r\n]*
+<COMMENT>"*"+[^*/\r\n]*[\r\n] { yylineno++; yycolumn = 0; parser->commented_newlines++; }
<COMMENT>"*"+"/" {
yy_pop_state(yyscanner);
/* In the <HASH> start condition, we don't want any SPACE token. */
<HASH>version{HSPACE}+ {
BEGIN INITIAL;
yyextra->space_tokens = 0;
- RETURN_STRING_TOKEN (HASH_VERSION);
+ RETURN_STRING_TOKEN (VERSION_TOKEN);
+}
+
+ /* Swallow empty #pragma directives, (to avoid confusing the
+ * downstream compiler). */
+<HASH>pragma{HSPACE}*/[\r\n] {
+ BEGIN INITIAL;
}
/* glcpp doesn't handle #extension, #version, or #pragma directives.
* Simply pass them through to the main compiler's lexer/parser. */
-<HASH>(extension|pragma)[^\n]* {
+<HASH>(extension|pragma)[^\r\n]* {
BEGIN INITIAL;
- yylineno++;
- yycolumn = 0;
- RETURN_STRING_TOKEN (HASH_PRAGMA);
+ RETURN_STRING_TOKEN (PRAGMA);
}
<HASH>line{HSPACE}+ {
BEGIN INITIAL;
- RETURN_TOKEN (HASH_LINE);
+ RETURN_TOKEN (LINE);
}
<HASH>\n {
BEGIN INITIAL;
yyextra->lexing_directive = 1;
yyextra->space_tokens = 0;
- RETURN_TOKEN_NEVER_SKIP (HASH_IFDEF);
+ RETURN_TOKEN_NEVER_SKIP (IFDEF);
}
<HASH>ifndef {
BEGIN INITIAL;
yyextra->lexing_directive = 1;
yyextra->space_tokens = 0;
- RETURN_TOKEN_NEVER_SKIP (HASH_IFNDEF);
+ RETURN_TOKEN_NEVER_SKIP (IFNDEF);
}
<HASH>if/[^_a-zA-Z0-9] {
BEGIN INITIAL;
yyextra->lexing_directive = 1;
yyextra->space_tokens = 0;
- RETURN_TOKEN_NEVER_SKIP (HASH_IF);
+ RETURN_TOKEN_NEVER_SKIP (IF);
}
<HASH>elif/[^_a-zA-Z0-9] {
BEGIN INITIAL;
yyextra->lexing_directive = 1;
yyextra->space_tokens = 0;
- RETURN_TOKEN_NEVER_SKIP (HASH_ELIF);
+ RETURN_TOKEN_NEVER_SKIP (ELIF);
}
<HASH>else {
BEGIN INITIAL;
yyextra->space_tokens = 0;
- RETURN_TOKEN_NEVER_SKIP (HASH_ELSE);
+ RETURN_TOKEN_NEVER_SKIP (ELSE);
}
<HASH>endif {
BEGIN INITIAL;
yyextra->space_tokens = 0;
- RETURN_TOKEN_NEVER_SKIP (HASH_ENDIF);
+ RETURN_TOKEN_NEVER_SKIP (ENDIF);
}
<HASH>error.* {
BEGIN INITIAL;
- RETURN_STRING_TOKEN (HASH_ERROR);
+ RETURN_STRING_TOKEN (ERROR_TOKEN);
}
/* After we see a "#define" we enter the <DEFINE> start state
* * Anything else, (not an identifier, not a comment,
* and not whitespace). This will generate an error.
*/
-<HASH>define{HSPACE}+ {
+<HASH>define{HSPACE}* {
if (! parser->skipping) {
BEGIN DEFINE;
yyextra->space_tokens = 0;
- RETURN_TOKEN (HASH_DEFINE);
+ RETURN_TOKEN (DEFINE_TOKEN);
}
}
<HASH>undef {
BEGIN INITIAL;
yyextra->space_tokens = 0;
- RETURN_TOKEN (HASH_UNDEF);
+ RETURN_TOKEN (UNDEF);
}
<HASH>{HSPACE}+ {
/* This will catch any non-directive garbage after a HASH */
<HASH>{NONSPACE} {
BEGIN INITIAL;
- RETURN_TOKEN (HASH_GARBAGE);
+ RETURN_TOKEN (GARBAGE);
}
/* An identifier immediately followed by '(' */
RETURN_TOKEN (OR);
}
+"++" {
+ RETURN_TOKEN (PLUS_PLUS);
+}
+
+"--" {
+ RETURN_TOKEN (MINUS_MINUS);
+}
+
"##" {
if (! parser->skipping) {
if (parser->is_gles)
/* We preserve all newlines, even between #if 0..#endif, so no
skipping.. */
-\n {
+<*>[\r\n] {
if (parser->commented_newlines) {
BEGIN NEWLINE_CATCHUP;
+ } else {
+ BEGIN INITIAL;
}
yyextra->space_tokens = 1;
yyextra->lexing_directive = 0;
<INITIAL,COMMENT,DEFINE,HASH><<EOF>> {
if (YY_START == COMMENT)
glcpp_error(yylloc, yyextra, "Unterminated comment");
- if (YY_START == DEFINE)
- glcpp_error(yylloc, yyextra, "#define without macro name");
BEGIN DONE; /* Don't keep matching this rule forever. */
yyextra->lexing_directive = 0;
if (! parser->last_token_was_newline)
RETURN_TOKEN (NEWLINE);
}
+ /* This is a catch-all to avoid the annoying default flex action which
+ * matches any character and prints it. If any input ever matches this
+ * rule, then we have made a mistake above and need to fix one or more
+ * of the preceding patterns to match that input. */
+
+<*>. {
+ glcpp_error(yylloc, yyextra, "Internal compiler error: Unexpected character: %s", yytext);
+
/* We don't actually use the UNREACHABLE start condition. We
- only have this action here so that we can pretend to call some
+ only have this block here so that we can pretend to call some
generated functions, (to avoid "defined but not used"
warnings. */
-<UNREACHABLE>. {
- unput('.');
- yy_top_state(yyextra);
+ if (YY_START == UNREACHABLE) {
+ unput('.');
+ yy_top_state(yyextra);
+ }
}
%%