glsl: Rework reserved word/keyword handling in the lexer.
[mesa.git] / src / glsl / glsl_lexer.lpp
index 9fd9b53c5c62b0847e5519ca46d438b97be5769b..8498b7e60f76d2c74a756e227c6b0938a07afdb9 100644 (file)
 
 #define YY_USER_INIT yylineno = 0; yycolumn = 0;
 
-#define TOKEN_OR_IDENTIFIER(version, token)                     \
-   do {                                                                 \
-      if (yyextra->language_version >= version) {               \
-        return token;                                           \
-      } else {                                                  \
-        yylval->identifier = strdup(yytext);                    \
-        return IDENTIFIER;                                      \
-      }                                                                 \
+/* A macro for handling reserved words and keywords across language versions.
+ *
+ * Certain words start out as identifiers, become reserved words in
+ * later language revisions, and finally become language keywords.
+ *
+ * For example, consider the following lexer rule:
+ * samplerBuffer       KEYWORD(130, 140, SAMPLERBUFFER)
+ *
+ * This means that "samplerBuffer" will be treated as:
+ * - a keyword (SAMPLERBUFFER token)         ...in GLSL >= 1.40
+ * - a reserved word - error                 ...in GLSL >= 1.30
+ * - an identifier                           ...in GLSL <  1.30
+ */
+#define KEYWORD(reserved_version, allowed_version, token)              \
+   do {                                                                        \
+      if (yyextra->language_version >= allowed_version) {              \
+        return token;                                                  \
+      } else if (yyextra->language_version >= reserved_version) {      \
+        _mesa_glsl_error(yylloc, yyextra,                              \
+                         "Illegal use of reserved word `%s'", yytext); \
+        return ERROR_TOK;                                              \
+      } else {                                                         \
+        yylval->identifier = strdup(yytext);                           \
+        return IDENTIFIER;                                             \
+      }                                                                        \
    } while (0)
 
+/* The ES macro can be used in KEYWORD checks:
+ *
+ *    word      KEYWORD(110 || ES, 400, TOKEN)
+ * ...means the word is reserved in GLSL ES 1.00, while
+ *
+ *    word      KEYWORD(110, 130 || ES, TOKEN)
+ * ...means the word is a legal keyword in GLSL ES 1.00.
+ */
+#define ES yyextra->es_shader
 %}
 
 %option bison-bridge bison-locations reentrant noyywrap
@@ -54,7 +80,7 @@
 %option prefix="_mesa_glsl_"
 %option extra-type="struct _mesa_glsl_parse_state *"
 
-%x PP
+%x PP PRAGMA
 
 DEC_INT                [1-9][0-9]*
 HEX_INT                0[xX][0-9a-fA-F]+
@@ -100,7 +126,27 @@ HASH               ^{SPC}#{SPC}
                                    */
                                   yylineno = strtol(ptr, &ptr, 0) - 1;
                                }
-^[ \t]*#[ \t]*pragma           { BEGIN PP; return PRAGMA; }
+^{SPC}#{SPC}pragma{SPCP}debug{SPC}\({SPC}on{SPC}\) {
+                                 BEGIN PP;
+                                 return PRAGMA_DEBUG_ON;
+                               }
+^{SPC}#{SPC}pragma{SPCP}debug{SPC}\({SPC}off{SPC}\) {
+                                 BEGIN PP;
+                                 return PRAGMA_DEBUG_OFF;
+                               }
+^{SPC}#{SPC}pragma{SPCP}optimize{SPC}\({SPC}on{SPC}\) {
+                                 BEGIN PP;
+                                 return PRAGMA_OPTIMIZE_ON;
+                               }
+^{SPC}#{SPC}pragma{SPCP}optimize{SPC}\({SPC}off{SPC}\) {
+                                 BEGIN PP;
+                                 return PRAGMA_OPTIMIZE_OFF;
+                               }
+^{SPC}#{SPC}pragma{SPCP}       { BEGIN PRAGMA; }
+
+<PRAGMA>\n                     { BEGIN 0; yylineno++; yycolumn = 0; }
+<PRAGMA>.                      { }
+
 <PP>\/\/[^\n]*                 { }
 <PP>[ \t\r]*                   { }
 <PP>:                          return COLON;
@@ -118,9 +164,10 @@ HASH               ^{SPC}#{SPC}
 
 attribute      return ATTRIBUTE;
 const          return CONST_TOK;
-bool           return BOOL;
-float          return FLOAT;
-int            return INT;
+bool           return BOOL_TOK;
+float          return FLOAT_TOK;
+int            return INT_TOK;
+uint           KEYWORD(130, 130, UINT_TOK);
 
 break          return BREAK;
 continue       return CONTINUE;
@@ -138,33 +185,35 @@ bvec4             return BVEC4;
 ivec2          return IVEC2;
 ivec3          return IVEC3;
 ivec4          return IVEC4;
+uvec2          KEYWORD(130, 130, UVEC2);
+uvec3          KEYWORD(130, 130, UVEC3);
+uvec4          KEYWORD(130, 130, UVEC4);
 vec2           return VEC2;
 vec3           return VEC3;
 vec4           return VEC4;
-mat2           return MAT2;
-mat3           return MAT3;
-mat4           return MAT4;
-mat2x2         TOKEN_OR_IDENTIFIER(120, MAT2X2);
-mat2x3         TOKEN_OR_IDENTIFIER(120, MAT2X3);
-mat2x4         TOKEN_OR_IDENTIFIER(120, MAT2X4);
-mat3x2         TOKEN_OR_IDENTIFIER(120, MAT3X2);
-mat3x3         TOKEN_OR_IDENTIFIER(120, MAT3X3);
-mat3x4         TOKEN_OR_IDENTIFIER(120, MAT3X4);
-mat4x2         TOKEN_OR_IDENTIFIER(120, MAT4X2);
-mat4x3         TOKEN_OR_IDENTIFIER(120, MAT4X3);
-mat4x4         TOKEN_OR_IDENTIFIER(120, MAT4X4);
-
-in             return IN;
-out            return OUT;
-inout          return INOUT;
+mat2           return MAT2X2;
+mat3           return MAT3X3;
+mat4           return MAT4X4;
+mat2x2         KEYWORD(120, 120, MAT2X2);
+mat2x3         KEYWORD(120, 120, MAT2X3);
+mat2x4         KEYWORD(120, 120, MAT2X4);
+mat3x2         KEYWORD(120, 120, MAT3X2);
+mat3x3         KEYWORD(120, 120, MAT3X3);
+mat3x4         KEYWORD(120, 120, MAT3X4);
+mat4x2         KEYWORD(120, 120, MAT4X2);
+mat4x3         KEYWORD(120, 120, MAT4X3);
+mat4x4         KEYWORD(120, 120, MAT4X4);
+
+in             return IN_TOK;
+out            return OUT_TOK;
+inout          return INOUT_TOK;
 uniform                return UNIFORM;
 varying                return VARYING;
-centroid       TOKEN_OR_IDENTIFIER(120, CENTROID);
-invariant      TOKEN_OR_IDENTIFIER(120, INVARIANT);
-
-flat           TOKEN_OR_IDENTIFIER(130, FLAT);
-smooth         TOKEN_OR_IDENTIFIER(130, SMOOTH);
-noperspective  TOKEN_OR_IDENTIFIER(130, NOPERSPECTIVE);
+centroid       KEYWORD(120, 120, CENTROID);
+invariant      KEYWORD(120 || ES, 120 || ES, INVARIANT);
+flat           KEYWORD(130 || ES, 130, FLAT);
+smooth         KEYWORD(130, 130, SMOOTH);
+noperspective  KEYWORD(130, 130, NOPERSPECTIVE);
 
 sampler1D      return SAMPLER1D;
 sampler2D      return SAMPLER2D;
@@ -174,10 +223,11 @@ sampler1DShadow   return SAMPLER1DSHADOW;
 sampler2DShadow        return SAMPLER2DSHADOW;
 
 struct         return STRUCT;
-void           return VOID;
+void           return VOID_TOK;
 
 layout         {
                  if ((yyextra->language_version >= 140)
+                     || yyextra->ARB_explicit_attrib_location_enable
                      || (yyextra->ARB_fragment_coord_conventions_enable)){
                      return LAYOUT_TOK;
                   } else {
@@ -195,6 +245,8 @@ layout              {
 &&             return AND_OP;
 \|\|           return OR_OP;
 "^^"           return XOR_OP;
+"<<"           return LEFT_OP;
+">>"           return RIGHT_OP;
 
 \*=            return MUL_ASSIGN;
 \/=            return DIV_ASSIGN;
@@ -203,7 +255,7 @@ layout              {
 \<\<=          return LEFT_ASSIGN;
 >>=            return RIGHT_ASSIGN;
 &=             return AND_ASSIGN;
-^=             return XOR_ASSIGN;
+"^="           return XOR_ASSIGN;
 \|=            return OR_ASSIGN;
 -=             return SUB_ASSIGN;
 
@@ -252,55 +304,87 @@ false                     {
 
 
     /* Reserved words in GLSL 1.10. */
-asm            return ASM;
-class          return CLASS;
-union          return UNION;
-enum           return ENUM;
-typedef                return TYPEDEF;
-template       return TEMPLATE;
-this           return THIS;
-packed         return PACKED;
-goto           return GOTO;
-switch         return SWITCH;
-default                return DEFAULT;
-inline         return INLINE_TOK;
-noinline       return NOINLINE;
-volatile       return VOLATILE;
-public         return PUBLIC_TOK;
-static         return STATIC;
-extern         return EXTERN;
-external       return EXTERNAL;
-interface      return INTERFACE;
-long           return LONG;
-short          return SHORT;
-double         return DOUBLE;
-half           return HALF;
-fixed          return FIXED;
-unsigned       return UNSIGNED;
-input          return INPUT;
-output         return OUTPUT;
-hvec2          return HVEC2;
-hvec3          return HVEC3;
-hvec4          return HVEC4;
-dvec2          return DVEC2;
-dvec3          return DVEC3;
-dvec4          return DVEC4;
-fvec2          return FVEC2;
-fvec3          return FVEC3;
-fvec4          return FVEC4;
+asm            KEYWORD(110 || ES, 999, ASM);
+class          KEYWORD(110 || ES, 999, CLASS);
+union          KEYWORD(110 || ES, 999, UNION);
+enum           KEYWORD(110 || ES, 999, ENUM);
+typedef                KEYWORD(110 || ES, 999, TYPEDEF);
+template       KEYWORD(110 || ES, 999, TEMPLATE);
+this           KEYWORD(110 || ES, 999, THIS);
+packed         KEYWORD(110 || ES, 999, PACKED_TOK);
+goto           KEYWORD(110 || ES, 999, GOTO);
+switch         KEYWORD(110 || ES, 130, SWITCH);
+default                KEYWORD(110 || ES, 130, DEFAULT);
+inline         KEYWORD(110 || ES, 999, INLINE_TOK);
+noinline       KEYWORD(110 || ES, 999, NOINLINE);
+volatile       KEYWORD(110 || ES, 999, VOLATILE);
+public         KEYWORD(110 || ES, 999, PUBLIC_TOK);
+static         KEYWORD(110 || ES, 999, STATIC);
+extern         KEYWORD(110 || ES, 999, EXTERN);
+external       KEYWORD(110 || ES, 999, EXTERNAL);
+interface      KEYWORD(110 || ES, 999, INTERFACE);
+long           KEYWORD(110 || ES, 999, LONG_TOK);
+short          KEYWORD(110 || ES, 999, SHORT_TOK);
+double         KEYWORD(110 || ES, 400, DOUBLE_TOK);
+half           KEYWORD(110 || ES, 999, HALF);
+fixed          KEYWORD(110 || ES, 999, FIXED_TOK);
+unsigned       KEYWORD(110 || ES, 999, UNSIGNED);
+input          KEYWORD(110 || ES, 999, INPUT_TOK);
+output         KEYWORD(110 || ES, 999, OUTPUT);
+hvec2          KEYWORD(110 || ES, 999, HVEC2);
+hvec3          KEYWORD(110 || ES, 999, HVEC3);
+hvec4          KEYWORD(110 || ES, 999, HVEC4);
+dvec2          KEYWORD(110 || ES, 400, DVEC2);
+dvec3          KEYWORD(110 || ES, 400, DVEC3);
+dvec4          KEYWORD(110 || ES, 400, DVEC4);
+fvec2          KEYWORD(110 || ES, 999, FVEC2);
+fvec3          KEYWORD(110 || ES, 999, FVEC3);
+fvec4          KEYWORD(110 || ES, 999, FVEC4);
 sampler2DRect          return SAMPLER2DRECT;
-sampler3DRect          return SAMPLER3DRECT;
+sampler3DRect          KEYWORD(110 || ES, 999, SAMPLER3DRECT);
 sampler2DRectShadow    return SAMPLER2DRECTSHADOW;
-sizeof         return SIZEOF;
-cast           return CAST;
-namespace      return NAMESPACE;
-using          return USING;
+sizeof         KEYWORD(110 || ES, 999, SIZEOF);
+cast           KEYWORD(110 || ES, 999, CAST);
+namespace      KEYWORD(110 || ES, 999, NAMESPACE);
+using          KEYWORD(110 || ES, 999, USING);
 
     /* Additional reserved words in GLSL 1.20. */
-lowp           TOKEN_OR_IDENTIFIER(120, LOWP);
-mediump                TOKEN_OR_IDENTIFIER(120, MEDIUMP);
-highp          TOKEN_OR_IDENTIFIER(120, HIGHP);
-precision      TOKEN_OR_IDENTIFIER(120, PRECISION);
+lowp           KEYWORD(120, 130 || ES, LOWP);
+mediump                KEYWORD(120, 130 || ES, MEDIUMP);
+highp          KEYWORD(120, 130 || ES, HIGHP);
+precision      KEYWORD(120, 130 || ES, PRECISION);
+
+    /* Additional reserved words in GLSL 1.30. */
+common         KEYWORD(130, 999, COMMON);
+partition      KEYWORD(130, 999, PARTITION);
+active         KEYWORD(130, 999, ACTIVE);
+superp         KEYWORD(130 || ES, 999, SUPERP);
+samplerBuffer  KEYWORD(130, 140, SAMPLERBUFFER);
+filter         KEYWORD(130, 999, FILTER);
+image1D                KEYWORD(130, 999, IMAGE1D);
+image2D                KEYWORD(130, 999, IMAGE2D);
+image3D                KEYWORD(130, 999, IMAGE3D);
+imageCube      KEYWORD(130, 999, IMAGECUBE);
+iimage1D       KEYWORD(130, 999, IIMAGE1D);
+iimage2D       KEYWORD(130, 999, IIMAGE2D);
+iimage3D       KEYWORD(130, 999, IIMAGE3D);
+iimageCube     KEYWORD(130, 999, IIMAGECUBE);
+uimage1D       KEYWORD(130, 999, UIMAGE1D);
+uimage2D       KEYWORD(130, 999, UIMAGE2D);
+uimage3D       KEYWORD(130, 999, UIMAGE3D);
+uimageCube     KEYWORD(130, 999, UIMAGECUBE);
+image1DArray   KEYWORD(130, 999, IMAGE1DARRAY);
+image2DArray   KEYWORD(130, 999, IMAGE2DARRAY);
+iimage1DArray  KEYWORD(130, 999, IIMAGE1DARRAY);
+iimage2DArray  KEYWORD(130, 999, IIMAGE2DARRAY);
+uimage1DArray  KEYWORD(130, 999, UIMAGE1DARRAY);
+uimage2DArray  KEYWORD(130, 999, UIMAGE2DARRAY);
+image1DShadow  KEYWORD(130, 999, IMAGE1DSHADOW);
+image2DShadow  KEYWORD(130, 999, IMAGE2DSHADOW);
+imageBuffer    KEYWORD(130, 999, IMAGEBUFFER);
+iimageBuffer   KEYWORD(130, 999, IIMAGEBUFFER);
+uimageBuffer   KEYWORD(130, 999, UIMAGEBUFFER);
+row_major      KEYWORD(130, 999, ROW_MAJOR);
 
 [_a-zA-Z][_a-zA-Z0-9]* {
                            struct _mesa_glsl_parse_state *state = yyextra;