OSDN Git Service

Support parsing defined operator generated by macro expansion
authorNicolas Capens <capn@google.com>
Fri, 22 Apr 2016 15:00:31 +0000 (11:00 -0400)
committerNicolas Capens <capn@google.com>
Fri, 22 Apr 2016 19:04:02 +0000 (19:04 +0000)
dEQP tests enforce that the defined operator should be parsed even when
it is generated as a result of macro expansion, even though this is
undefined according to the C++ preprocessor spec.

Implement support for this by putting the parsing for the defined
operator inside MacroExpander. The operator gets processed right after
it is generated by macro expansion. Parsing the defined operator is
toggled with a boolean according to the context where MacroExpander
is used.

Change-Id: I8557e829f4278ab6cb27eb4a0f84ca0c0dd18d1a
Reviewed-on: https://swiftshader-review.googlesource.com/5182
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
Tested-by: Nicolas Capens <capn@google.com>
src/OpenGL/compiler/preprocessor/DirectiveParser.cpp
src/OpenGL/compiler/preprocessor/MacroExpander.cpp
src/OpenGL/compiler/preprocessor/MacroExpander.h
src/OpenGL/compiler/preprocessor/Preprocessor.cpp

index cf759b1..8e6dcbd 100644 (file)
@@ -139,71 +139,6 @@ static bool isMacroPredefined(const std::string& name,
 namespace pp\r
 {\r
 \r
-class DefinedParser : public Lexer\r
-{\r
-  public:\r
-    DefinedParser(Lexer* lexer,\r
-                  const MacroSet* macroSet,\r
-                  Diagnostics* diagnostics) :\r
-        mLexer(lexer),\r
-        mMacroSet(macroSet),\r
-        mDiagnostics(diagnostics)\r
-    {\r
-    }\r
-\r
-  protected:\r
-    virtual void lex(Token* token)\r
-    {\r
-        static const std::string kDefined("defined");\r
-\r
-        mLexer->lex(token);\r
-        if (token->type != Token::IDENTIFIER)\r
-            return;\r
-        if (token->text != kDefined)\r
-            return;\r
-\r
-        bool paren = false;\r
-        mLexer->lex(token);\r
-        if (token->type == '(')\r
-        {\r
-            paren = true;\r
-            mLexer->lex(token);\r
-        }\r
-\r
-        if (token->type != Token::IDENTIFIER)\r
-        {\r
-            mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,\r
-                                 token->location, token->text);\r
-            skipUntilEOD(mLexer, token);\r
-            return;\r
-        }\r
-        MacroSet::const_iterator iter = mMacroSet->find(token->text);\r
-        std::string expression = iter != mMacroSet->end() ? "1" : "0";\r
-\r
-        if (paren)\r
-        {\r
-            mLexer->lex(token);\r
-            if (token->type != ')')\r
-            {\r
-                mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,\r
-                                     token->location, token->text);\r
-                skipUntilEOD(mLexer, token);\r
-                return;\r
-            }\r
-        }\r
-\r
-        // We have a valid defined operator.\r
-        // Convert the current token into a CONST_INT token.\r
-        token->type = Token::CONST_INT;\r
-        token->text = expression;\r
-    }\r
-\r
-  private:\r
-    Lexer* mLexer;\r
-    const MacroSet* mMacroSet;\r
-    Diagnostics* mDiagnostics;\r
-};\r
-\r
 DirectiveParser::DirectiveParser(Tokenizer* tokenizer,\r
                                  MacroSet* macroSet,\r
                                  Diagnostics* diagnostics,\r
@@ -794,7 +729,7 @@ void DirectiveParser::parseLine(Token* token)
     int line = 0, file = 0;\r
     int state = LINE_NUMBER;\r
 \r
-    MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);\r
+    MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, false);\r
     macroExpander.lex(token);\r
     while ((token->type != '\n') && (token->type != Token::LAST))\r
     {\r
@@ -907,8 +842,7 @@ int DirectiveParser::parseExpressionIf(Token* token)
     assert((getDirective(token) == DIRECTIVE_IF) ||\r
            (getDirective(token) == DIRECTIVE_ELIF));\r
 \r
-    DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);\r
-    MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);\r
+    MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, true);\r
     ExpressionParser expressionParser(&macroExpander, mDiagnostics);\r
 \r
     int expression = 0;\r
index d8bbe8b..325daba 100644 (file)
@@ -48,10 +48,9 @@ class TokenLexer : public Lexer
 \r
 MacroExpander::MacroExpander(Lexer* lexer,\r
                              MacroSet* macroSet,\r
-                             Diagnostics* diagnostics) :\r
-    mLexer(lexer),\r
-    mMacroSet(macroSet),\r
-    mDiagnostics(diagnostics)\r
+                             Diagnostics* diagnostics,\r
+                             bool parseDefined) :\r
+    mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics), mParseDefined(parseDefined)\r
 {\r
 }\r
 \r
@@ -72,6 +71,47 @@ void MacroExpander::lex(Token* token)
         if (token->type != Token::IDENTIFIER)\r
             break;\r
 \r
+               // Defined operator is parsed here since it may be generated by macro expansion.\r
+        // Defined operator produced by macro expansion has undefined behavior according to C++\r
+        // spec, which the GLSL spec references (see C++14 draft spec section 16.1.4), but this\r
+        // behavior is needed for passing dEQP tests, which enforce stricter compatibility between\r
+        // implementations.\r
+        if (mParseDefined && token->text == "defined")\r
+        {\r
+            bool paren = false;\r
+            getToken(token);\r
+            if (token->type == '(')\r
+            {\r
+                paren = true;\r
+                getToken(token);\r
+            }\r
+            if (token->type != Token::IDENTIFIER)\r
+            {\r
+                mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, token->location,\r
+                                     token->text);\r
+                break;\r
+            }\r
+            auto iter = mMacroSet->find(token->text);\r
+            std::string expression = iter != mMacroSet->end() ? "1" : "0";\r
+\r
+            if (paren)\r
+            {\r
+                getToken(token);\r
+                if (token->type != ')')\r
+                {\r
+                    mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, token->location,\r
+                                         token->text);\r
+                    break;\r
+                }\r
+            }\r
+\r
+            // We have a valid defined operator.\r
+            // Convert the current token into a CONST_INT token.\r
+            token->type = Token::CONST_INT;\r
+            token->text = expression;\r
+            break;\r
+        }\r
+\r
         if (token->expansionDisabled())\r
             break;\r
 \r
@@ -315,7 +355,7 @@ bool MacroExpander::collectMacroArgs(const Macro& macro,
     {\r
         MacroArg& arg = args->at(i);\r
         TokenLexer lexer(&arg);\r
-        MacroExpander expander(&lexer, mMacroSet, mDiagnostics);\r
+        MacroExpander expander(&lexer, mMacroSet, mDiagnostics, mParseDefined);\r
 \r
         arg.clear();\r
         expander.lex(&token);\r
index b10b01f..e1b049a 100644 (file)
@@ -23,7 +23,7 @@ class Diagnostics;
 class MacroExpander : public Lexer\r
 {\r
   public:\r
-    MacroExpander(Lexer* lexer, MacroSet* macroSet, Diagnostics* diagnostics);\r
+    MacroExpander(Lexer* lexer, MacroSet* macroSet, Diagnostics* diagnostics, bool parseDefined);\r
     virtual ~MacroExpander();\r
 \r
     virtual void lex(Token* token);\r
@@ -65,6 +65,7 @@ class MacroExpander : public Lexer
     Lexer* mLexer;\r
     MacroSet* mMacroSet;\r
     Diagnostics* mDiagnostics;\r
+       const bool mParseDefined;\r
 \r
     std::auto_ptr<Token> mReserveToken;\r
     std::vector<MacroContext*> mContextStack;\r
index 296c8aa..675b30b 100644 (file)
@@ -27,12 +27,11 @@ struct PreprocessorImpl
     DirectiveParser directiveParser;\r
     MacroExpander macroExpander;\r
 \r
-    PreprocessorImpl(Diagnostics* diag,\r
-                     DirectiveHandler* directiveHandler) :\r
+    PreprocessorImpl(Diagnostics* diag, DirectiveHandler* directiveHandler) :\r
         diagnostics(diag),\r
         tokenizer(diag),\r
         directiveParser(&tokenizer, &macroSet, diag, directiveHandler),\r
-        macroExpander(&directiveParser, &macroSet, diag)\r
+        macroExpander(&directiveParser, &macroSet, diag, false)\r
     {\r
     }\r
 };\r