Commit 809ec546 by Olli Etuaho

Don't evaluate short-circuited preprocessor expressions

Resubmit with clang build issue fixed. The result of a short-circuited operation is now either 0 or 1. ESSL 3.00 spec section 3.4 mentions that the second operand in a logical && or || preprocessor operation is evaluated only if the first operand doesn't short-circuit the expression. The non-evaluated part of a preprocessor expression may also have undefined identifiers. Make the expression parser follow the spec by ignoring errors that are generated inside short-circuited expressions. This includes undefined identifiers and divide by zero. BUG=angleproject:347 TEST=dEQP-GLES3.functional.shaders.preprocessor.undefined_identifiers.* angle_unittests Change-Id: I4163f96ec46d40ac859ffb39d91b89490041e44d Reviewed-on: https://chromium-review.googlesource.com/297252Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 9a1b49f7
...@@ -122,6 +122,13 @@ struct Context ...@@ -122,6 +122,13 @@ struct Context
pp::Lexer* lexer; pp::Lexer* lexer;
pp::Token* token; pp::Token* token;
int* result; int* result;
void startIgnoreErrors() { ++ignoreErrors; }
void endIgnoreErrors() { --ignoreErrors; }
bool isIgnoringErrors() { return ignoreErrors > 0; }
int ignoreErrors;
}; };
} // namespace } // namespace
...@@ -162,15 +169,16 @@ extern int ppdebug; ...@@ -162,15 +169,16 @@ extern int ppdebug;
enum yytokentype enum yytokentype
{ {
TOK_CONST_INT = 258, TOK_CONST_INT = 258,
TOK_OP_OR = 259, TOK_IDENTIFIER = 259,
TOK_OP_AND = 260, TOK_OP_OR = 260,
TOK_OP_EQ = 261, TOK_OP_AND = 261,
TOK_OP_NE = 262, TOK_OP_EQ = 262,
TOK_OP_LE = 263, TOK_OP_NE = 263,
TOK_OP_GE = 264, TOK_OP_LE = 264,
TOK_OP_LEFT = 265, TOK_OP_GE = 265,
TOK_OP_RIGHT = 266, TOK_OP_LEFT = 266,
TOK_UNARY = 267 TOK_OP_RIGHT = 267,
TOK_UNARY = 268
}; };
#endif #endif
...@@ -429,23 +437,23 @@ union yyalloc ...@@ -429,23 +437,23 @@ union yyalloc
#endif /* !YYCOPY_NEEDED */ #endif /* !YYCOPY_NEEDED */
/* YYFINAL -- State number of the termination state. */ /* YYFINAL -- State number of the termination state. */
#define YYFINAL 14 #define YYFINAL 15
/* YYLAST -- Last index in YYTABLE. */ /* YYLAST -- Last index in YYTABLE. */
#define YYLAST 175 #define YYLAST 176
/* YYNTOKENS -- Number of terminals. */ /* YYNTOKENS -- Number of terminals. */
#define YYNTOKENS 27 #define YYNTOKENS 28
/* YYNNTS -- Number of nonterminals. */ /* YYNNTS -- Number of nonterminals. */
#define YYNNTS 3 #define YYNNTS 5
/* YYNRULES -- Number of rules. */ /* YYNRULES -- Number of rules. */
#define YYNRULES 26 #define YYNRULES 29
/* YYNSTATES -- Number of states. */ /* YYNSTATES -- Number of states. */
#define YYNSTATES 52 #define YYNSTATES 55
/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
by yylex, with out-of-bounds checking. */ by yylex, with out-of-bounds checking. */
#define YYUNDEFTOK 2 #define YYUNDEFTOK 2
#define YYMAXUTOK 267 #define YYMAXUTOK 268
#define YYTRANSLATE(YYX) \ #define YYTRANSLATE(YYX) \
((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
...@@ -457,16 +465,16 @@ static const yytype_uint8 yytranslate[] = ...@@ -457,16 +465,16 @@ static const yytype_uint8 yytranslate[] =
0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 23, 2, 2, 2, 21, 8, 2, 2, 2, 2, 24, 2, 2, 2, 22, 9, 2,
25, 26, 19, 17, 2, 18, 2, 20, 2, 2, 26, 27, 20, 18, 2, 19, 2, 21, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
11, 2, 12, 2, 2, 2, 2, 2, 2, 2, 12, 2, 13, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 6, 2, 24, 2, 2, 2, 2, 2, 2, 2, 7, 2, 25, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
...@@ -480,16 +488,16 @@ static const yytype_uint8 yytranslate[] = ...@@ -480,16 +488,16 @@ static const yytype_uint8 yytranslate[] =
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
5, 9, 10, 13, 14, 15, 16, 22 5, 6, 10, 11, 14, 15, 16, 17, 23
}; };
#if YYDEBUG #if YYDEBUG
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
static const yytype_uint8 yyrline[] = static const yytype_uint16 yyrline[] =
{ {
0, 97, 97, 104, 105, 108, 111, 114, 117, 120, 0, 105, 105, 111, 112, 118, 118, 139, 139, 160,
123, 126, 129, 132, 135, 138, 141, 144, 147, 150, 163, 166, 169, 172, 175, 178, 181, 184, 187, 190,
163, 176, 179, 182, 185, 188, 191 193, 196, 199, 222, 245, 248, 251, 254, 257, 260
}; };
#endif #endif
...@@ -498,11 +506,11 @@ static const yytype_uint8 yyrline[] = ...@@ -498,11 +506,11 @@ static const yytype_uint8 yyrline[] =
First, the terminals, then, starting at YYNTOKENS, nonterminals. */ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
static const char *const yytname[] = static const char *const yytname[] =
{ {
"$end", "error", "$undefined", "TOK_CONST_INT", "TOK_OP_OR", "$end", "error", "$undefined", "TOK_CONST_INT", "TOK_IDENTIFIER",
"TOK_OP_AND", "'|'", "'^'", "'&'", "TOK_OP_EQ", "TOK_OP_NE", "'<'", "TOK_OP_OR", "TOK_OP_AND", "'|'", "'^'", "'&'", "TOK_OP_EQ", "TOK_OP_NE",
"'>'", "TOK_OP_LE", "TOK_OP_GE", "TOK_OP_LEFT", "TOK_OP_RIGHT", "'+'", "'<'", "'>'", "TOK_OP_LE", "TOK_OP_GE", "TOK_OP_LEFT", "TOK_OP_RIGHT",
"'-'", "'*'", "'/'", "'%'", "TOK_UNARY", "'!'", "'~'", "'('", "')'", "'+'", "'-'", "'*'", "'/'", "'%'", "TOK_UNARY", "'!'", "'~'", "'('",
"$accept", "input", "expression", YY_NULLPTR "')'", "$accept", "input", "expression", "$@1", "$@2", YY_NULLPTR
}; };
#endif #endif
...@@ -511,16 +519,16 @@ static const char *const yytname[] = ...@@ -511,16 +519,16 @@ static const char *const yytname[] =
(internal) symbol number NUM (which must be that of a token). */ (internal) symbol number NUM (which must be that of a token). */
static const yytype_uint16 yytoknum[] = static const yytype_uint16 yytoknum[] =
{ {
0, 256, 257, 258, 259, 260, 124, 94, 38, 261, 0, 256, 257, 258, 259, 260, 261, 124, 94, 38,
262, 60, 62, 263, 264, 265, 266, 43, 45, 42, 262, 263, 60, 62, 264, 265, 266, 267, 43, 45,
47, 37, 267, 33, 126, 40, 41 42, 47, 37, 268, 33, 126, 40, 41
}; };
# endif # endif
#define YYPACT_NINF -11 #define YYPACT_NINF -12
#define yypact_value_is_default(Yystate) \ #define yypact_value_is_default(Yystate) \
(!!((Yystate) == (-11))) (!!((Yystate) == (-12)))
#define YYTABLE_NINF -1 #define YYTABLE_NINF -1
...@@ -531,12 +539,12 @@ static const yytype_uint16 yytoknum[] = ...@@ -531,12 +539,12 @@ static const yytype_uint16 yytoknum[] =
STATE-NUM. */ STATE-NUM. */
static const yytype_int16 yypact[] = static const yytype_int16 yypact[] =
{ {
46, -11, 46, 46, 46, 46, 46, 12, 68, -11, 31, -12, -12, 31, 31, 31, 31, 31, 51, 76,
-11, -11, -11, 27, -11, 46, 46, 46, 46, 46, -12, -12, -12, -12, 53, -12, -12, -12, 31, 31,
46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
46, 46, 46, -11, 85, 101, 116, 130, 143, 154, 31, 31, 31, 31, -12, 31, 31, 124, 138, 26,
154, -10, -10, -10, -10, 37, 37, 31, 31, -11, 149, 149, -11, -11, -11, -11, 154, 154, -8, -8,
-11, -11 -12, -12, -12, 93, 109
}; };
/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
...@@ -544,24 +552,24 @@ static const yytype_int16 yypact[] = ...@@ -544,24 +552,24 @@ static const yytype_int16 yypact[] =
means the default is an error. */ means the default is an error. */
static const yytype_uint8 yydefact[] = static const yytype_uint8 yydefact[] =
{ {
0, 3, 0, 0, 0, 0, 0, 0, 2, 25, 0, 3, 4, 0, 0, 0, 0, 0, 0, 2,
24, 22, 23, 0, 1, 0, 0, 0, 0, 0, 28, 27, 25, 26, 0, 1, 5, 7, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 26, 4, 5, 6, 7, 8, 10, 0, 0, 0, 0, 29, 0, 0, 9, 10, 11,
9, 14, 13, 12, 11, 16, 15, 18, 17, 21, 13, 12, 17, 16, 15, 14, 19, 18, 21, 20,
20, 19 24, 23, 22, 6, 8
}; };
/* YYPGOTO[NTERM-NUM]. */ /* YYPGOTO[NTERM-NUM]. */
static const yytype_int8 yypgoto[] = static const yytype_int8 yypgoto[] =
{ {
-11, -11, -2 -12, -12, -3, -12, -12
}; };
/* YYDEFGOTO[NTERM-NUM]. */ /* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int8 yydefgoto[] = static const yytype_int8 yydefgoto[] =
{ {
-1, 7, 8 -1, 8, 9, 35, 36
}; };
/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
...@@ -569,74 +577,74 @@ static const yytype_int8 yydefgoto[] = ...@@ -569,74 +577,74 @@ static const yytype_int8 yydefgoto[] =
number is the opposite. If YYTABLE_NINF, syntax error. */ number is the opposite. If YYTABLE_NINF, syntax error. */
static const yytype_uint8 yytable[] = static const yytype_uint8 yytable[] =
{ {
9, 10, 11, 12, 13, 26, 27, 28, 29, 30, 10, 11, 12, 13, 14, 27, 28, 29, 30, 31,
31, 32, 14, 34, 35, 36, 37, 38, 39, 40, 32, 33, 31, 32, 33, 37, 38, 39, 40, 41,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
51, 15, 16, 17, 18, 19, 20, 21, 22, 23, 52, 0, 53, 54, 1, 2, 21, 22, 23, 24,
24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 25, 26, 27, 28, 29, 30, 31, 32, 33, 3,
30, 31, 32, 33, 28, 29, 30, 31, 32, 0, 4, 15, 0, 0, 0, 5, 6, 7, 16, 17,
0, 0, 0, 2, 3, 0, 0, 0, 0, 4, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
5, 6, 15, 16, 17, 18, 19, 20, 21, 22, 28, 29, 30, 31, 32, 33, 0, 0, 0, 0,
34, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, 32, 33, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31, 32, 33, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 33, 23, 24, 25, 26, 27, 28, 29, 30, 31,
26, 27, 28, 29, 30, 31, 32, 17, 18, 19, 32, 33, 29, 30, 31, 32, 33
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32, 20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, 32, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31, 32
}; };
static const yytype_int8 yycheck[] = static const yytype_int8 yycheck[] =
{ {
2, 3, 4, 5, 6, 15, 16, 17, 18, 19, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20,
20, 21, 0, 15, 16, 17, 18, 19, 20, 21, 21, 22, 20, 21, 22, 18, 19, 20, 21, 22,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
32, 4, 5, 6, 7, 8, 9, 10, 11, 12, 33, -1, 35, 36, 3, 4, 10, 11, 12, 13,
13, 14, 15, 16, 17, 18, 19, 20, 21, 3, 14, 15, 16, 17, 18, 19, 20, 21, 22, 18,
19, 20, 21, 26, 17, 18, 19, 20, 21, -1, 19, 0, -1, -1, -1, 24, 25, 26, 5, 6,
-1, -1, -1, 17, 18, -1, -1, -1, -1, 23, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
24, 25, 4, 5, 6, 7, 8, 9, 10, 11, 17, 18, 19, 20, 21, 22, -1, -1, -1, -1,
27, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 22, 12, 13, 14, 15, 16, 17, 18, 19, 20,
15, 16, 17, 18, 19, 20, 21, 6, 7, 8, 21, 22, 18, 19, 20, 21, 22
9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21
}; };
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
symbol of state STATE-NUM. */ symbol of state STATE-NUM. */
static const yytype_uint8 yystos[] = static const yytype_uint8 yystos[] =
{ {
0, 3, 17, 18, 23, 24, 25, 28, 29, 29, 0, 3, 4, 18, 19, 24, 25, 26, 29, 30,
29, 29, 29, 29, 0, 4, 5, 6, 7, 8, 30, 30, 30, 30, 30, 0, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 26, 29, 29, 29, 29, 29, 29, 19, 20, 21, 22, 27, 31, 32, 30, 30, 30,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
29, 29 30, 30, 30, 30, 30
}; };
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
static const yytype_uint8 yyr1[] = static const yytype_uint8 yyr1[] =
{ {
0, 27, 28, 29, 29, 29, 29, 29, 29, 29, 0, 28, 29, 30, 30, 31, 30, 32, 30, 30,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
29, 29, 29, 29, 29, 29, 29 30, 30, 30, 30, 30, 30, 30, 30, 30, 30
}; };
/* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
static const yytype_uint8 yyr2[] = static const yytype_uint8 yyr2[] =
{ {
0, 2, 1, 1, 3, 3, 3, 3, 3, 3, 0, 2, 1, 1, 1, 0, 4, 0, 4, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 2, 2, 2, 2, 3 3, 3, 3, 3, 3, 2, 2, 2, 2, 3
}; };
...@@ -1322,7 +1330,6 @@ yyreduce: ...@@ -1322,7 +1330,6 @@ yyreduce:
{ {
*(context->result) = static_cast<int>((yyvsp[0])); *(context->result) = static_cast<int>((yyvsp[0]));
YYACCEPT;
} }
break; break;
...@@ -1330,7 +1337,10 @@ yyreduce: ...@@ -1330,7 +1337,10 @@ yyreduce:
case 4: case 4:
{ {
(yyval) = (yyvsp[-2]) || (yyvsp[0]); if (!context->isIgnoringErrors())
{
YYABORT;
}
} }
break; break;
...@@ -1338,7 +1348,15 @@ yyreduce: ...@@ -1338,7 +1348,15 @@ yyreduce:
case 5: case 5:
{ {
(yyval) = (yyvsp[-2]) && (yyvsp[0]); if ((yyvsp[-1]) != 0)
{
// Ignore errors in the short-circuited part of the expression.
// ESSL3.00 section 3.4:
// If an operand is not evaluated, the presence of undefined identifiers
// in the operand will not cause an error.
// Unevaluated division by zero should not cause an error either.
context->startIgnoreErrors();
}
} }
break; break;
...@@ -1346,7 +1364,15 @@ yyreduce: ...@@ -1346,7 +1364,15 @@ yyreduce:
case 6: case 6:
{ {
(yyval) = (yyvsp[-2]) | (yyvsp[0]); if ((yyvsp[-3]) != 0)
{
context->endIgnoreErrors();
(yyval) = static_cast<YYSTYPE>(1);
}
else
{
(yyval) = (yyvsp[-3]) || (yyvsp[0]);
}
} }
break; break;
...@@ -1354,7 +1380,15 @@ yyreduce: ...@@ -1354,7 +1380,15 @@ yyreduce:
case 7: case 7:
{ {
(yyval) = (yyvsp[-2]) ^ (yyvsp[0]); if ((yyvsp[-1]) == 0)
{
// Ignore errors in the short-circuited part of the expression.
// ESSL3.00 section 3.4:
// If an operand is not evaluated, the presence of undefined identifiers
// in the operand will not cause an error.
// Unevaluated division by zero should not cause an error either.
context->startIgnoreErrors();
}
} }
break; break;
...@@ -1362,7 +1396,15 @@ yyreduce: ...@@ -1362,7 +1396,15 @@ yyreduce:
case 8: case 8:
{ {
(yyval) = (yyvsp[-2]) & (yyvsp[0]); if ((yyvsp[-3]) == 0)
{
context->endIgnoreErrors();
(yyval) = static_cast<YYSTYPE>(0);
}
else
{
(yyval) = (yyvsp[-3]) && (yyvsp[0]);
}
} }
break; break;
...@@ -1370,7 +1412,7 @@ yyreduce: ...@@ -1370,7 +1412,7 @@ yyreduce:
case 9: case 9:
{ {
(yyval) = (yyvsp[-2]) != (yyvsp[0]); (yyval) = (yyvsp[-2]) | (yyvsp[0]);
} }
break; break;
...@@ -1378,7 +1420,7 @@ yyreduce: ...@@ -1378,7 +1420,7 @@ yyreduce:
case 10: case 10:
{ {
(yyval) = (yyvsp[-2]) == (yyvsp[0]); (yyval) = (yyvsp[-2]) ^ (yyvsp[0]);
} }
break; break;
...@@ -1386,7 +1428,7 @@ yyreduce: ...@@ -1386,7 +1428,7 @@ yyreduce:
case 11: case 11:
{ {
(yyval) = (yyvsp[-2]) >= (yyvsp[0]); (yyval) = (yyvsp[-2]) & (yyvsp[0]);
} }
break; break;
...@@ -1394,7 +1436,7 @@ yyreduce: ...@@ -1394,7 +1436,7 @@ yyreduce:
case 12: case 12:
{ {
(yyval) = (yyvsp[-2]) <= (yyvsp[0]); (yyval) = (yyvsp[-2]) != (yyvsp[0]);
} }
break; break;
...@@ -1402,7 +1444,7 @@ yyreduce: ...@@ -1402,7 +1444,7 @@ yyreduce:
case 13: case 13:
{ {
(yyval) = (yyvsp[-2]) > (yyvsp[0]); (yyval) = (yyvsp[-2]) == (yyvsp[0]);
} }
break; break;
...@@ -1410,7 +1452,7 @@ yyreduce: ...@@ -1410,7 +1452,7 @@ yyreduce:
case 14: case 14:
{ {
(yyval) = (yyvsp[-2]) < (yyvsp[0]); (yyval) = (yyvsp[-2]) >= (yyvsp[0]);
} }
break; break;
...@@ -1418,7 +1460,7 @@ yyreduce: ...@@ -1418,7 +1460,7 @@ yyreduce:
case 15: case 15:
{ {
(yyval) = (yyvsp[-2]) >> (yyvsp[0]); (yyval) = (yyvsp[-2]) <= (yyvsp[0]);
} }
break; break;
...@@ -1426,7 +1468,7 @@ yyreduce: ...@@ -1426,7 +1468,7 @@ yyreduce:
case 16: case 16:
{ {
(yyval) = (yyvsp[-2]) << (yyvsp[0]); (yyval) = (yyvsp[-2]) > (yyvsp[0]);
} }
break; break;
...@@ -1434,7 +1476,7 @@ yyreduce: ...@@ -1434,7 +1476,7 @@ yyreduce:
case 17: case 17:
{ {
(yyval) = (yyvsp[-2]) - (yyvsp[0]); (yyval) = (yyvsp[-2]) < (yyvsp[0]);
} }
break; break;
...@@ -1442,7 +1484,7 @@ yyreduce: ...@@ -1442,7 +1484,7 @@ yyreduce:
case 18: case 18:
{ {
(yyval) = (yyvsp[-2]) + (yyvsp[0]); (yyval) = (yyvsp[-2]) >> (yyvsp[0]);
} }
break; break;
...@@ -1450,40 +1492,84 @@ yyreduce: ...@@ -1450,40 +1492,84 @@ yyreduce:
case 19: case 19:
{ {
if ((yyvsp[0]) == 0) { (yyval) = (yyvsp[-2]) << (yyvsp[0]);
std::ostringstream stream; }
stream << (yyvsp[-2]) << " % " << (yyvsp[0]);
std::string text = stream.str(); break;
context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
context->token->location, case 20:
text.c_str());
YYABORT; {
} else { (yyval) = (yyvsp[-2]) - (yyvsp[0]);
}
break;
case 21:
{
(yyval) = (yyvsp[-2]) + (yyvsp[0]);
}
break;
case 22:
{
if ((yyvsp[0]) == 0)
{
if (context->isIgnoringErrors())
{
(yyval) = static_cast<YYSTYPE>(0);
}
else
{
std::ostringstream stream;
stream << (yyvsp[-2]) << " % " << (yyvsp[0]);
std::string text = stream.str();
context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
context->token->location,
text.c_str());
YYABORT;
}
}
else
{
(yyval) = (yyvsp[-2]) % (yyvsp[0]); (yyval) = (yyvsp[-2]) % (yyvsp[0]);
} }
} }
break; break;
case 20: case 23:
{ {
if ((yyvsp[0]) == 0) { if ((yyvsp[0]) == 0)
std::ostringstream stream; {
stream << (yyvsp[-2]) << " / " << (yyvsp[0]); if (context->isIgnoringErrors())
std::string text = stream.str(); {
context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO, (yyval) = static_cast<YYSTYPE>(0);
context->token->location, }
text.c_str()); else
YYABORT; {
} else { std::ostringstream stream;
stream << (yyvsp[-2]) << " / " << (yyvsp[0]);
std::string text = stream.str();
context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
context->token->location,
text.c_str());
YYABORT;
}
}
else
{
(yyval) = (yyvsp[-2]) / (yyvsp[0]); (yyval) = (yyvsp[-2]) / (yyvsp[0]);
} }
} }
break; break;
case 21: case 24:
{ {
(yyval) = (yyvsp[-2]) * (yyvsp[0]); (yyval) = (yyvsp[-2]) * (yyvsp[0]);
...@@ -1491,7 +1577,7 @@ yyreduce: ...@@ -1491,7 +1577,7 @@ yyreduce:
break; break;
case 22: case 25:
{ {
(yyval) = ! (yyvsp[0]); (yyval) = ! (yyvsp[0]);
...@@ -1499,7 +1585,7 @@ yyreduce: ...@@ -1499,7 +1585,7 @@ yyreduce:
break; break;
case 23: case 26:
{ {
(yyval) = ~ (yyvsp[0]); (yyval) = ~ (yyvsp[0]);
...@@ -1507,7 +1593,7 @@ yyreduce: ...@@ -1507,7 +1593,7 @@ yyreduce:
break; break;
case 24: case 27:
{ {
(yyval) = - (yyvsp[0]); (yyval) = - (yyvsp[0]);
...@@ -1515,7 +1601,7 @@ yyreduce: ...@@ -1515,7 +1601,7 @@ yyreduce:
break; break;
case 25: case 28:
{ {
(yyval) = + (yyvsp[0]); (yyval) = + (yyvsp[0]);
...@@ -1523,7 +1609,7 @@ yyreduce: ...@@ -1523,7 +1609,7 @@ yyreduce:
break; break;
case 26: case 29:
{ {
(yyval) = (yyvsp[-1]); (yyval) = (yyvsp[-1]);
...@@ -1781,6 +1867,15 @@ int yylex(YYSTYPE *lvalp, Context *context) ...@@ -1781,6 +1867,15 @@ int yylex(YYSTYPE *lvalp, Context *context)
type = TOK_CONST_INT; type = TOK_CONST_INT;
break; break;
} }
case pp::Token::IDENTIFIER:
if (!context->isIgnoringErrors())
{
context->diagnostics->report(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
token->location, token->text);
}
*lvalp = static_cast<YYSTYPE>(-1);
type = TOK_IDENTIFIER;
break;
case pp::Token::OP_OR: case pp::Token::OP_OR:
type = TOK_OP_OR; type = TOK_OP_OR;
break; break;
...@@ -1855,6 +1950,7 @@ bool ExpressionParser::parse(Token *token, int *result) ...@@ -1855,6 +1950,7 @@ bool ExpressionParser::parse(Token *token, int *result)
context.lexer = mLexer; context.lexer = mLexer;
context.token = token; context.token = token;
context.result = result; context.result = result;
context.ignoreErrors = 0;
int ret = yyparse(&context); int ret = yyparse(&context);
switch (ret) switch (ret)
{ {
......
...@@ -64,6 +64,13 @@ struct Context ...@@ -64,6 +64,13 @@ struct Context
pp::Lexer* lexer; pp::Lexer* lexer;
pp::Token* token; pp::Token* token;
int* result; int* result;
void startIgnoreErrors() { ++ignoreErrors; }
void endIgnoreErrors() { --ignoreErrors; }
bool isIgnoringErrors() { return ignoreErrors > 0; }
int ignoreErrors;
}; };
} // namespace } // namespace
%} %}
...@@ -79,6 +86,7 @@ static void yyerror(Context* context, const char* reason); ...@@ -79,6 +86,7 @@ static void yyerror(Context* context, const char* reason);
%} %}
%token TOK_CONST_INT %token TOK_CONST_INT
%token TOK_IDENTIFIER
%left TOK_OP_OR %left TOK_OP_OR
%left TOK_OP_AND %left TOK_OP_AND
%left '|' %left '|'
...@@ -96,17 +104,58 @@ static void yyerror(Context* context, const char* reason); ...@@ -96,17 +104,58 @@ static void yyerror(Context* context, const char* reason);
input input
: expression { : expression {
*(context->result) = static_cast<int>($1); *(context->result) = static_cast<int>($1);
YYACCEPT;
} }
; ;
expression expression
: TOK_CONST_INT : TOK_CONST_INT
| expression TOK_OP_OR expression { | TOK_IDENTIFIER {
$$ = $1 || $3; if (!context->isIgnoringErrors())
{
YYABORT;
}
} }
| expression TOK_OP_AND expression { | expression TOK_OP_OR {
$$ = $1 && $3; if ($1 != 0)
{
// Ignore errors in the short-circuited part of the expression.
// ESSL3.00 section 3.4:
// If an operand is not evaluated, the presence of undefined identifiers
// in the operand will not cause an error.
// Unevaluated division by zero should not cause an error either.
context->startIgnoreErrors();
}
} expression {
if ($1 != 0)
{
context->endIgnoreErrors();
$$ = static_cast<YYSTYPE>(1);
}
else
{
$$ = $1 || $4;
}
}
| expression TOK_OP_AND {
if ($1 == 0)
{
// Ignore errors in the short-circuited part of the expression.
// ESSL3.00 section 3.4:
// If an operand is not evaluated, the presence of undefined identifiers
// in the operand will not cause an error.
// Unevaluated division by zero should not cause an error either.
context->startIgnoreErrors();
}
} expression {
if ($1 == 0)
{
context->endIgnoreErrors();
$$ = static_cast<YYSTYPE>(0);
}
else
{
$$ = $1 && $4;
}
} }
| expression '|' expression { | expression '|' expression {
$$ = $1 | $3; $$ = $1 | $3;
...@@ -148,28 +197,48 @@ expression ...@@ -148,28 +197,48 @@ expression
$$ = $1 + $3; $$ = $1 + $3;
} }
| expression '%' expression { | expression '%' expression {
if ($3 == 0) { if ($3 == 0)
std::ostringstream stream; {
stream << $1 << " % " << $3; if (context->isIgnoringErrors())
std::string text = stream.str(); {
context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO, $$ = static_cast<YYSTYPE>(0);
context->token->location, }
text.c_str()); else
YYABORT; {
} else { std::ostringstream stream;
stream << $1 << " % " << $3;
std::string text = stream.str();
context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
context->token->location,
text.c_str());
YYABORT;
}
}
else
{
$$ = $1 % $3; $$ = $1 % $3;
} }
} }
| expression '/' expression { | expression '/' expression {
if ($3 == 0) { if ($3 == 0)
std::ostringstream stream; {
stream << $1 << " / " << $3; if (context->isIgnoringErrors())
std::string text = stream.str(); {
context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO, $$ = static_cast<YYSTYPE>(0);
context->token->location, }
text.c_str()); else
YYABORT; {
} else { std::ostringstream stream;
stream << $1 << " / " << $3;
std::string text = stream.str();
context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
context->token->location,
text.c_str());
YYABORT;
}
}
else
{
$$ = $1 / $3; $$ = $1 / $3;
} }
} }
...@@ -213,6 +282,15 @@ int yylex(YYSTYPE *lvalp, Context *context) ...@@ -213,6 +282,15 @@ int yylex(YYSTYPE *lvalp, Context *context)
type = TOK_CONST_INT; type = TOK_CONST_INT;
break; break;
} }
case pp::Token::IDENTIFIER:
if (!context->isIgnoringErrors())
{
context->diagnostics->report(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
token->location, token->text);
}
*lvalp = static_cast<YYSTYPE>(-1);
type = TOK_IDENTIFIER;
break;
case pp::Token::OP_OR: case pp::Token::OP_OR:
type = TOK_OP_OR; type = TOK_OP_OR;
break; break;
...@@ -287,6 +365,7 @@ bool ExpressionParser::parse(Token *token, int *result) ...@@ -287,6 +365,7 @@ bool ExpressionParser::parse(Token *token, int *result)
context.lexer = mLexer; context.lexer = mLexer;
context.token = token; context.token = token;
context.result = result; context.result = result;
context.ignoreErrors = 0;
int ret = yyparse(&context); int ret = yyparse(&context);
switch (ret) switch (ret)
{ {
......
...@@ -697,10 +697,6 @@ TEST_F(IfTest, UndefinedMacro) ...@@ -697,10 +697,6 @@ TEST_F(IfTest, UndefinedMacro)
ASSERT_TRUE(mPreprocessor.init(1, &str, 0)); ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
EXPECT_CALL(mDiagnostics, EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::PP_INVALID_EXPRESSION,
pp::SourceLocation(0, 1),
"syntax error"));
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, print(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
pp::SourceLocation(0, 1), pp::SourceLocation(0, 1),
"UNDEFINED")); "UNDEFINED"));
...@@ -833,3 +829,65 @@ TEST_F(IfTest, UnterminatedIfdef) ...@@ -833,3 +829,65 @@ TEST_F(IfTest, UnterminatedIfdef)
mPreprocessor.lex(&token); mPreprocessor.lex(&token);
} }
// The preprocessor only allows one expression to follow an #if directive.
// Supplying two integer expressions should be an error.
TEST_F(IfTest, ExtraIntExpression)
{
const char *str =
"#if 1 1\n"
"#endif\n";
ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_INVALID_EXPRESSION,
pp::SourceLocation(0, 1), "syntax error"));
pp::Token token;
mPreprocessor.lex(&token);
}
// The preprocessor only allows one expression to follow an #if directive.
// Supplying two expressions where one uses a preprocessor define should be an error.
TEST_F(IfTest, ExtraIdentifierExpression)
{
const char *str =
"#define one 1\n"
"#if 1 one\n"
"#endif\n";
ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_INVALID_EXPRESSION,
pp::SourceLocation(0, 2), "syntax error"));
pp::Token token;
mPreprocessor.lex(&token);
}
// Divide by zero that's not evaluated because of short-circuiting should not cause an error.
TEST_F(IfTest, ShortCircuitedDivideByZero)
{
const char *str =
"#if 1 || (2 / 0)\n"
"pass\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n";
preprocess(str, expected);
}
// Undefined identifier that's not evaluated because of short-circuiting should not cause an error.
TEST_F(IfTest, ShortCircuitedUndefined)
{
const char *str =
"#if 1 || UNDEFINED\n"
"pass\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n";
preprocess(str, expected);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment