aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/glsl/glcpp
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/glsl/glcpp')
-rw-r--r--mesalib/src/glsl/glcpp/glcpp-lex.l79
-rw-r--r--mesalib/src/glsl/glcpp/glcpp-parse.y24
-rw-r--r--mesalib/src/glsl/glcpp/glcpp.h2
3 files changed, 94 insertions, 11 deletions
diff --git a/mesalib/src/glsl/glcpp/glcpp-lex.l b/mesalib/src/glsl/glcpp/glcpp-lex.l
index a029f6203..f1fa192c5 100644
--- a/mesalib/src/glsl/glcpp/glcpp-lex.l
+++ b/mesalib/src/glsl/glcpp/glcpp-lex.l
@@ -67,7 +67,7 @@ void glcpp_set_column (int column_no , yyscan_t yyscanner);
%option stack
%option never-interactive
-%x DONE COMMENT UNREACHABLE SKIP DEFINE
+%x DONE COMMENT UNREACHABLE SKIP DEFINE NEWLINE_CATCHUP
SPACE [[:space:]]
NONSPACE [^[:space:]]
@@ -92,13 +92,62 @@ OCTAL_INTEGER 0[0-7]*[uU]?
HEXADECIMAL_INTEGER 0[xX][0-9a-fA-F]+[uU]?
%%
- /* Implicitly switch between SKIP and INITIAL (non-skipping);
- * don't switch if some other state was explicitly set.
- */
+
glcpp_parser_t *parser = yyextra;
- if (YY_START == 0 || YY_START == SKIP) {
- if (parser->lexing_if || parser->skip_stack == NULL || parser->skip_stack->type == SKIP_NO_SKIP) {
- BEGIN 0;
+
+ /* When we lex a multi-line comment, we replace it (as
+ * specified) with a single space. But if the comment spanned
+ * multiple lines, then subsequent parsing stages will not
+ * count correct line numbers. To avoid this problem we keep
+ * track of all newlines that were commented out by a
+ * multi-line comment, and we emit a NEWLINE token for each at
+ * the next legal opportunity, (which is when the lexer would
+ * be emitting a NEWLINE token anyway).
+ */
+ if (YY_START == NEWLINE_CATCHUP) {
+ if (parser->commented_newlines)
+ parser->commented_newlines--;
+ if (parser->commented_newlines == 0)
+ BEGIN INITIAL;
+ return NEWLINE;
+ }
+
+ /* The handling of the SKIP vs INITIAL start states requires
+ * some special handling. Typically, a lexer would change
+ * start states with statements like "BEGIN SKIP" within the
+ * lexer rules. We can't get away with that here, since we
+ * need the parser to actually evaluate expressions for
+ * directives like "#if".
+ *
+ * So, here, in code that will be executed on every call to
+ * the lexer,and before any rules, we examine the skip_stack
+ * as set by the parser to know whether to change from INITIAL
+ * to SKIP or from SKIP back to INITIAL.
+ *
+ * Three cases cause us to switch out of the SKIP state and
+ * back to the INITIAL state:
+ *
+ * 1. The top of the skip_stack is of type SKIP_NO_SKIP
+ * This means we're still evaluating some #if
+ * hierarchy, but we're on a branch of it where
+ * content should not be skipped (such as "#if 1" or
+ * "#else" or so).
+ *
+ * 2. The skip_stack is NULL meaning that we've reached
+ * the last #endif.
+ *
+ * 3. The lexing_if bit is set. This indicates that we
+ * are lexing the expression following an "#if" of
+ * "#elif". Even inside an "#if 0" we need to lex this
+ * expression so the parser can correctly update the
+ * skip_stack state.
+ */
+ if (YY_START == INITIAL || YY_START == SKIP) {
+ if (parser->lexing_if ||
+ parser->skip_stack == NULL ||
+ parser->skip_stack->type == SKIP_NO_SKIP)
+ {
+ BEGIN INITIAL;
} else {
BEGIN SKIP;
}
@@ -106,14 +155,16 @@ HEXADECIMAL_INTEGER 0[xX][0-9a-fA-F]+[uU]?
/* Single-line comments */
"//"[^\n]* {
+ if (parser->commented_newlines)
+ BEGIN NEWLINE_CATCHUP;
}
/* Multi-line comments */
"/*" { yy_push_state(COMMENT, yyscanner); }
<COMMENT>[^*\n]*
-<COMMENT>[^*\n]*\n { yylineno++; yycolumn = 0; return NEWLINE; }
+<COMMENT>[^*\n]*\n { yylineno++; yycolumn = 0; parser->commented_newlines++; }
<COMMENT>"*"+[^*/\n]*
-<COMMENT>"*"+[^*/\n]*\n { yylineno++; yycolumn = 0; return NEWLINE; }
+<COMMENT>"*"+[^*/\n]*\n { yylineno++; yycolumn = 0; parser->commented_newlines++; }
<COMMENT>"*"+"/" {
yy_pop_state(yyscanner);
if (yyextra->space_tokens)
@@ -129,6 +180,8 @@ HEXADECIMAL_INTEGER 0[xX][0-9a-fA-F]+[uU]?
/* glcpp doesn't handle #extension, #version, or #pragma directives.
* Simply pass them through to the main compiler's lexer/parser. */
{HASH}(extension|pragma)[^\n]+ {
+ if (parser->commented_newlines)
+ BEGIN NEWLINE_CATCHUP;
yylval->str = ralloc_strdup (yyextra, yytext);
yylineno++;
yycolumn = 0;
@@ -175,7 +228,10 @@ HEXADECIMAL_INTEGER 0[xX][0-9a-fA-F]+[uU]?
}
}
-<SKIP>[^\n] ;
+<SKIP>[^\n] {
+ if (parser->commented_newlines)
+ BEGIN NEWLINE_CATCHUP;
+}
{HASH}error.* {
char *p;
@@ -290,6 +346,9 @@ HEXADECIMAL_INTEGER 0[xX][0-9a-fA-F]+[uU]?
}
<SKIP,INITIAL>\n {
+ if (parser->commented_newlines) {
+ BEGIN NEWLINE_CATCHUP;
+ }
yyextra->lexing_if = 0;
yylineno++;
yycolumn = 0;
diff --git a/mesalib/src/glsl/glcpp/glcpp-parse.y b/mesalib/src/glsl/glcpp/glcpp-parse.y
index 7edc27488..ef084b639 100644
--- a/mesalib/src/glsl/glcpp/glcpp-parse.y
+++ b/mesalib/src/glsl/glcpp/glcpp-parse.y
@@ -310,6 +310,11 @@ control_line:
_glcpp_parser_expand_and_lex_from (parser,
ELIF_EXPANDED, $2);
}
+ else if (parser->skip_stack &&
+ parser->skip_stack->has_else)
+ {
+ glcpp_error(& @1, parser, "#elif after #else");
+ }
else
{
_glcpp_parser_skip_stack_change_if (parser, & @1,
@@ -324,6 +329,11 @@ control_line:
{
glcpp_error(& @1, parser, "#elif with no expression");
}
+ else if (parser->skip_stack &&
+ parser->skip_stack->has_else)
+ {
+ glcpp_error(& @1, parser, "#elif after #else");
+ }
else
{
_glcpp_parser_skip_stack_change_if (parser, & @1,
@@ -332,7 +342,17 @@ control_line:
}
}
| HASH_ELSE {
- _glcpp_parser_skip_stack_change_if (parser, & @1, "else", 1);
+ if (parser->skip_stack &&
+ parser->skip_stack->has_else)
+ {
+ glcpp_error(& @1, parser, "multiple #else");
+ }
+ else
+ {
+ _glcpp_parser_skip_stack_change_if (parser, & @1, "else", 1);
+ if (parser->skip_stack)
+ parser->skip_stack->has_else = true;
+ }
} NEWLINE
| HASH_ENDIF {
_glcpp_parser_skip_stack_pop (parser, & @1);
@@ -1164,6 +1184,7 @@ glcpp_parser_create (const struct gl_extensions *extensions, int api)
parser->newline_as_space = 0;
parser->in_control_line = 0;
parser->paren_count = 0;
+ parser->commented_newlines = 0;
parser->skip_stack = NULL;
@@ -2024,6 +2045,7 @@ _glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc,
node->type = SKIP_TO_ENDIF;
}
+ node->has_else = false;
node->next = parser->skip_stack;
parser->skip_stack = node;
}
diff --git a/mesalib/src/glsl/glcpp/glcpp.h b/mesalib/src/glsl/glcpp/glcpp.h
index 8aaa551d1..85f3fdcd2 100644
--- a/mesalib/src/glsl/glcpp/glcpp.h
+++ b/mesalib/src/glsl/glcpp/glcpp.h
@@ -153,6 +153,7 @@ typedef enum skip_type {
typedef struct skip_node {
skip_type_t type;
+ bool has_else;
YYLTYPE loc; /* location of the initial #if/#elif/... */
struct skip_node *next;
} skip_node_t;
@@ -172,6 +173,7 @@ struct glcpp_parser {
int newline_as_space;
int in_control_line;
int paren_count;
+ int commented_newlines;
skip_node_t *skip_stack;
token_list_t *lex_from_list;
token_node_t *lex_from_node;