- Moved the implementation for ShCompile to the compiler class so that internal details about compiler can be encapsulated. Now we do not need to expose built-in symbol table.
- Fixed a few const violations.
- Added CollectAttribsUniforms class.
BUG=26
Review URL: http://codereview.appspot.com/2263041

git-svn-id: https://angleproject.googlecode.com/svn/trunk@437 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/compiler/Compiler.cpp b/src/compiler/Compiler.cpp
new file mode 100644
index 0000000..6008f96
--- /dev/null
+++ b/src/compiler/Compiler.cpp
@@ -0,0 +1,158 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/Initialize.h"
+#include "compiler/ParseHelper.h"
+#include "compiler/ShHandle.h"
+
+static bool InitializeSymbolTable(
+        const TBuiltInStrings& builtInStrings,
+        EShLanguage language, EShSpec spec, const TBuiltInResource& resources,
+        TInfoSink& infoSink, TSymbolTable& symbolTable)
+{
+    TIntermediate intermediate(infoSink);
+    TExtensionBehavior extBehavior;
+    TParseContext parseContext(symbolTable, extBehavior, intermediate, language, spec, infoSink);
+
+    GlobalParseContext = &parseContext;
+
+    setInitialState();
+
+    assert(symbolTable.isEmpty());       
+    //
+    // Parse the built-ins.  This should only happen once per
+    // language symbol table.
+    //
+    // Push the symbol table to give it an initial scope.  This
+    // push should not have a corresponding pop, so that built-ins
+    // are preserved, and the test for an empty table fails.
+    //
+    symbolTable.push();
+    
+    //Initialize the Preprocessor
+    if (InitPreprocessor())
+    {
+        infoSink.info.message(EPrefixInternalError,  "Unable to intialize the Preprocessor");
+        return false;
+    }
+
+    for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i)
+    {
+        const char* builtInShaders[1];
+        int builtInLengths[1];
+
+        builtInShaders[0] = (*i).c_str();
+        builtInLengths[0] = (int) (*i).size();
+
+        if (PaParseStrings(builtInShaders, builtInLengths, 1, parseContext) != 0)
+        {
+            infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
+            return false;
+        }
+    }
+
+    IdentifyBuiltIns(language, spec, resources, symbolTable);
+
+    FinalizePreprocessor();
+
+    return true;
+}
+
+static void DefineExtensionMacros(const TExtensionBehavior& extBehavior)
+{
+    for (TExtensionBehavior::const_iterator iter = extBehavior.begin();
+         iter != extBehavior.end(); ++iter) {
+        PredefineIntMacro(iter->first.c_str(), 1);
+    }
+}
+
+bool TCompiler::Init(const TBuiltInResource& resources)
+{
+    // Generate built-in symbol table.
+    if (!InitBuiltInSymbolTable(resources))
+        return false;
+
+    InitExtensionBehavior(resources, extensionBehavior);
+    return true;
+}
+
+bool TCompiler::compile(const char* const shaderStrings[],
+                        const int numStrings,
+                        int compileOptions)
+{
+    clearResults();
+
+    if (numStrings == 0)
+        return true;
+
+    TIntermediate intermediate(infoSink);
+    TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
+                               language, spec, infoSink);
+    GlobalParseContext = &parseContext;
+    setInitialState();
+
+    // Initialize preprocessor.
+    InitPreprocessor();
+    DefineExtensionMacros(extensionBehavior);
+
+    // We preserve symbols at the built-in level from compile-to-compile.
+    // Start pushing the user-defined symbols at global level.
+    symbolTable.push();
+    if (!symbolTable.atGlobalLevel())
+        infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
+
+    // Parse shader.
+    bool success =
+        (PaParseStrings(shaderStrings, 0, numStrings, parseContext) == 0) &&
+        (parseContext.treeRoot != NULL);
+    if (success) {
+        success = intermediate.postProcess(parseContext.treeRoot);
+
+        if (success && (compileOptions & EShOptIntermediateTree))
+            intermediate.outputTree(parseContext.treeRoot);
+
+        if (success && (compileOptions & EShOptObjectCode))
+            translate(parseContext.treeRoot);
+
+        if (success && (compileOptions & EShOptAttribsUniforms))
+            collectAttribsUniforms(parseContext.treeRoot);
+    }
+
+    // Cleanup memory.
+    intermediate.remove(parseContext.treeRoot);
+    // Ensure symbol table is returned to the built-in level,
+    // throwing away all but the built-ins.
+    while (!symbolTable.atBuiltInLevel())
+        symbolTable.pop();
+    FinalizePreprocessor();
+
+    return success;
+}
+
+bool TCompiler::InitBuiltInSymbolTable(const TBuiltInResource& resources)
+{
+    TBuiltIns builtIns;
+
+    builtIns.initialize(language, spec, resources);
+    return InitializeSymbolTable(builtIns.getBuiltInStrings(), language, spec, resources, infoSink, symbolTable);
+}
+
+void TCompiler::clearResults()
+{
+    infoSink.info.erase();
+    infoSink.obj.erase();
+    infoSink.debug.erase();
+
+    attribs.clear();
+    uniforms.clear();
+}
+
+void TCompiler::collectAttribsUniforms(TIntermNode* root)
+{
+    CollectAttribsUniforms collect(attribs, uniforms);
+    root->traverse(&collect);
+}
+