Add SwiftShader dump from Feb 6 2013
diff --git a/src/GLES2/compiler/BaseTypes.h b/src/GLES2/compiler/BaseTypes.h new file mode 100644 index 0000000..3334436 --- /dev/null +++ b/src/GLES2/compiler/BaseTypes.h
@@ -0,0 +1,148 @@ +// +// 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. +// + +#ifndef _BASICTYPES_INCLUDED_ +#define _BASICTYPES_INCLUDED_ + +// +// Precision qualifiers +// +enum TPrecision +{ + // These need to be kept sorted + EbpUndefined, + EbpLow, + EbpMedium, + EbpHigh, +}; + +inline const char* getPrecisionString(TPrecision p) +{ + switch(p) + { + case EbpHigh: return "highp"; break; + case EbpMedium: return "mediump"; break; + case EbpLow: return "lowp"; break; + default: return "mediump"; break; // Safest fallback + } +} + +// +// Basic type. Arrays, vectors, etc., are orthogonal to this. +// +enum TBasicType +{ + EbtVoid, + EbtFloat, + EbtInt, + EbtBool, + EbtGuardSamplerBegin, // non type: see implementation of IsSampler() + EbtSampler2D, + EbtSamplerCube, + EbtGuardSamplerEnd, // non type: see implementation of IsSampler() + EbtStruct, + EbtAddress, // should be deprecated?? + EbtInvariant, // used as a type when qualifying a previously declared variable as being invariant +}; + +inline const char* getBasicString(TBasicType t) +{ + switch (t) + { + case EbtVoid: return "void"; break; + case EbtFloat: return "float"; break; + case EbtInt: return "int"; break; + case EbtBool: return "bool"; break; + case EbtSampler2D: return "sampler2D"; break; + case EbtSamplerCube: return "samplerCube"; break; + case EbtStruct: return "structure"; break; + default: return "unknown type"; + } +} + +inline bool IsSampler(TBasicType type) +{ + return type > EbtGuardSamplerBegin && type < EbtGuardSamplerEnd; +} + +// +// Qualifiers and built-ins. These are mainly used to see what can be read +// or written, and by the machine dependent translator to know which registers +// to allocate variables in. Since built-ins tend to go to different registers +// than varying or uniform, it makes sense they are peers, not sub-classes. +// +enum TQualifier +{ + EvqTemporary, // For temporaries (within a function), read/write + EvqGlobal, // For globals read/write + EvqConst, // User defined constants and non-output parameters in functions + EvqAttribute, // Readonly + EvqVaryingIn, // readonly, fragment shaders only + EvqVaryingOut, // vertex shaders only read/write + EvqInvariantVaryingIn, // readonly, fragment shaders only + EvqInvariantVaryingOut, // vertex shaders only read/write + EvqUniform, // Readonly, vertex and fragment + + // pack/unpack input and output + EvqInput, + EvqOutput, + + // parameters + EvqIn, + EvqOut, + EvqInOut, + EvqConstReadOnly, + + // built-ins written by vertex shader + EvqPosition, + EvqPointSize, + + // built-ins read by fragment shader + EvqFragCoord, + EvqFrontFacing, + EvqPointCoord, + + // built-ins written by fragment shader + EvqFragColor, + EvqFragData, + + // end of list + EvqLast, +}; + +// +// This is just for debug print out, carried along with the definitions above. +// +inline const char* getQualifierString(TQualifier q) +{ + switch(q) + { + case EvqTemporary: return "Temporary"; break; + case EvqGlobal: return "Global"; break; + case EvqConst: return "const"; break; + case EvqConstReadOnly: return "const"; break; + case EvqAttribute: return "attribute"; break; + case EvqVaryingIn: return "varying"; break; + case EvqVaryingOut: return "varying"; break; + case EvqInvariantVaryingIn: return "invariant varying"; break; + case EvqInvariantVaryingOut:return "invariant varying"; break; + case EvqUniform: return "uniform"; break; + case EvqIn: return "in"; break; + case EvqOut: return "out"; break; + case EvqInOut: return "inout"; break; + case EvqInput: return "input"; break; + case EvqOutput: return "output"; break; + case EvqPosition: return "Position"; break; + case EvqPointSize: return "PointSize"; break; + case EvqFragCoord: return "FragCoord"; break; + case EvqFrontFacing: return "FrontFacing"; break; + case EvqFragColor: return "FragColor"; break; + case EvqFragData: return "FragData"; break; + default: return "unknown qualifier"; + } +} + +#endif // _BASICTYPES_INCLUDED_
diff --git a/src/GLES2/compiler/Common.h b/src/GLES2/compiler/Common.h new file mode 100644 index 0000000..27a5598 --- /dev/null +++ b/src/GLES2/compiler/Common.h
@@ -0,0 +1,89 @@ +// +// 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. +// + +#ifndef _COMMON_INCLUDED_ +#define _COMMON_INCLUDED_ + +#include <map> +#include <sstream> +#include <string> +#include <vector> + +#include "compiler/PoolAlloc.h" + +// We need two pieces of information to report errors/warnings - string and +// line number. We encode these into a single int so that it can be easily +// incremented/decremented by lexer. The right SOURCE_LOC_LINE_SIZE bits store +// line number while the rest store the string number. Since the shaders are +// usually small, we should not run out of memory. SOURCE_LOC_LINE_SIZE +// can be increased to alleviate this issue. +typedef int TSourceLoc; +const unsigned int SOURCE_LOC_LINE_SIZE = 16; // in bits. +const unsigned int SOURCE_LOC_LINE_MASK = (1 << SOURCE_LOC_LINE_SIZE) - 1; + +inline TSourceLoc EncodeSourceLoc(int string, int line) { + return (string << SOURCE_LOC_LINE_SIZE) | (line & SOURCE_LOC_LINE_MASK); +} + +inline void DecodeSourceLoc(TSourceLoc loc, int* string, int* line) { + if (string) *string = loc >> SOURCE_LOC_LINE_SIZE; + if (line) *line = loc & SOURCE_LOC_LINE_MASK; +} + +// +// Put POOL_ALLOCATOR_NEW_DELETE in base classes to make them use this scheme. +// +#define POOL_ALLOCATOR_NEW_DELETE(A) \ + void* operator new(size_t s) { return (A).allocate(s); } \ + void* operator new(size_t, void *_Where) { return (_Where); } \ + void operator delete(void*) { } \ + void operator delete(void *, void *) { } \ + void* operator new[](size_t s) { return (A).allocate(s); } \ + void* operator new[](size_t, void *_Where) { return (_Where); } \ + void operator delete[](void*) { } \ + void operator delete[](void *, void *) { } + +// +// Pool version of string. +// +typedef pool_allocator<char> TStringAllocator; +typedef std::basic_string <char, std::char_traits<char>, TStringAllocator> TString; +typedef std::basic_ostringstream<char, std::char_traits<char>, TStringAllocator> TStringStream; +inline TString* NewPoolTString(const char* s) +{ + void* memory = GlobalPoolAllocator.allocate(sizeof(TString)); + return new(memory) TString(s); +} + +// +// Persistent string memory. Should only be used for strings that survive +// across compiles. +// +#define TPersistString std::string +#define TPersistStringStream std::ostringstream + +// +// Pool allocator versions of vectors, lists, and maps +// +template <class T> class TVector : public std::vector<T, pool_allocator<T> > { +public: + typedef typename std::vector<T, pool_allocator<T> >::size_type size_type; + TVector() : std::vector<T, pool_allocator<T> >() {} + TVector(const pool_allocator<T>& a) : std::vector<T, pool_allocator<T> >(a) {} + TVector(size_type i): std::vector<T, pool_allocator<T> >(i) {} +}; + +template <class K, class D, class CMP = std::less<K> > +class TMap : public std::map<K, D, CMP, pool_allocator<std::pair<const K, D> > > { +public: + typedef pool_allocator<std::pair<const K, D> > tAllocator; + + TMap() : std::map<K, D, CMP, tAllocator>() {} + // use correct two-stage name lookup supported in gcc 3.4 and above + TMap(const tAllocator& a) : std::map<K, D, CMP, tAllocator>(std::map<K, D, CMP, tAllocator>::key_compare(), a) {} +}; + +#endif // _COMMON_INCLUDED_
diff --git a/src/GLES2/compiler/Compiler.cpp b/src/GLES2/compiler/Compiler.cpp new file mode 100644 index 0000000..59e8ffe --- /dev/null +++ b/src/GLES2/compiler/Compiler.cpp
@@ -0,0 +1,231 @@ +// +// Copyright (c) 2002-2012 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/DetectRecursion.h" +#include "compiler/Initialize.h" +#include "compiler/InitializeParseContext.h" +#include "compiler/ParseHelper.h" +#include "compiler/ShHandle.h" +#include "compiler/ValidateLimitations.h" + +namespace { +bool InitializeSymbolTable( + const TBuiltInStrings& builtInStrings, + ShShaderType type, ShShaderSpec spec, const ShBuiltInResources& resources, + TInfoSink& infoSink, TSymbolTable& symbolTable) +{ + TIntermediate intermediate(infoSink); + TExtensionBehavior extBehavior; + InitExtensionBehavior(resources, extBehavior); + // The builtins deliberately don't specify precisions for the function + // arguments and return types. For that reason we don't try to check them. + TParseContext parseContext(symbolTable, extBehavior, intermediate, type, spec, 0, false, NULL, infoSink); + + GlobalParseContext = &parseContext; + + 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(); + + for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i) + { + const char* builtInShaders = i->c_str(); + int builtInLengths = static_cast<int>(i->size()); + if (builtInLengths <= 0) + continue; + + if (PaParseStrings(1, &builtInShaders, &builtInLengths, &parseContext) != 0) + { + infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins"); + return false; + } + } + + IdentifyBuiltIns(type, spec, resources, symbolTable); + + return true; +} + +class TScopedPoolAllocator { +public: + TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop) + : mAllocator(allocator), mPushPopAllocator(pushPop) { + if (mPushPopAllocator) mAllocator->push(); + SetGlobalPoolAllocator(mAllocator); + } + ~TScopedPoolAllocator() { + SetGlobalPoolAllocator(NULL); + if (mPushPopAllocator) mAllocator->pop(); + } + +private: + TPoolAllocator* mAllocator; + bool mPushPopAllocator; +}; +} // namespace + +TShHandleBase::TShHandleBase() { + allocator.push(); + SetGlobalPoolAllocator(&allocator); +} + +TShHandleBase::~TShHandleBase() { + SetGlobalPoolAllocator(NULL); + allocator.popAll(); +} + +TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec) + : shaderType(type), + shaderSpec(spec) +{ +} + +TCompiler::~TCompiler() +{ +} + +bool TCompiler::Init(const ShBuiltInResources& resources) +{ + TScopedPoolAllocator scopedAlloc(&allocator, false); + + // 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) +{ + TScopedPoolAllocator scopedAlloc(&allocator, true); + clearResults(); + + if (numStrings == 0) + return true; + + // If compiling for WebGL, validate loop and indexing as well. + if (shaderSpec == SH_WEBGL_SPEC) + compileOptions |= SH_VALIDATE_LOOP_INDEXING; + + // First string is path of source file if flag is set. The actual source follows. + const char* sourcePath = NULL; + int firstSource = 0; + if (compileOptions & SH_SOURCE_PATH) + { + sourcePath = shaderStrings[0]; + ++firstSource; + } + + TIntermediate intermediate(infoSink); + TParseContext parseContext(symbolTable, extensionBehavior, intermediate, + shaderType, shaderSpec, compileOptions, true, + sourcePath, infoSink); + GlobalParseContext = &parseContext; + + // 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(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) && + (parseContext.treeRoot != NULL); + if (success) { + TIntermNode* root = parseContext.treeRoot; + success = intermediate.postProcess(root); + + if (success) + success = detectRecursion(root); + + if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING)) + success = validateLimitations(root); + + if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS)) + collectAttribsUniforms(root); + + if (success && (compileOptions & SH_INTERMEDIATE_TREE)) + intermediate.outputTree(root); + + if (success && (compileOptions & SH_OBJECT_CODE)) + translate(root); + } + + // 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(); + + return success; +} + +bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources& resources) +{ + TBuiltIns builtIns; + + builtIns.initialize(shaderType, shaderSpec, resources); + return InitializeSymbolTable(builtIns.getBuiltInStrings(), + shaderType, shaderSpec, resources, infoSink, symbolTable); +} + +void TCompiler::clearResults() +{ + infoSink.info.erase(); + infoSink.obj.erase(); + infoSink.debug.erase(); + + attribs.clear(); + uniforms.clear(); +} + +bool TCompiler::detectRecursion(TIntermNode* root) +{ + DetectRecursion detect; + root->traverse(&detect); + switch (detect.detectRecursion()) { + case DetectRecursion::kErrorNone: + return true; + case DetectRecursion::kErrorMissingMain: + infoSink.info.message(EPrefixError, "Missing main()"); + return false; + case DetectRecursion::kErrorRecursion: + infoSink.info.message(EPrefixError, "Function recursion detected"); + return false; + default: + UNREACHABLE(); + return false; + } +} + +bool TCompiler::validateLimitations(TIntermNode* root) { + ValidateLimitations validate(shaderType, infoSink.info); + root->traverse(&validate); + return validate.numErrors() == 0; +} + +void TCompiler::collectAttribsUniforms(TIntermNode* root) +{ + CollectAttribsUniforms collect(attribs, uniforms); + root->traverse(&collect); +} + +const TExtensionBehavior& TCompiler::getExtensionBehavior() const +{ + return extensionBehavior; +}
diff --git a/src/GLES2/compiler/Compiler.vcxproj b/src/GLES2/compiler/Compiler.vcxproj new file mode 100644 index 0000000..9ca34db --- /dev/null +++ b/src/GLES2/compiler/Compiler.vcxproj
@@ -0,0 +1,218 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Profile|Win32"> + <Configuration>Profile</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}</ProjectGuid> + <RootNamespace>compiler</RootNamespace> + <Keyword>Win32Proj</Keyword> + <ProjectName>Compiler</ProjectName> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <CharacterSet>NotSet</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <CharacterSet>NotSet</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <CharacterSet>NotSet</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">$(Platform)\$(Configuration)\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">$(Platform)\$(Configuration)\</IntDir> + <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\include;$(DXSDK_DIR)\Include;$(VCInstallDir)PlatformSDK\include;$(IncludePath)</IncludePath> + <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\include;$(DXSDK_DIR)\Include;$(VCInstallDir)PlatformSDK\include;$(IncludePath)</IncludePath> + <IncludePath Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">..\include;$(DXSDK_DIR)\Include;$(VCInstallDir)PlatformSDK\include;$(IncludePath)</IncludePath> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)../;$(ProjectDir)../../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>true</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <BrowseInformation>true</BrowseInformation> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> + <AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)../;$(ProjectDir)../../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'"> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> + <AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)../;$(ProjectDir)../../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <OmitFramePointers>false</OmitFramePointers> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="Compiler.cpp" /> + <ClCompile Include="debug.cpp" /> + <ClCompile Include="DetectRecursion.cpp" /> + <ClCompile Include="Diagnostics.cpp" /> + <ClCompile Include="DirectiveHandler.cpp" /> + <ClCompile Include="InfoSink.cpp" /> + <ClCompile Include="Initialize.cpp" /> + <ClCompile Include="InitializeDll.cpp" /> + <ClCompile Include="InitializeParseContext.cpp" /> + <ClCompile Include="Intermediate.cpp" /> + <ClCompile Include="intermOut.cpp" /> + <ClCompile Include="IntermTraverse.cpp" /> + <ClCompile Include="ossource_win.cpp" /> + <ClCompile Include="OutputASM.cpp" /> + <ClCompile Include="parseConst.cpp" /> + <ClCompile Include="ParseHelper.cpp" /> + <ClCompile Include="PoolAlloc.cpp" /> + <ClCompile Include="QualifierAlive.cpp" /> + <ClCompile Include="RemoveTree.cpp" /> + <ClCompile Include="ShaderLang.cpp" /> + <ClCompile Include="SymbolTable.cpp" /> + <ClCompile Include="TranslatorASM.cpp" /> + <ClCompile Include="util.cpp" /> + <ClCompile Include="ValidateLimitations.cpp" /> + <ClCompile Include="VariableInfo.cpp" /> + <ClCompile Include="glslang_lex.cpp" /> + <ClCompile Include="glslang_tab.cpp" /> + </ItemGroup> + <ItemGroup> + <CustomBuild Include="glslang.l"> + <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + </Message> + <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + </Command> + <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalInputs)</AdditionalInputs> + <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(Outputs)</Outputs> + <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + </Message> + <Message Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'"> + </Message> + <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + </Command> + <Command Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'"> + </Command> + <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalInputs)</AdditionalInputs> + <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">%(AdditionalInputs)</AdditionalInputs> + <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(Outputs)</Outputs> + <Outputs Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">%(Outputs)</Outputs> + </CustomBuild> + <CustomBuild Include="glslang.y"> + <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + </Message> + <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + </Command> + <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(Outputs)</Outputs> + <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + </Message> + <Message Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'"> + </Message> + <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + </Command> + <Command Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'"> + </Command> + <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(Outputs)</Outputs> + <Outputs Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">%(Outputs)</Outputs> + </CustomBuild> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\include\GLSLANG\ShaderLang.h" /> + <ClInclude Include="BaseTypes.h" /> + <ClInclude Include="Common.h" /> + <ClInclude Include="ConstantUnion.h" /> + <ClInclude Include="debug.h" /> + <ClInclude Include="DetectRecursion.h" /> + <ClInclude Include="Diagnostics.h" /> + <ClInclude Include="InfoSink.h" /> + <ClInclude Include="Initialize.h" /> + <ClInclude Include="InitializeDll.h" /> + <ClInclude Include="InitializeGlobals.h" /> + <ClInclude Include="InitializeParseContext.h" /> + <ClInclude Include="intermediate.h" /> + <ClInclude Include="localintermediate.h" /> + <ClInclude Include="MMap.h" /> + <ClInclude Include="osinclude.h" /> + <ClInclude Include="OutputASM.h" /> + <ClInclude Include="ParseHelper.h" /> + <ClInclude Include="PoolAlloc.h" /> + <ClInclude Include="Pragma.h" /> + <ClInclude Include="QualifierAlive.h" /> + <ClInclude Include="RemoveTree.h" /> + <ClInclude Include="ShHandle.h" /> + <ClInclude Include="SymbolTable.h" /> + <ClInclude Include="TranslatorASM.h" /> + <ClInclude Include="Types.h" /> + <ClInclude Include="util.h" /> + <ClInclude Include="ValidateLimitations.h" /> + <ClInclude Include="VariableInfo.h" /> + <ClInclude Include="glslang_tab.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="preprocessor\preprocessor.vcxproj"> + <Project>{92940255-ab4b-42fb-a2c4-0fab19c3c48a}</Project> + <Private>true</Private> + <ReferenceOutputAssembly>true</ReferenceOutputAssembly> + <CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies> + <LinkLibraryDependencies>true</LinkLibraryDependencies> + <UseLibraryDependencyInputs>false</UseLibraryDependencyInputs> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file
diff --git a/src/GLES2/compiler/Compiler.vcxproj.filters b/src/GLES2/compiler/Compiler.vcxproj.filters new file mode 100644 index 0000000..cce0afb --- /dev/null +++ b/src/GLES2/compiler/Compiler.vcxproj.filters
@@ -0,0 +1,202 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Source Files\generated"> + <UniqueIdentifier>{1add4406-d193-4c4e-a8ec-c41c8d0bd499}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Header Files\generated"> + <UniqueIdentifier>{a56a1771-4799-47ac-ace9-6955dd3f055b}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="Compiler.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="InfoSink.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Initialize.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="InitializeDll.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Intermediate.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="intermOut.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="IntermTraverse.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ossource_win.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="parseConst.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ParseHelper.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="PoolAlloc.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="QualifierAlive.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="RemoveTree.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ShaderLang.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SymbolTable.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="util.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ValidateLimitations.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="VariableInfo.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="glslang_lex.cpp"> + <Filter>Source Files\generated</Filter> + </ClCompile> + <ClCompile Include="glslang_tab.cpp"> + <Filter>Source Files\generated</Filter> + </ClCompile> + <ClCompile Include="DetectRecursion.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="OutputASM.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="TranslatorASM.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="debug.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Diagnostics.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="DirectiveHandler.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="InitializeParseContext.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="BaseTypes.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Common.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="ConstantUnion.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="InfoSink.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Initialize.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="InitializeDll.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="InitializeGlobals.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="InitializeParseContext.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="intermediate.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="localintermediate.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="MMap.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="osinclude.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="ParseHelper.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="PoolAlloc.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="QualifierAlive.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="RemoveTree.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="ShHandle.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="SymbolTable.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Types.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="util.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="ValidateLimitations.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="VariableInfo.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="glslang_tab.h"> + <Filter>Header Files\generated</Filter> + </ClInclude> + <ClInclude Include="DetectRecursion.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\GLSLANG\ShaderLang.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="OutputASM.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="TranslatorASM.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="debug.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Diagnostics.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Pragma.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <CustomBuild Include="glslang.l"> + <Filter>Source Files</Filter> + </CustomBuild> + <CustomBuild Include="glslang.y"> + <Filter>Source Files</Filter> + </CustomBuild> + </ItemGroup> +</Project> \ No newline at end of file
diff --git a/src/GLES2/compiler/ConstantUnion.h b/src/GLES2/compiler/ConstantUnion.h new file mode 100644 index 0000000..bac2e9a --- /dev/null +++ b/src/GLES2/compiler/ConstantUnion.h
@@ -0,0 +1,275 @@ +// +// Copyright (c) 2002-2012 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. +// + +#ifndef _CONSTANT_UNION_INCLUDED_ +#define _CONSTANT_UNION_INCLUDED_ + +#include <assert.h> + +class ConstantUnion { +public: + ConstantUnion() + { + iConst = 0; + } + + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + void setIConst(int i) {iConst = i; type = EbtInt; } + void setFConst(float f) {fConst = f; type = EbtFloat; } + void setBConst(bool b) {bConst = b; type = EbtBool; } + + int getIConst() { return iConst; } + float getFConst() { return fConst; } + bool getBConst() { return bConst; } + int getIConst() const { return iConst; } + float getFConst() const { return fConst; } + bool getBConst() const { return bConst; } + + float getAsFloat() + { + const int FFFFFFFFh = 0xFFFFFFFF; + + switch(type) + { + case EbtInt: return (float)iConst; + case EbtFloat: return fConst; + case EbtBool: return (bConst == true) ? (float&)FFFFFFFFh : 0; + default: return 0; + } + } + + bool operator==(const int i) const + { + return i == iConst; + } + + bool operator==(const float f) const + { + return f == fConst; + } + + bool operator==(const bool b) const + { + return b == bConst; + } + + bool operator==(const ConstantUnion& constant) const + { + if (constant.type != type) + return false; + + switch (type) { + case EbtInt: + return constant.iConst == iConst; + case EbtFloat: + return constant.fConst == fConst; + case EbtBool: + return constant.bConst == bConst; + default: + return false; + } + + return false; + } + + bool operator!=(const int i) const + { + return !operator==(i); + } + + bool operator!=(const float f) const + { + return !operator==(f); + } + + bool operator!=(const bool b) const + { + return !operator==(b); + } + + bool operator!=(const ConstantUnion& constant) const + { + return !operator==(constant); + } + + bool operator>(const ConstantUnion& constant) const + { + assert(type == constant.type); + switch (type) { + case EbtInt: + return iConst > constant.iConst; + case EbtFloat: + return fConst > constant.fConst; + default: + return false; // Invalid operation, handled at semantic analysis + } + + return false; + } + + bool operator<(const ConstantUnion& constant) const + { + assert(type == constant.type); + switch (type) { + case EbtInt: + return iConst < constant.iConst; + case EbtFloat: + return fConst < constant.fConst; + default: + return false; // Invalid operation, handled at semantic analysis + } + + return false; + } + + ConstantUnion operator+(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst + constant.iConst); break; + case EbtFloat: returnValue.setFConst(fConst + constant.fConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator-(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst - constant.iConst); break; + case EbtFloat: returnValue.setFConst(fConst - constant.fConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator*(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst * constant.iConst); break; + case EbtFloat: returnValue.setFConst(fConst * constant.fConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator%(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst % constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator>>(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator<<(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst << constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator&(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst & constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator|(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst | constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator^(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator&&(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtBool: returnValue.setBConst(bConst && constant.bConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator||(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtBool: returnValue.setBConst(bConst || constant.bConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + TBasicType getType() const { return type; } +private: + + union { + int iConst; // used for ivec, scalar ints + bool bConst; // used for bvec, scalar bools + float fConst; // used for vec, mat, scalar floats + } ; + + TBasicType type; +}; + +#endif // _CONSTANT_UNION_INCLUDED_
diff --git a/src/GLES2/compiler/DetectRecursion.cpp b/src/GLES2/compiler/DetectRecursion.cpp new file mode 100644 index 0000000..e79b70d --- /dev/null +++ b/src/GLES2/compiler/DetectRecursion.cpp
@@ -0,0 +1,125 @@ +// +// Copyright (c) 2002-2012 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/DetectRecursion.h" + +DetectRecursion::FunctionNode::FunctionNode(const TString& fname) + : name(fname), + visit(PreVisit) +{ +} + +const TString& DetectRecursion::FunctionNode::getName() const +{ + return name; +} + +void DetectRecursion::FunctionNode::addCallee( + DetectRecursion::FunctionNode* callee) +{ + for (size_t i = 0; i < callees.size(); ++i) { + if (callees[i] == callee) + return; + } + callees.push_back(callee); +} + +bool DetectRecursion::FunctionNode::detectRecursion() +{ + ASSERT(visit == PreVisit); + visit = InVisit; + for (size_t i = 0; i < callees.size(); ++i) { + switch (callees[i]->visit) { + case InVisit: + // cycle detected, i.e., recursion detected. + return true; + case PostVisit: + break; + case PreVisit: { + bool recursion = callees[i]->detectRecursion(); + if (recursion) + return true; + break; + } + default: + UNREACHABLE(); + break; + } + } + visit = PostVisit; + return false; +} + +DetectRecursion::DetectRecursion() + : currentFunction(NULL) +{ +} + +DetectRecursion::~DetectRecursion() +{ + for (size_t i = 0; i < functions.size(); ++i) + delete functions[i]; +} + +bool DetectRecursion::visitAggregate(Visit visit, TIntermAggregate* node) +{ + switch (node->getOp()) + { + case EOpPrototype: + // Function declaration. + // Don't add FunctionNode here because node->getName() is the + // unmangled function name. + break; + case EOpFunction: { + // Function definition. + if (visit == PreVisit) { + currentFunction = findFunctionByName(node->getName()); + if (currentFunction == NULL) { + currentFunction = new FunctionNode(node->getName()); + functions.push_back(currentFunction); + } + } + break; + } + case EOpFunctionCall: { + // Function call. + if (visit == PreVisit) { + ASSERT(currentFunction != NULL); + FunctionNode* func = findFunctionByName(node->getName()); + if (func == NULL) { + func = new FunctionNode(node->getName()); + functions.push_back(func); + } + currentFunction->addCallee(func); + } + break; + } + default: + break; + } + return true; +} + +DetectRecursion::ErrorCode DetectRecursion::detectRecursion() +{ + FunctionNode* main = findFunctionByName("main("); + if (main == NULL) + return kErrorMissingMain; + if (main->detectRecursion()) + return kErrorRecursion; + return kErrorNone; +} + +DetectRecursion::FunctionNode* DetectRecursion::findFunctionByName( + const TString& name) +{ + for (size_t i = 0; i < functions.size(); ++i) { + if (functions[i]->getName() == name) + return functions[i]; + } + return NULL; +} +
diff --git a/src/GLES2/compiler/DetectRecursion.h b/src/GLES2/compiler/DetectRecursion.h new file mode 100644 index 0000000..bbac79d --- /dev/null +++ b/src/GLES2/compiler/DetectRecursion.h
@@ -0,0 +1,60 @@ +// +// Copyright (c) 2002-2011 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. +// + +#ifndef COMPILER_DETECT_RECURSION_H_ +#define COMPILER_DETECT_RECURSION_H_ + +#include "GLSLANG/ShaderLang.h" + +#include "compiler/intermediate.h" +#include "compiler/VariableInfo.h" + +// Traverses intermediate tree to detect function recursion. +class DetectRecursion : public TIntermTraverser { +public: + enum ErrorCode { + kErrorMissingMain, + kErrorRecursion, + kErrorNone + }; + + DetectRecursion(); + ~DetectRecursion(); + + virtual bool visitAggregate(Visit, TIntermAggregate*); + + ErrorCode detectRecursion(); + +private: + class FunctionNode { + public: + FunctionNode(const TString& fname); + + const TString& getName() const; + + // If a function is already in the callee list, this becomes a no-op. + void addCallee(FunctionNode* callee); + + // Return true if recursive function calls are detected. + bool detectRecursion(); + + private: + // mangled function name is unique. + TString name; + + // functions that are directly called by this function. + TVector<FunctionNode*> callees; + + Visit visit; + }; + + FunctionNode* findFunctionByName(const TString& name); + + TVector<FunctionNode*> functions; + FunctionNode* currentFunction; +}; + +#endif // COMPILER_DETECT_RECURSION_H_
diff --git a/src/GLES2/compiler/Diagnostics.cpp b/src/GLES2/compiler/Diagnostics.cpp new file mode 100644 index 0000000..166a4a8 --- /dev/null +++ b/src/GLES2/compiler/Diagnostics.cpp
@@ -0,0 +1,63 @@ +// +// Copyright (c) 2012 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/Diagnostics.h" + +#include "compiler/debug.h" +#include "compiler/InfoSink.h" +#include "compiler/preprocessor/SourceLocation.h" + +TDiagnostics::TDiagnostics(TInfoSink& infoSink) : + mInfoSink(infoSink), + mNumErrors(0), + mNumWarnings(0) +{ +} + +TDiagnostics::~TDiagnostics() +{ +} + +void TDiagnostics::writeInfo(Severity severity, + const pp::SourceLocation& loc, + const std::string& reason, + const std::string& token, + const std::string& extra) +{ + TPrefixType prefix = EPrefixNone; + switch (severity) + { + case PP_ERROR: + ++mNumErrors; + prefix = EPrefixError; + break; + case PP_WARNING: + ++mNumWarnings; + prefix = EPrefixWarning; + break; + default: + UNREACHABLE(); + break; + } + + TInfoSinkBase& sink = mInfoSink.info; + /* VC++ format: file(linenum) : error #: 'token' : extrainfo */ + sink.prefix(prefix); + sink.location(EncodeSourceLoc(loc.file, loc.line)); + sink << "'" << token << "' : " << reason << " " << extra << "\n"; +} + +void TDiagnostics::writeDebug(const std::string& str) +{ + mInfoSink.debug << str; +} + +void TDiagnostics::print(ID id, + const pp::SourceLocation& loc, + const std::string& text) +{ + writeInfo(severity(id), loc, message(id), text, ""); +}
diff --git a/src/GLES2/compiler/Diagnostics.h b/src/GLES2/compiler/Diagnostics.h new file mode 100644 index 0000000..43dfcb7 --- /dev/null +++ b/src/GLES2/compiler/Diagnostics.h
@@ -0,0 +1,44 @@ +// +// Copyright (c) 2012 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. +// + +#ifndef COMPILER_DIAGNOSTICS_H_ +#define COMPILER_DIAGNOSTICS_H_ + +#include "compiler/preprocessor/Diagnostics.h" + +class TInfoSink; + +class TDiagnostics : public pp::Diagnostics +{ + public: + TDiagnostics(TInfoSink& infoSink); + virtual ~TDiagnostics(); + + TInfoSink& infoSink() { return mInfoSink; } + + int numErrors() const { return mNumErrors; } + int numWarnings() const { return mNumWarnings; } + + void writeInfo(Severity severity, + const pp::SourceLocation& loc, + const std::string& reason, + const std::string& token, + const std::string& extra); + + void writeDebug(const std::string& str); + + protected: + virtual void print(ID id, + const pp::SourceLocation& loc, + const std::string& text); + + private: + TInfoSink& mInfoSink; + int mNumErrors; + int mNumWarnings; +}; + +#endif // COMPILER_DIAGNOSTICS_H_
diff --git a/src/GLES2/compiler/DirectiveHandler.cpp b/src/GLES2/compiler/DirectiveHandler.cpp new file mode 100644 index 0000000..f6a9a93 --- /dev/null +++ b/src/GLES2/compiler/DirectiveHandler.cpp
@@ -0,0 +1,161 @@ +// +// Copyright (c) 2012 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/DirectiveHandler.h" + +#include <sstream> + +#include "compiler/debug.h" +#include "compiler/Diagnostics.h" + +static TBehavior getBehavior(const std::string& str) +{ + static const std::string kRequire("require"); + static const std::string kEnable("enable"); + static const std::string kDisable("disable"); + static const std::string kWarn("warn"); + + if (str == kRequire) return EBhRequire; + else if (str == kEnable) return EBhEnable; + else if (str == kDisable) return EBhDisable; + else if (str == kWarn) return EBhWarn; + return EBhUndefined; +} + +TDirectiveHandler::TDirectiveHandler(TExtensionBehavior& extBehavior, + TDiagnostics& diagnostics) + : mExtensionBehavior(extBehavior), + mDiagnostics(diagnostics) +{ +} + +TDirectiveHandler::~TDirectiveHandler() +{ +} + +void TDirectiveHandler::handleError(const pp::SourceLocation& loc, + const std::string& msg) +{ + mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, msg, "", ""); +} + +void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc, + const std::string& name, + const std::string& value) +{ + static const std::string kSTDGL("STDGL"); + static const std::string kOptimize("optimize"); + static const std::string kDebug("debug"); + static const std::string kOn("on"); + static const std::string kOff("off"); + + bool invalidValue = false; + if (name == kSTDGL) + { + // The STDGL pragma is used to reserve pragmas for use by future + // revisions of GLSL. Ignore it. + return; + } + else if (name == kOptimize) + { + if (value == kOn) mPragma.optimize = true; + else if (value == kOff) mPragma.optimize = false; + else invalidValue = true; + } + else if (name == kDebug) + { + if (value == kOn) mPragma.debug = true; + else if (value == kOff) mPragma.debug = false; + else invalidValue = true; + } + else + { + mDiagnostics.report(pp::Diagnostics::UNRECOGNIZED_PRAGMA, loc, name); + return; + } + + if (invalidValue) + mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, + "invalid pragma value", value, + "'on' or 'off' expected"); +} + +void TDirectiveHandler::handleExtension(const pp::SourceLocation& loc, + const std::string& name, + const std::string& behavior) +{ + static const std::string kExtAll("all"); + + TBehavior behaviorVal = getBehavior(behavior); + if (behaviorVal == EBhUndefined) + { + mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, + "behavior", name, "invalid"); + return; + } + + if (name == kExtAll) + { + if (behaviorVal == EBhRequire) + { + mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, + "extension", name, + "cannot have 'require' behavior"); + } + else if (behaviorVal == EBhEnable) + { + mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, + "extension", name, + "cannot have 'enable' behavior"); + } + else + { + for (TExtensionBehavior::iterator iter = mExtensionBehavior.begin(); + iter != mExtensionBehavior.end(); ++iter) + iter->second = behaviorVal; + } + return; + } + + TExtensionBehavior::iterator iter = mExtensionBehavior.find(name); + if (iter != mExtensionBehavior.end()) + { + iter->second = behaviorVal; + return; + } + + pp::Diagnostics::Severity severity = pp::Diagnostics::PP_ERROR; + switch (behaviorVal) { + case EBhRequire: + severity = pp::Diagnostics::PP_ERROR; + break; + case EBhEnable: + case EBhWarn: + case EBhDisable: + severity = pp::Diagnostics::PP_WARNING; + break; + default: + UNREACHABLE(); + break; + } + mDiagnostics.writeInfo(severity, loc, + "extension", name, "is not supported"); +} + +void TDirectiveHandler::handleVersion(const pp::SourceLocation& loc, + int version) +{ + static const int kVersion = 100; + + if (version != kVersion) + { + std::stringstream stream; + stream << version; + std::string str = stream.str(); + mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, + "version number", str, "not supported"); + } +}
diff --git a/src/GLES2/compiler/DirectiveHandler.h b/src/GLES2/compiler/DirectiveHandler.h new file mode 100644 index 0000000..a08b7a8 --- /dev/null +++ b/src/GLES2/compiler/DirectiveHandler.h
@@ -0,0 +1,46 @@ +// +// Copyright (c) 2012 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. +// + +#ifndef COMPILER_DIRECTIVE_HANDLER_H_ +#define COMPILER_DIRECTIVE_HANDLER_H_ + +#include "compiler/ExtensionBehavior.h" +#include "compiler/Pragma.h" +#include "compiler/preprocessor/DirectiveHandler.h" + +class TDiagnostics; + +class TDirectiveHandler : public pp::DirectiveHandler +{ + public: + TDirectiveHandler(TExtensionBehavior& extBehavior, + TDiagnostics& diagnostics); + virtual ~TDirectiveHandler(); + + const TPragma& pragma() const { return mPragma; } + const TExtensionBehavior& extensionBehavior() const { return mExtensionBehavior; } + + virtual void handleError(const pp::SourceLocation& loc, + const std::string& msg); + + virtual void handlePragma(const pp::SourceLocation& loc, + const std::string& name, + const std::string& value); + + virtual void handleExtension(const pp::SourceLocation& loc, + const std::string& name, + const std::string& behavior); + + virtual void handleVersion(const pp::SourceLocation& loc, + int version); + + private: + TPragma mPragma; + TExtensionBehavior& mExtensionBehavior; + TDiagnostics& mDiagnostics; +}; + +#endif // COMPILER_DIRECTIVE_HANDLER_H_
diff --git a/src/GLES2/compiler/ExtensionBehavior.h b/src/GLES2/compiler/ExtensionBehavior.h new file mode 100644 index 0000000..e369ddd --- /dev/null +++ b/src/GLES2/compiler/ExtensionBehavior.h
@@ -0,0 +1,37 @@ +// +// Copyright (c) 2002-2012 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. +// + +#ifndef _EXTENSION_BEHAVIOR_INCLUDED_ +#define _EXTENSION_BEHAVIOR_INCLUDED_ + +#include <map> +#include <string> + +typedef enum +{ + EBhRequire, + EBhEnable, + EBhWarn, + EBhDisable, + EBhUndefined, +} TBehavior; + +inline const char *getBehaviorString(TBehavior b) +{ + switch(b) + { + case EBhRequire: return "require"; + case EBhEnable: return "enable"; + case EBhWarn: return "warn"; + case EBhDisable: return "disable"; + default: return NULL; + } +} + +// Mapping between extension name and behavior. +typedef std::map<std::string, TBehavior> TExtensionBehavior; + +#endif // _EXTENSION_TABLE_INCLUDED_
diff --git a/src/GLES2/compiler/InfoSink.cpp b/src/GLES2/compiler/InfoSink.cpp new file mode 100644 index 0000000..ba32f78 --- /dev/null +++ b/src/GLES2/compiler/InfoSink.cpp
@@ -0,0 +1,59 @@ +// +// 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/InfoSink.h" + +void TInfoSinkBase::prefix(TPrefixType message) { + switch(message) { + case EPrefixNone: + break; + case EPrefixWarning: + sink.append("WARNING: "); + break; + case EPrefixError: + sink.append("ERROR: "); + break; + case EPrefixInternalError: + sink.append("INTERNAL ERROR: "); + break; + case EPrefixUnimplemented: + sink.append("UNIMPLEMENTED: "); + break; + case EPrefixNote: + sink.append("NOTE: "); + break; + default: + sink.append("UNKOWN ERROR: "); + break; + } +} + +void TInfoSinkBase::location(TSourceLoc loc) { + int string = 0, line = 0; + DecodeSourceLoc(loc, &string, &line); + + TPersistStringStream stream; + if (line) + stream << string << ":" << line; + else + stream << string << ":? "; + stream << ": "; + + sink.append(stream.str()); +} + +void TInfoSinkBase::message(TPrefixType message, const char* s) { + prefix(message); + sink.append(s); + sink.append("\n"); +} + +void TInfoSinkBase::message(TPrefixType message, const char* s, TSourceLoc loc) { + prefix(message); + location(loc); + sink.append(s); + sink.append("\n"); +}
diff --git a/src/GLES2/compiler/InfoSink.h b/src/GLES2/compiler/InfoSink.h new file mode 100644 index 0000000..e2224e9 --- /dev/null +++ b/src/GLES2/compiler/InfoSink.h
@@ -0,0 +1,115 @@ +// +// 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. +// + +#ifndef _INFOSINK_INCLUDED_ +#define _INFOSINK_INCLUDED_ + +#include <math.h> +#include "compiler/Common.h" + +// Returns the fractional part of the given floating-point number. +inline float fractionalPart(float f) { + float intPart = 0.0f; + return modff(f, &intPart); +} + +// +// TPrefixType is used to centralize how info log messages start. +// See below. +// +enum TPrefixType { + EPrefixNone, + EPrefixWarning, + EPrefixError, + EPrefixInternalError, + EPrefixUnimplemented, + EPrefixNote +}; + +// +// Encapsulate info logs for all objects that have them. +// +// The methods are a general set of tools for getting a variety of +// messages and types inserted into the log. +// +class TInfoSinkBase { +public: + TInfoSinkBase() {} + + template <typename T> + TInfoSinkBase& operator<<(const T& t) { + TPersistStringStream stream; + stream << t; + sink.append(stream.str()); + return *this; + } + // Override << operator for specific types. It is faster to append strings + // and characters directly to the sink. + TInfoSinkBase& operator<<(char c) { + sink.append(1, c); + return *this; + } + TInfoSinkBase& operator<<(const char* str) { + sink.append(str); + return *this; + } + TInfoSinkBase& operator<<(const TPersistString& str) { + sink.append(str); + return *this; + } + TInfoSinkBase& operator<<(const TString& str) { + sink.append(str.c_str()); + return *this; + } + // Make sure floats are written with correct precision. + TInfoSinkBase& operator<<(float f) { + // Make sure that at least one decimal point is written. If a number + // does not have a fractional part, the default precision format does + // not write the decimal portion which gets interpreted as integer by + // the compiler. + TPersistStringStream stream; + if (fractionalPart(f) == 0.0f) { + stream.precision(1); + stream << std::showpoint << std::fixed << f; + } else { + stream.unsetf(std::ios::fixed); + stream.unsetf(std::ios::scientific); + stream.precision(8); + stream << f; + } + sink.append(stream.str()); + return *this; + } + // Write boolean values as their names instead of integral value. + TInfoSinkBase& operator<<(bool b) { + const char* str = b ? "true" : "false"; + sink.append(str); + return *this; + } + + void erase() { sink.clear(); } + int size() { return static_cast<int>(sink.size()); } + + const TPersistString& str() const { return sink; } + const char* c_str() const { return sink.c_str(); } + + void prefix(TPrefixType message); + void location(TSourceLoc loc); + void message(TPrefixType message, const char* s); + void message(TPrefixType message, const char* s, TSourceLoc loc); + +private: + TPersistString sink; +}; + +class TInfoSink { +public: + TInfoSinkBase info; + TInfoSinkBase debug; + TInfoSinkBase obj; +}; + +#endif // _INFOSINK_INCLUDED_
diff --git a/src/GLES2/compiler/Initialize.cpp b/src/GLES2/compiler/Initialize.cpp new file mode 100644 index 0000000..401b9b8 --- /dev/null +++ b/src/GLES2/compiler/Initialize.cpp
@@ -0,0 +1,628 @@ +// +// 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. +// + +// +// Create strings that declare built-in definitions, add built-ins that +// cannot be expressed in the files, and establish mappings between +// built-in functions and operators. +// + +#include "compiler/Initialize.h" + +#include "compiler/intermediate.h" + +//============================================================================ +// +// Prototypes for built-in functions seen by both vertex and fragment shaders. +// +//============================================================================ +static TString BuiltInFunctionsCommon() +{ + TString s; + + // + // Angle and Trigonometric Functions. + // + s.append(TString("float radians(float degrees);")); + s.append(TString("vec2 radians(vec2 degrees);")); + s.append(TString("vec3 radians(vec3 degrees);")); + s.append(TString("vec4 radians(vec4 degrees);")); + + s.append(TString("float degrees(float radians);")); + s.append(TString("vec2 degrees(vec2 radians);")); + s.append(TString("vec3 degrees(vec3 radians);")); + s.append(TString("vec4 degrees(vec4 radians);")); + + s.append(TString("float sin(float angle);")); + s.append(TString("vec2 sin(vec2 angle);")); + s.append(TString("vec3 sin(vec3 angle);")); + s.append(TString("vec4 sin(vec4 angle);")); + + s.append(TString("float cos(float angle);")); + s.append(TString("vec2 cos(vec2 angle);")); + s.append(TString("vec3 cos(vec3 angle);")); + s.append(TString("vec4 cos(vec4 angle);")); + + s.append(TString("float tan(float angle);")); + s.append(TString("vec2 tan(vec2 angle);")); + s.append(TString("vec3 tan(vec3 angle);")); + s.append(TString("vec4 tan(vec4 angle);")); + + s.append(TString("float asin(float x);")); + s.append(TString("vec2 asin(vec2 x);")); + s.append(TString("vec3 asin(vec3 x);")); + s.append(TString("vec4 asin(vec4 x);")); + + s.append(TString("float acos(float x);")); + s.append(TString("vec2 acos(vec2 x);")); + s.append(TString("vec3 acos(vec3 x);")); + s.append(TString("vec4 acos(vec4 x);")); + + s.append(TString("float atan(float y, float x);")); + s.append(TString("vec2 atan(vec2 y, vec2 x);")); + s.append(TString("vec3 atan(vec3 y, vec3 x);")); + s.append(TString("vec4 atan(vec4 y, vec4 x);")); + + s.append(TString("float atan(float y_over_x);")); + s.append(TString("vec2 atan(vec2 y_over_x);")); + s.append(TString("vec3 atan(vec3 y_over_x);")); + s.append(TString("vec4 atan(vec4 y_over_x);")); + + // + // Exponential Functions. + // + s.append(TString("float pow(float x, float y);")); + s.append(TString("vec2 pow(vec2 x, vec2 y);")); + s.append(TString("vec3 pow(vec3 x, vec3 y);")); + s.append(TString("vec4 pow(vec4 x, vec4 y);")); + + s.append(TString("float exp(float x);")); + s.append(TString("vec2 exp(vec2 x);")); + s.append(TString("vec3 exp(vec3 x);")); + s.append(TString("vec4 exp(vec4 x);")); + + s.append(TString("float log(float x);")); + s.append(TString("vec2 log(vec2 x);")); + s.append(TString("vec3 log(vec3 x);")); + s.append(TString("vec4 log(vec4 x);")); + + s.append(TString("float exp2(float x);")); + s.append(TString("vec2 exp2(vec2 x);")); + s.append(TString("vec3 exp2(vec3 x);")); + s.append(TString("vec4 exp2(vec4 x);")); + + s.append(TString("float log2(float x);")); + s.append(TString("vec2 log2(vec2 x);")); + s.append(TString("vec3 log2(vec3 x);")); + s.append(TString("vec4 log2(vec4 x);")); + + s.append(TString("float sqrt(float x);")); + s.append(TString("vec2 sqrt(vec2 x);")); + s.append(TString("vec3 sqrt(vec3 x);")); + s.append(TString("vec4 sqrt(vec4 x);")); + + s.append(TString("float inversesqrt(float x);")); + s.append(TString("vec2 inversesqrt(vec2 x);")); + s.append(TString("vec3 inversesqrt(vec3 x);")); + s.append(TString("vec4 inversesqrt(vec4 x);")); + + // + // Common Functions. + // + s.append(TString("float abs(float x);")); + s.append(TString("vec2 abs(vec2 x);")); + s.append(TString("vec3 abs(vec3 x);")); + s.append(TString("vec4 abs(vec4 x);")); + + s.append(TString("float sign(float x);")); + s.append(TString("vec2 sign(vec2 x);")); + s.append(TString("vec3 sign(vec3 x);")); + s.append(TString("vec4 sign(vec4 x);")); + + s.append(TString("float floor(float x);")); + s.append(TString("vec2 floor(vec2 x);")); + s.append(TString("vec3 floor(vec3 x);")); + s.append(TString("vec4 floor(vec4 x);")); + + s.append(TString("float ceil(float x);")); + s.append(TString("vec2 ceil(vec2 x);")); + s.append(TString("vec3 ceil(vec3 x);")); + s.append(TString("vec4 ceil(vec4 x);")); + + s.append(TString("float fract(float x);")); + s.append(TString("vec2 fract(vec2 x);")); + s.append(TString("vec3 fract(vec3 x);")); + s.append(TString("vec4 fract(vec4 x);")); + + s.append(TString("float mod(float x, float y);")); + s.append(TString("vec2 mod(vec2 x, float y);")); + s.append(TString("vec3 mod(vec3 x, float y);")); + s.append(TString("vec4 mod(vec4 x, float y);")); + s.append(TString("vec2 mod(vec2 x, vec2 y);")); + s.append(TString("vec3 mod(vec3 x, vec3 y);")); + s.append(TString("vec4 mod(vec4 x, vec4 y);")); + + s.append(TString("float min(float x, float y);")); + s.append(TString("vec2 min(vec2 x, float y);")); + s.append(TString("vec3 min(vec3 x, float y);")); + s.append(TString("vec4 min(vec4 x, float y);")); + s.append(TString("vec2 min(vec2 x, vec2 y);")); + s.append(TString("vec3 min(vec3 x, vec3 y);")); + s.append(TString("vec4 min(vec4 x, vec4 y);")); + + s.append(TString("float max(float x, float y);")); + s.append(TString("vec2 max(vec2 x, float y);")); + s.append(TString("vec3 max(vec3 x, float y);")); + s.append(TString("vec4 max(vec4 x, float y);")); + s.append(TString("vec2 max(vec2 x, vec2 y);")); + s.append(TString("vec3 max(vec3 x, vec3 y);")); + s.append(TString("vec4 max(vec4 x, vec4 y);")); + + s.append(TString("float clamp(float x, float minVal, float maxVal);")); + s.append(TString("vec2 clamp(vec2 x, float minVal, float maxVal);")); + s.append(TString("vec3 clamp(vec3 x, float minVal, float maxVal);")); + s.append(TString("vec4 clamp(vec4 x, float minVal, float maxVal);")); + s.append(TString("vec2 clamp(vec2 x, vec2 minVal, vec2 maxVal);")); + s.append(TString("vec3 clamp(vec3 x, vec3 minVal, vec3 maxVal);")); + s.append(TString("vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal);")); + + s.append(TString("float mix(float x, float y, float a);")); + s.append(TString("vec2 mix(vec2 x, vec2 y, float a);")); + s.append(TString("vec3 mix(vec3 x, vec3 y, float a);")); + s.append(TString("vec4 mix(vec4 x, vec4 y, float a);")); + s.append(TString("vec2 mix(vec2 x, vec2 y, vec2 a);")); + s.append(TString("vec3 mix(vec3 x, vec3 y, vec3 a);")); + s.append(TString("vec4 mix(vec4 x, vec4 y, vec4 a);")); + + s.append(TString("float step(float edge, float x);")); + s.append(TString("vec2 step(vec2 edge, vec2 x);")); + s.append(TString("vec3 step(vec3 edge, vec3 x);")); + s.append(TString("vec4 step(vec4 edge, vec4 x);")); + s.append(TString("vec2 step(float edge, vec2 x);")); + s.append(TString("vec3 step(float edge, vec3 x);")); + s.append(TString("vec4 step(float edge, vec4 x);")); + + s.append(TString("float smoothstep(float edge0, float edge1, float x);")); + s.append(TString("vec2 smoothstep(vec2 edge0, vec2 edge1, vec2 x);")); + s.append(TString("vec3 smoothstep(vec3 edge0, vec3 edge1, vec3 x);")); + s.append(TString("vec4 smoothstep(vec4 edge0, vec4 edge1, vec4 x);")); + s.append(TString("vec2 smoothstep(float edge0, float edge1, vec2 x);")); + s.append(TString("vec3 smoothstep(float edge0, float edge1, vec3 x);")); + s.append(TString("vec4 smoothstep(float edge0, float edge1, vec4 x);")); + + // + // Geometric Functions. + // + s.append(TString("float length(float x);")); + s.append(TString("float length(vec2 x);")); + s.append(TString("float length(vec3 x);")); + s.append(TString("float length(vec4 x);")); + + s.append(TString("float distance(float p0, float p1);")); + s.append(TString("float distance(vec2 p0, vec2 p1);")); + s.append(TString("float distance(vec3 p0, vec3 p1);")); + s.append(TString("float distance(vec4 p0, vec4 p1);")); + + s.append(TString("float dot(float x, float y);")); + s.append(TString("float dot(vec2 x, vec2 y);")); + s.append(TString("float dot(vec3 x, vec3 y);")); + s.append(TString("float dot(vec4 x, vec4 y);")); + + s.append(TString("vec3 cross(vec3 x, vec3 y);")); + s.append(TString("float normalize(float x);")); + s.append(TString("vec2 normalize(vec2 x);")); + s.append(TString("vec3 normalize(vec3 x);")); + s.append(TString("vec4 normalize(vec4 x);")); + + s.append(TString("float faceforward(float N, float I, float Nref);")); + s.append(TString("vec2 faceforward(vec2 N, vec2 I, vec2 Nref);")); + s.append(TString("vec3 faceforward(vec3 N, vec3 I, vec3 Nref);")); + s.append(TString("vec4 faceforward(vec4 N, vec4 I, vec4 Nref);")); + + s.append(TString("float reflect(float I, float N);")); + s.append(TString("vec2 reflect(vec2 I, vec2 N);")); + s.append(TString("vec3 reflect(vec3 I, vec3 N);")); + s.append(TString("vec4 reflect(vec4 I, vec4 N);")); + + s.append(TString("float refract(float I, float N, float eta);")); + s.append(TString("vec2 refract(vec2 I, vec2 N, float eta);")); + s.append(TString("vec3 refract(vec3 I, vec3 N, float eta);")); + s.append(TString("vec4 refract(vec4 I, vec4 N, float eta);")); + + // + // Matrix Functions. + // + s.append(TString("mat2 matrixCompMult(mat2 x, mat2 y);")); + s.append(TString("mat3 matrixCompMult(mat3 x, mat3 y);")); + s.append(TString("mat4 matrixCompMult(mat4 x, mat4 y);")); + + // + // Vector relational functions. + // + s.append(TString("bvec2 lessThan(vec2 x, vec2 y);")); + s.append(TString("bvec3 lessThan(vec3 x, vec3 y);")); + s.append(TString("bvec4 lessThan(vec4 x, vec4 y);")); + + s.append(TString("bvec2 lessThan(ivec2 x, ivec2 y);")); + s.append(TString("bvec3 lessThan(ivec3 x, ivec3 y);")); + s.append(TString("bvec4 lessThan(ivec4 x, ivec4 y);")); + + s.append(TString("bvec2 lessThanEqual(vec2 x, vec2 y);")); + s.append(TString("bvec3 lessThanEqual(vec3 x, vec3 y);")); + s.append(TString("bvec4 lessThanEqual(vec4 x, vec4 y);")); + + s.append(TString("bvec2 lessThanEqual(ivec2 x, ivec2 y);")); + s.append(TString("bvec3 lessThanEqual(ivec3 x, ivec3 y);")); + s.append(TString("bvec4 lessThanEqual(ivec4 x, ivec4 y);")); + + s.append(TString("bvec2 greaterThan(vec2 x, vec2 y);")); + s.append(TString("bvec3 greaterThan(vec3 x, vec3 y);")); + s.append(TString("bvec4 greaterThan(vec4 x, vec4 y);")); + + s.append(TString("bvec2 greaterThan(ivec2 x, ivec2 y);")); + s.append(TString("bvec3 greaterThan(ivec3 x, ivec3 y);")); + s.append(TString("bvec4 greaterThan(ivec4 x, ivec4 y);")); + + s.append(TString("bvec2 greaterThanEqual(vec2 x, vec2 y);")); + s.append(TString("bvec3 greaterThanEqual(vec3 x, vec3 y);")); + s.append(TString("bvec4 greaterThanEqual(vec4 x, vec4 y);")); + + s.append(TString("bvec2 greaterThanEqual(ivec2 x, ivec2 y);")); + s.append(TString("bvec3 greaterThanEqual(ivec3 x, ivec3 y);")); + s.append(TString("bvec4 greaterThanEqual(ivec4 x, ivec4 y);")); + + s.append(TString("bvec2 equal(vec2 x, vec2 y);")); + s.append(TString("bvec3 equal(vec3 x, vec3 y);")); + s.append(TString("bvec4 equal(vec4 x, vec4 y);")); + + s.append(TString("bvec2 equal(ivec2 x, ivec2 y);")); + s.append(TString("bvec3 equal(ivec3 x, ivec3 y);")); + s.append(TString("bvec4 equal(ivec4 x, ivec4 y);")); + + s.append(TString("bvec2 equal(bvec2 x, bvec2 y);")); + s.append(TString("bvec3 equal(bvec3 x, bvec3 y);")); + s.append(TString("bvec4 equal(bvec4 x, bvec4 y);")); + + s.append(TString("bvec2 notEqual(vec2 x, vec2 y);")); + s.append(TString("bvec3 notEqual(vec3 x, vec3 y);")); + s.append(TString("bvec4 notEqual(vec4 x, vec4 y);")); + + s.append(TString("bvec2 notEqual(ivec2 x, ivec2 y);")); + s.append(TString("bvec3 notEqual(ivec3 x, ivec3 y);")); + s.append(TString("bvec4 notEqual(ivec4 x, ivec4 y);")); + + s.append(TString("bvec2 notEqual(bvec2 x, bvec2 y);")); + s.append(TString("bvec3 notEqual(bvec3 x, bvec3 y);")); + s.append(TString("bvec4 notEqual(bvec4 x, bvec4 y);")); + + s.append(TString("bool any(bvec2 x);")); + s.append(TString("bool any(bvec3 x);")); + s.append(TString("bool any(bvec4 x);")); + + s.append(TString("bool all(bvec2 x);")); + s.append(TString("bool all(bvec3 x);")); + s.append(TString("bool all(bvec4 x);")); + + s.append(TString("bvec2 not(bvec2 x);")); + s.append(TString("bvec3 not(bvec3 x);")); + s.append(TString("bvec4 not(bvec4 x);")); + + // + // Texture Functions. + // + s.append(TString("vec4 texture2D(sampler2D sampler, vec2 coord);")); + s.append(TString("vec4 texture2DProj(sampler2D sampler, vec3 coord);")); + s.append(TString("vec4 texture2DProj(sampler2D sampler, vec4 coord);")); + s.append(TString("vec4 textureCube(samplerCube sampler, vec3 coord);")); + + // + // Noise functions. + // + //s.append(TString("float noise1(float x);")); + //s.append(TString("float noise1(vec2 x);")); + //s.append(TString("float noise1(vec3 x);")); + //s.append(TString("float noise1(vec4 x);")); + + //s.append(TString("vec2 noise2(float x);")); + //s.append(TString("vec2 noise2(vec2 x);")); + //s.append(TString("vec2 noise2(vec3 x);")); + //s.append(TString("vec2 noise2(vec4 x);")); + + //s.append(TString("vec3 noise3(float x);")); + //s.append(TString("vec3 noise3(vec2 x);")); + //s.append(TString("vec3 noise3(vec3 x);")); + //s.append(TString("vec3 noise3(vec4 x);")); + + //s.append(TString("vec4 noise4(float x);")); + //s.append(TString("vec4 noise4(vec2 x);")); + //s.append(TString("vec4 noise4(vec3 x);")); + //s.append(TString("vec4 noise4(vec4 x);")); + + return s; +} + +//============================================================================ +// +// Prototypes for built-in functions seen by vertex shaders only. +// +//============================================================================ +static TString BuiltInFunctionsVertex(const ShBuiltInResources& resources) +{ + TString s; + + // + // Geometric Functions. + // + //s.append(TString("vec4 ftransform();")); + + // + // Texture Functions. + // + s.append(TString("vec4 texture2DLod(sampler2D sampler, vec2 coord, float lod);")); + s.append(TString("vec4 texture2DProjLod(sampler2D sampler, vec3 coord, float lod);")); + s.append(TString("vec4 texture2DProjLod(sampler2D sampler, vec4 coord, float lod);")); + s.append(TString("vec4 textureCubeLod(samplerCube sampler, vec3 coord, float lod);")); + + return s; +} + +//============================================================================ +// +// Prototypes for built-in functions seen by fragment shaders only. +// +//============================================================================ +static TString BuiltInFunctionsFragment(const ShBuiltInResources& resources) +{ + TString s; + + // + // Texture Functions. + // + s.append(TString("vec4 texture2D(sampler2D sampler, vec2 coord, float bias);")); + s.append(TString("vec4 texture2DProj(sampler2D sampler, vec3 coord, float bias);")); + s.append(TString("vec4 texture2DProj(sampler2D sampler, vec4 coord, float bias);")); + s.append(TString("vec4 textureCube(samplerCube sampler, vec3 coord, float bias);")); + + if (resources.OES_standard_derivatives) + { + s.append(TString("float dFdx(float p);")); + s.append(TString("vec2 dFdx(vec2 p);")); + s.append(TString("vec3 dFdx(vec3 p);")); + s.append(TString("vec4 dFdx(vec4 p);")); + + s.append(TString("float dFdy(float p);")); + s.append(TString("vec2 dFdy(vec2 p);")); + s.append(TString("vec3 dFdy(vec3 p);")); + s.append(TString("vec4 dFdy(vec4 p);")); + + s.append(TString("float fwidth(float p);")); + s.append(TString("vec2 fwidth(vec2 p);")); + s.append(TString("vec3 fwidth(vec3 p);")); + s.append(TString("vec4 fwidth(vec4 p);")); + } + + return s; +} + +//============================================================================ +// +// Standard uniforms. +// +//============================================================================ +static TString StandardUniforms() +{ + TString s; + + // + // Depth range in window coordinates + // + s.append(TString("struct gl_DepthRangeParameters {")); + s.append(TString(" highp float near;")); // n + s.append(TString(" highp float far;")); // f + s.append(TString(" highp float diff;")); // f - n + s.append(TString("};")); + s.append(TString("uniform gl_DepthRangeParameters gl_DepthRange;")); + + return s; +} + +//============================================================================ +// +// Default precision for vertex shaders. +// +//============================================================================ +static TString DefaultPrecisionVertex() +{ + TString s; + + s.append(TString("precision highp int;")); + s.append(TString("precision highp float;")); + + return s; +} + +//============================================================================ +// +// Default precision for fragment shaders. +// +//============================================================================ +static TString DefaultPrecisionFragment() +{ + TString s; + + s.append(TString("precision mediump int;")); + // No default precision for float in fragment shaders + + return s; +} + +//============================================================================ +// +// Implementation dependent built-in constants. +// +//============================================================================ +static TString BuiltInConstants(const ShBuiltInResources &resources) +{ + TStringStream s; + + s << "const int gl_MaxVertexAttribs = " << resources.MaxVertexAttribs << ";"; + s << "const int gl_MaxVertexUniformVectors = " << resources.MaxVertexUniformVectors << ";"; + + s << "const int gl_MaxVaryingVectors = " << resources.MaxVaryingVectors << ";"; + s << "const int gl_MaxVertexTextureImageUnits = " << resources.MaxVertexTextureImageUnits << ";"; + s << "const int gl_MaxCombinedTextureImageUnits = " << resources.MaxCombinedTextureImageUnits << ";"; + s << "const int gl_MaxTextureImageUnits = " << resources.MaxTextureImageUnits << ";"; + s << "const int gl_MaxFragmentUniformVectors = " << resources.MaxFragmentUniformVectors << ";"; + s << "const int gl_MaxDrawBuffers = " << resources.MaxDrawBuffers << ";"; + + return s.str(); +} + +void TBuiltIns::initialize(ShShaderType type, ShShaderSpec spec, + const ShBuiltInResources& resources) +{ + switch (type) { + case SH_FRAGMENT_SHADER: + builtInStrings.push_back(DefaultPrecisionFragment()); + builtInStrings.push_back(BuiltInFunctionsCommon()); + builtInStrings.push_back(BuiltInFunctionsFragment(resources)); + builtInStrings.push_back(StandardUniforms()); + break; + + case SH_VERTEX_SHADER: + builtInStrings.push_back(DefaultPrecisionVertex()); + builtInStrings.push_back(BuiltInFunctionsCommon()); + builtInStrings.push_back(BuiltInFunctionsVertex(resources)); + builtInStrings.push_back(StandardUniforms()); + break; + + default: assert(false && "Language not supported"); + } + + builtInStrings.push_back(BuiltInConstants(resources)); +} + +void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec, + const ShBuiltInResources& resources, + TSymbolTable& symbolTable) +{ + // + // First, insert some special built-in variables that are not in + // the built-in header files. + // + switch(type) { + case SH_FRAGMENT_SHADER: + symbolTable.insert(*new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EbpMedium, EvqFragCoord, 4))); + symbolTable.insert(*new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool, EbpUndefined, EvqFrontFacing, 1))); + symbolTable.insert(*new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EbpMedium, EvqFragColor, 4))); + symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqFragData, 4))); + symbolTable.insert(*new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EbpMedium, EvqPointCoord, 2))); + break; + case SH_VERTEX_SHADER: + symbolTable.insert(*new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EbpHigh, EvqPosition, 4))); + symbolTable.insert(*new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EbpMedium, EvqPointSize, 1))); + break; + default: assert(false && "Language not supported"); + } + + // + // Next, identify which built-ins from the already loaded headers have + // a mapping to an operator. Those that are not identified as such are + // expected to be resolved through a library of functions, versus as + // operations. + // + symbolTable.relateToOperator("not", EOpVectorLogicalNot); + + symbolTable.relateToOperator("matrixCompMult", EOpMul); + + symbolTable.relateToOperator("equal", EOpVectorEqual); + symbolTable.relateToOperator("notEqual", EOpVectorNotEqual); + symbolTable.relateToOperator("lessThan", EOpLessThan); + symbolTable.relateToOperator("greaterThan", EOpGreaterThan); + symbolTable.relateToOperator("lessThanEqual", EOpLessThanEqual); + symbolTable.relateToOperator("greaterThanEqual", EOpGreaterThanEqual); + + symbolTable.relateToOperator("radians", EOpRadians); + symbolTable.relateToOperator("degrees", EOpDegrees); + symbolTable.relateToOperator("sin", EOpSin); + symbolTable.relateToOperator("cos", EOpCos); + symbolTable.relateToOperator("tan", EOpTan); + symbolTable.relateToOperator("asin", EOpAsin); + symbolTable.relateToOperator("acos", EOpAcos); + symbolTable.relateToOperator("atan", EOpAtan); + + symbolTable.relateToOperator("pow", EOpPow); + symbolTable.relateToOperator("exp2", EOpExp2); + symbolTable.relateToOperator("log", EOpLog); + symbolTable.relateToOperator("exp", EOpExp); + symbolTable.relateToOperator("log2", EOpLog2); + symbolTable.relateToOperator("sqrt", EOpSqrt); + symbolTable.relateToOperator("inversesqrt", EOpInverseSqrt); + + symbolTable.relateToOperator("abs", EOpAbs); + symbolTable.relateToOperator("sign", EOpSign); + symbolTable.relateToOperator("floor", EOpFloor); + symbolTable.relateToOperator("ceil", EOpCeil); + symbolTable.relateToOperator("fract", EOpFract); + symbolTable.relateToOperator("mod", EOpMod); + symbolTable.relateToOperator("min", EOpMin); + symbolTable.relateToOperator("max", EOpMax); + symbolTable.relateToOperator("clamp", EOpClamp); + symbolTable.relateToOperator("mix", EOpMix); + symbolTable.relateToOperator("step", EOpStep); + symbolTable.relateToOperator("smoothstep", EOpSmoothStep); + + symbolTable.relateToOperator("length", EOpLength); + symbolTable.relateToOperator("distance", EOpDistance); + symbolTable.relateToOperator("dot", EOpDot); + symbolTable.relateToOperator("cross", EOpCross); + symbolTable.relateToOperator("normalize", EOpNormalize); + symbolTable.relateToOperator("faceforward", EOpFaceForward); + symbolTable.relateToOperator("reflect", EOpReflect); + symbolTable.relateToOperator("refract", EOpRefract); + + symbolTable.relateToOperator("any", EOpAny); + symbolTable.relateToOperator("all", EOpAll); + + // Map language-specific operators. + switch(type) { + case SH_VERTEX_SHADER: + break; + case SH_FRAGMENT_SHADER: + if (resources.OES_standard_derivatives) { + symbolTable.relateToOperator("dFdx", EOpDFdx); + symbolTable.relateToOperator("dFdy", EOpDFdy); + symbolTable.relateToOperator("fwidth", EOpFwidth); + + symbolTable.relateToExtension("dFdx", "GL_OES_standard_derivatives"); + symbolTable.relateToExtension("dFdy", "GL_OES_standard_derivatives"); + symbolTable.relateToExtension("fwidth", "GL_OES_standard_derivatives"); + } + break; + default: break; + } + + // Finally add resource-specific variables. + switch(type) + { + case SH_FRAGMENT_SHADER: + { + // Set up gl_FragData. The array size. + TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, false, true); + fragData.setArraySize(resources.MaxDrawBuffers); + symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"), fragData)); + } + break; + default: break; + } +} + +void InitExtensionBehavior(const ShBuiltInResources& resources, + TExtensionBehavior& extBehavior) +{ + if (resources.OES_standard_derivatives) + extBehavior["GL_OES_standard_derivatives"] = EBhUndefined; +}
diff --git a/src/GLES2/compiler/Initialize.h b/src/GLES2/compiler/Initialize.h new file mode 100644 index 0000000..8b0adc6 --- /dev/null +++ b/src/GLES2/compiler/Initialize.h
@@ -0,0 +1,35 @@ +// +// 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. +// + +#ifndef _INITIALIZE_INCLUDED_ +#define _INITIALIZE_INCLUDED_ + +#include "compiler/Common.h" +#include "compiler/ShHandle.h" +#include "compiler/SymbolTable.h" + +typedef TVector<TString> TBuiltInStrings; + +class TBuiltIns { +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + + void initialize(ShShaderType type, ShShaderSpec spec, + const ShBuiltInResources& resources); + const TBuiltInStrings& getBuiltInStrings() { return builtInStrings; } + +protected: + TBuiltInStrings builtInStrings; +}; + +void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec, + const ShBuiltInResources& resources, + TSymbolTable& symbolTable); + +void InitExtensionBehavior(const ShBuiltInResources& resources, + TExtensionBehavior& extensionBehavior); + +#endif // _INITIALIZE_INCLUDED_
diff --git a/src/GLES2/compiler/InitializeDll.cpp b/src/GLES2/compiler/InitializeDll.cpp new file mode 100644 index 0000000..8763cfe --- /dev/null +++ b/src/GLES2/compiler/InitializeDll.cpp
@@ -0,0 +1,115 @@ +// +// 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/InitializeDll.h" + +#include "compiler/InitializeGlobals.h" +#include "compiler/InitializeParseContext.h" +#include "compiler/osinclude.h" + +OS_TLSIndex ThreadInitializeIndex = OS_INVALID_TLS_INDEX; + +bool InitProcess() +{ + if (ThreadInitializeIndex != OS_INVALID_TLS_INDEX) { + // + // Function is re-entrant. + // + return true; + } + + ThreadInitializeIndex = OS_AllocTLSIndex(); + + if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "InitProcess(): Failed to allocate TLS area for init flag"); + return false; + } + + + if (!InitializePoolIndex()) { + assert(0 && "InitProcess(): Failed to initalize global pool"); + return false; + } + + if (!InitializeParseContextIndex()) { + assert(0 && "InitProcess(): Failed to initalize parse context"); + return false; + } + + return InitThread(); +} + +bool DetachProcess() +{ + bool success = true; + + if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) + return true; + + success = DetachThread(); + + if (!FreeParseContextIndex()) + success = false; + + FreePoolIndex(); + + OS_FreeTLSIndex(ThreadInitializeIndex); + ThreadInitializeIndex = OS_INVALID_TLS_INDEX; + + return success; +} + +bool InitThread() +{ + // + // This function is re-entrant + // + if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "InitThread(): Process hasn't been initalised."); + return false; + } + + if (OS_GetTLSValue(ThreadInitializeIndex) != 0) + return true; + + InitializeGlobalPools(); + + if (!InitializeGlobalParseContext()) + return false; + + if (!OS_SetTLSValue(ThreadInitializeIndex, (void *)1)) { + assert(0 && "InitThread(): Unable to set init flag."); + return false; + } + + return true; +} + +bool DetachThread() +{ + bool success = true; + + if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) + return true; + + // + // Function is re-entrant and this thread may not have been initalised. + // + if (OS_GetTLSValue(ThreadInitializeIndex) != 0) { + if (!OS_SetTLSValue(ThreadInitializeIndex, (void *)0)) { + assert(0 && "DetachThread(): Unable to clear init flag."); + success = false; + } + + if (!FreeParseContext()) + success = false; + + FreeGlobalPools(); + } + + return success; +} +
diff --git a/src/GLES2/compiler/InitializeDll.h b/src/GLES2/compiler/InitializeDll.h new file mode 100644 index 0000000..857238e --- /dev/null +++ b/src/GLES2/compiler/InitializeDll.h
@@ -0,0 +1,16 @@ +// +// 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. +// +#ifndef __INITIALIZEDLL_H +#define __INITIALIZEDLL_H + +bool InitProcess(); +bool DetachProcess(); + +bool InitThread(); +bool DetachThread(); + +#endif // __INITIALIZEDLL_H +
diff --git a/src/GLES2/compiler/InitializeGlobals.h b/src/GLES2/compiler/InitializeGlobals.h new file mode 100644 index 0000000..842a452 --- /dev/null +++ b/src/GLES2/compiler/InitializeGlobals.h
@@ -0,0 +1,15 @@ +// +// 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. +// + +#ifndef __INITIALIZE_GLOBALS_INCLUDED_ +#define __INITIALIZE_GLOBALS_INCLUDED_ + +void InitializeGlobalPools(); +void FreeGlobalPools(); +bool InitializePoolIndex(); +void FreePoolIndex(); + +#endif // __INITIALIZE_GLOBALS_INCLUDED_
diff --git a/src/GLES2/compiler/InitializeParseContext.cpp b/src/GLES2/compiler/InitializeParseContext.cpp new file mode 100644 index 0000000..1f40cf5 --- /dev/null +++ b/src/GLES2/compiler/InitializeParseContext.cpp
@@ -0,0 +1,96 @@ +// +// Copyright (c) 2012 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/InitializeParseContext.h" + +#include "compiler/osinclude.h" + +OS_TLSIndex GlobalParseContextIndex = OS_INVALID_TLS_INDEX; + +bool InitializeParseContextIndex() +{ + if (GlobalParseContextIndex != OS_INVALID_TLS_INDEX) { + assert(0 && "InitializeParseContextIndex(): Parse Context already initalized"); + return false; + } + + // + // Allocate a TLS index. + // + GlobalParseContextIndex = OS_AllocTLSIndex(); + + if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "InitializeParseContextIndex(): Parse Context already initalized"); + return false; + } + + return true; +} + +bool FreeParseContextIndex() +{ + OS_TLSIndex tlsiIndex = GlobalParseContextIndex; + + if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "FreeParseContextIndex(): Parse Context index not initalized"); + return false; + } + + GlobalParseContextIndex = OS_INVALID_TLS_INDEX; + + return OS_FreeTLSIndex(tlsiIndex); +} + +bool InitializeGlobalParseContext() +{ + if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "InitializeGlobalParseContext(): Parse Context index not initalized"); + return false; + } + + TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex)); + if (lpParseContext != 0) { + assert(0 && "InitializeParseContextIndex(): Parse Context already initalized"); + return false; + } + + TThreadParseContext *lpThreadData = new TThreadParseContext(); + if (lpThreadData == 0) { + assert(0 && "InitializeGlobalParseContext(): Unable to create thread parse context"); + return false; + } + + lpThreadData->lpGlobalParseContext = 0; + OS_SetTLSValue(GlobalParseContextIndex, lpThreadData); + + return true; +} + +bool FreeParseContext() +{ + if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "FreeParseContext(): Parse Context index not initalized"); + return false; + } + + TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex)); + if (lpParseContext) + delete lpParseContext; + + return true; +} + +TParseContextPointer& GetGlobalParseContext() +{ + // + // Minimal error checking for speed + // + + TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex)); + + return lpParseContext->lpGlobalParseContext; +} +
diff --git a/src/GLES2/compiler/InitializeParseContext.h b/src/GLES2/compiler/InitializeParseContext.h new file mode 100644 index 0000000..354bfe1 --- /dev/null +++ b/src/GLES2/compiler/InitializeParseContext.h
@@ -0,0 +1,26 @@ +// +// Copyright (c) 2002-2012 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. +// + +#ifndef __INITIALIZE_PARSE_CONTEXT_INCLUDED_ +#define __INITIALIZE_PARSE_CONTEXT_INCLUDED_ + +bool InitializeParseContextIndex(); +bool FreeParseContextIndex(); + +bool InitializeGlobalParseContext(); +bool FreeParseContext(); + +struct TParseContext; +typedef TParseContext* TParseContextPointer; +extern TParseContextPointer& GetGlobalParseContext(); +#define GlobalParseContext GetGlobalParseContext() + +typedef struct TThreadParseContextRec +{ + TParseContext *lpGlobalParseContext; +} TThreadParseContext; + +#endif // __INITIALIZE_PARSE_CONTEXT_INCLUDED_
diff --git a/src/GLES2/compiler/IntermTraverse.cpp b/src/GLES2/compiler/IntermTraverse.cpp new file mode 100644 index 0000000..a13877f --- /dev/null +++ b/src/GLES2/compiler/IntermTraverse.cpp
@@ -0,0 +1,293 @@ +// +// 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/intermediate.h" + +// +// Traverse the intermediate representation tree, and +// call a node type specific function for each node. +// Done recursively through the member function Traverse(). +// Node types can be skipped if their function to call is 0, +// but their subtree will still be traversed. +// Nodes with children can have their whole subtree skipped +// if preVisit is turned on and the type specific function +// returns false. +// +// preVisit, postVisit, and rightToLeft control what order +// nodes are visited in. +// + +// +// Traversal functions for terminals are straighforward.... +// +void TIntermSymbol::traverse(TIntermTraverser* it) +{ + it->visitSymbol(this); +} + +void TIntermConstantUnion::traverse(TIntermTraverser* it) +{ + it->visitConstantUnion(this); +} + +// +// Traverse a binary node. +// +void TIntermBinary::traverse(TIntermTraverser* it) +{ + bool visit = true; + + // + // visit the node before children if pre-visiting. + // + if(it->preVisit) + { + visit = it->visitBinary(PreVisit, this); + } + + // + // Visit the children, in the right order. + // + if(visit) + { + it->incrementDepth(); + + if(it->rightToLeft) + { + if(right) + { + right->traverse(it); + } + + if(it->inVisit) + { + visit = it->visitBinary(InVisit, this); + } + + if(visit && left) + { + left->traverse(it); + } + } + else + { + if(left) + { + left->traverse(it); + } + + if(it->inVisit) + { + visit = it->visitBinary(InVisit, this); + } + + if(visit && right) + { + right->traverse(it); + } + } + + it->decrementDepth(); + } + + // + // Visit the node after the children, if requested and the traversal + // hasn't been cancelled yet. + // + if(visit && it->postVisit) + { + it->visitBinary(PostVisit, this); + } +} + +// +// Traverse a unary node. Same comments in binary node apply here. +// +void TIntermUnary::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if (it->preVisit) + visit = it->visitUnary(PreVisit, this); + + if (visit) { + it->incrementDepth(); + operand->traverse(it); + it->decrementDepth(); + } + + if (visit && it->postVisit) + it->visitUnary(PostVisit, this); +} + +// +// Traverse an aggregate node. Same comments in binary node apply here. +// +void TIntermAggregate::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if(it->preVisit) + { + visit = it->visitAggregate(PreVisit, this); + } + + if(visit) + { + it->incrementDepth(); + + if(it->rightToLeft) + { + for(TIntermSequence::reverse_iterator sit = sequence.rbegin(); sit != sequence.rend(); sit++) + { + (*sit)->traverse(it); + + if(visit && it->inVisit) + { + if(*sit != sequence.front()) + { + visit = it->visitAggregate(InVisit, this); + } + } + } + } + else + { + for(TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) + { + (*sit)->traverse(it); + + if(visit && it->inVisit) + { + if(*sit != sequence.back()) + { + visit = it->visitAggregate(InVisit, this); + } + } + } + } + + it->decrementDepth(); + } + + if(visit && it->postVisit) + { + it->visitAggregate(PostVisit, this); + } +} + +// +// Traverse a selection node. Same comments in binary node apply here. +// +void TIntermSelection::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if (it->preVisit) + visit = it->visitSelection(PreVisit, this); + + if (visit) { + it->incrementDepth(); + if (it->rightToLeft) { + if (falseBlock) + falseBlock->traverse(it); + if (trueBlock) + trueBlock->traverse(it); + condition->traverse(it); + } else { + condition->traverse(it); + if (trueBlock) + trueBlock->traverse(it); + if (falseBlock) + falseBlock->traverse(it); + } + it->decrementDepth(); + } + + if (visit && it->postVisit) + it->visitSelection(PostVisit, this); +} + +// +// Traverse a loop node. Same comments in binary node apply here. +// +void TIntermLoop::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if(it->preVisit) + { + visit = it->visitLoop(PreVisit, this); + } + + if(visit) + { + it->incrementDepth(); + + if(it->rightToLeft) + { + if(expr) + { + expr->traverse(it); + } + + if(body) + { + body->traverse(it); + } + + if(cond) + { + cond->traverse(it); + } + } + else + { + if(cond) + { + cond->traverse(it); + } + + if(body) + { + body->traverse(it); + } + + if(expr) + { + expr->traverse(it); + } + } + + it->decrementDepth(); + } + + if(visit && it->postVisit) + { + it->visitLoop(PostVisit, this); + } +} + +// +// Traverse a branch node. Same comments in binary node apply here. +// +void TIntermBranch::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if (it->preVisit) + visit = it->visitBranch(PreVisit, this); + + if (visit && expression) { + it->incrementDepth(); + expression->traverse(it); + it->decrementDepth(); + } + + if (visit && it->postVisit) + it->visitBranch(PostVisit, this); +} +
diff --git a/src/GLES2/compiler/Intermediate.cpp b/src/GLES2/compiler/Intermediate.cpp new file mode 100644 index 0000000..5ef2789 --- /dev/null +++ b/src/GLES2/compiler/Intermediate.cpp
@@ -0,0 +1,1452 @@ +// +// Copyright (c) 2002-2012 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. +// + +// +// Build the intermediate representation. +// + +#include <float.h> +#include <limits.h> +#include <algorithm> + +#include "compiler/localintermediate.h" +#include "compiler/QualifierAlive.h" +#include "compiler/RemoveTree.h" + +bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray); + +static TPrecision GetHigherPrecision( TPrecision left, TPrecision right ){ + return left > right ? left : right; +} + +const char* getOperatorString(TOperator op) { + switch (op) { + case EOpInitialize: return "="; + case EOpAssign: return "="; + case EOpAddAssign: return "+="; + case EOpSubAssign: return "-="; + case EOpDivAssign: return "/="; + + // Fall-through. + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: return "*="; + + // Fall-through. + case EOpIndexDirect: + case EOpIndexIndirect: return "[]"; + + case EOpIndexDirectStruct: return "."; + case EOpVectorSwizzle: return "."; + case EOpAdd: return "+"; + case EOpSub: return "-"; + case EOpMul: return "*"; + case EOpDiv: return "/"; + case EOpMod: UNIMPLEMENTED(); break; + case EOpEqual: return "=="; + case EOpNotEqual: return "!="; + case EOpLessThan: return "<"; + case EOpGreaterThan: return ">"; + case EOpLessThanEqual: return "<="; + case EOpGreaterThanEqual: return ">="; + + // Fall-through. + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: + case EOpMatrixTimesMatrix: return "*"; + + case EOpLogicalOr: return "||"; + case EOpLogicalXor: return "^^"; + case EOpLogicalAnd: return "&&"; + case EOpNegative: return "-"; + case EOpVectorLogicalNot: return "not"; + case EOpLogicalNot: return "!"; + case EOpPostIncrement: return "++"; + case EOpPostDecrement: return "--"; + case EOpPreIncrement: return "++"; + case EOpPreDecrement: return "--"; + + // Fall-through. + case EOpConvIntToBool: + case EOpConvFloatToBool: return "bool"; + + // Fall-through. + case EOpConvBoolToFloat: + case EOpConvIntToFloat: return "float"; + + // Fall-through. + case EOpConvFloatToInt: + case EOpConvBoolToInt: return "int"; + + case EOpRadians: return "radians"; + case EOpDegrees: return "degrees"; + case EOpSin: return "sin"; + case EOpCos: return "cos"; + case EOpTan: return "tan"; + case EOpAsin: return "asin"; + case EOpAcos: return "acos"; + case EOpAtan: return "atan"; + case EOpExp: return "exp"; + case EOpLog: return "log"; + case EOpExp2: return "exp2"; + case EOpLog2: return "log2"; + case EOpSqrt: return "sqrt"; + case EOpInverseSqrt: return "inversesqrt"; + case EOpAbs: return "abs"; + case EOpSign: return "sign"; + case EOpFloor: return "floor"; + case EOpCeil: return "ceil"; + case EOpFract: return "fract"; + case EOpLength: return "length"; + case EOpNormalize: return "normalize"; + case EOpDFdx: return "dFdx"; + case EOpDFdy: return "dFdy"; + case EOpFwidth: return "fwidth"; + case EOpAny: return "any"; + case EOpAll: return "all"; + + default: break; + } + return ""; +} + +//////////////////////////////////////////////////////////////////////////// +// +// First set of functions are to help build the intermediate representation. +// These functions are not member functions of the nodes. +// They are called from parser productions. +// +///////////////////////////////////////////////////////////////////////////// + +// +// Add a terminal node for an identifier in an expression. +// +// Returns the added node. +// +TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, TSourceLoc line) +{ + TIntermSymbol* node = new TIntermSymbol(id, name, type); + node->setLine(line); + + return node; +} + +// +// Connect two nodes with a new parent that does a binary operation on the nodes. +// +// Returns the added node. +// +TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line, TSymbolTable& symbolTable) +{ + switch (op) { + case EOpEqual: + case EOpNotEqual: + if (left->isArray()) + return 0; + break; + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) { + return 0; + } + break; + case EOpLogicalOr: + case EOpLogicalXor: + case EOpLogicalAnd: + if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) { + return 0; + } + break; + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpMul: + if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) + return 0; + default: break; + } + + // + // First try converting the children to compatible types. + // + if (left->getType().getStruct() && right->getType().getStruct()) { + if (left->getType() != right->getType()) + return 0; + } else { + TIntermTyped* child = addConversion(op, left->getType(), right); + if (child) + right = child; + else { + child = addConversion(op, right->getType(), left); + if (child) + left = child; + else + return 0; + } + } + + // + // Need a new node holding things together then. Make + // one and promote it to the right type. + // + TIntermBinary* node = new TIntermBinary(op); + if (line == 0) + line = right->getLine(); + node->setLine(line); + + node->setLeft(left); + node->setRight(right); + if (!node->promote(infoSink)) + return 0; + + // + // See if we can fold constants. + // + TIntermTyped* typedReturnNode = 0; + TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion(); + TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion(); + if (leftTempConstant && rightTempConstant) { + typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink); + + if (typedReturnNode) + return typedReturnNode; + } + + return node; +} + +// +// Connect two nodes through an assignment. +// +// Returns the added node. +// +TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line) +{ + // + // Like adding binary math, except the conversion can only go + // from right to left. + // + TIntermBinary* node = new TIntermBinary(op); + if (line == 0) + line = left->getLine(); + node->setLine(line); + + TIntermTyped* child = addConversion(op, left->getType(), right); + if (child == 0) + return 0; + + node->setLeft(left); + node->setRight(child); + if (! node->promote(infoSink)) + return 0; + + return node; +} + +// +// Connect two nodes through an index operator, where the left node is the base +// of an array or struct, and the right node is a direct or indirect offset. +// +// Returns the added node. +// The caller should set the type of the returned node. +// +TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc line) +{ + TIntermBinary* node = new TIntermBinary(op); + if (line == 0) + line = index->getLine(); + node->setLine(line); + node->setLeft(base); + node->setRight(index); + + // caller should set the type + + return node; +} + +// +// Add one node as the parent of another that it operates on. +// +// Returns the added node. +// +TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, TSourceLoc line, TSymbolTable& symbolTable) +{ + TIntermUnary* node; + TIntermTyped* child = childNode->getAsTyped(); + + if (child == 0) { + infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath", line); + return 0; + } + + switch (op) { + case EOpLogicalNot: + if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) { + return 0; + } + break; + + case EOpPostIncrement: + case EOpPreIncrement: + case EOpPostDecrement: + case EOpPreDecrement: + case EOpNegative: + if (child->getType().getBasicType() == EbtStruct || child->getType().isArray()) + return 0; + default: break; + } + + // + // Do we need to promote the operand? + // + // Note: Implicit promotions were removed from the language. + // + TBasicType newType = EbtVoid; + switch (op) { + case EOpConstructInt: newType = EbtInt; break; + case EOpConstructBool: newType = EbtBool; break; + case EOpConstructFloat: newType = EbtFloat; break; + default: break; + } + + if (newType != EbtVoid) { + child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary, + child->getNominalSize(), + child->isMatrix(), + child->isArray()), + child); + if (child == 0) + return 0; + } + + // + // For constructors, we are now done, it's all in the conversion. + // + switch (op) { + case EOpConstructInt: + case EOpConstructBool: + case EOpConstructFloat: + return child; + default: break; + } + + TIntermConstantUnion *childTempConstant = 0; + if (child->getAsConstantUnion()) + childTempConstant = child->getAsConstantUnion(); + + // + // Make a new node for the operator. + // + node = new TIntermUnary(op); + if (line == 0) + line = child->getLine(); + node->setLine(line); + node->setOperand(child); + + if (! node->promote(infoSink)) + return 0; + + if (childTempConstant) { + TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink); + + if (newChild) + return newChild; + } + + return node; +} + +// +// This is the safe way to change the operator on an aggregate, as it +// does lots of error checking and fixing. Especially for establishing +// a function call's operation on it's set of parameters. Sequences +// of instructions are also aggregates, but they just direnctly set +// their operator to EOpSequence. +// +// Returns an aggregate node, which could be the one passed in if +// it was already an aggregate but no operator was set. +// +TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, TSourceLoc line) +{ + TIntermAggregate* aggNode; + + // + // Make sure we have an aggregate. If not turn it into one. + // + if (node) { + aggNode = node->getAsAggregate(); + if (aggNode == 0 || aggNode->getOp() != EOpNull) { + // + // Make an aggregate containing this node. + // + aggNode = new TIntermAggregate(); + aggNode->getSequence().push_back(node); + if (line == 0) + line = node->getLine(); + } + } else + aggNode = new TIntermAggregate(); + + // + // Set the operator. + // + aggNode->setOp(op); + if (line != 0) + aggNode->setLine(line); + + return aggNode; +} + +// +// Convert one type to another. +// +// Returns the node representing the conversion, which could be the same +// node passed in if no conversion was needed. +// +// Return 0 if a conversion can't be done. +// +TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) +{ + // + // Does the base type allow operation? + // + switch (node->getBasicType()) { + case EbtVoid: + case EbtSampler2D: + case EbtSamplerCube: + return 0; + default: break; + } + + // + // Otherwise, if types are identical, no problem + // + if (type == node->getType()) + return node; + + // + // If one's a structure, then no conversions. + // + if (type.getStruct() || node->getType().getStruct()) + return 0; + + // + // If one's an array, then no conversions. + // + if (type.isArray() || node->getType().isArray()) + return 0; + + TBasicType promoteTo; + + switch (op) { + // + // Explicit conversions + // + case EOpConstructBool: + promoteTo = EbtBool; + break; + case EOpConstructFloat: + promoteTo = EbtFloat; + break; + case EOpConstructInt: + promoteTo = EbtInt; + break; + default: + // + // implicit conversions were removed from the language. + // + if (type.getBasicType() != node->getType().getBasicType()) + return 0; + // + // Size and structure could still differ, but that's + // handled by operator promotion. + // + return node; + } + + if (node->getAsConstantUnion()) { + + return (promoteConstantUnion(promoteTo, node->getAsConstantUnion())); + } else { + + // + // Add a new newNode for the conversion. + // + TIntermUnary* newNode = 0; + + TOperator newOp = EOpNull; + switch (promoteTo) { + case EbtFloat: + switch (node->getBasicType()) { + case EbtInt: newOp = EOpConvIntToFloat; break; + case EbtBool: newOp = EOpConvBoolToFloat; break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); + return 0; + } + break; + case EbtBool: + switch (node->getBasicType()) { + case EbtInt: newOp = EOpConvIntToBool; break; + case EbtFloat: newOp = EOpConvFloatToBool; break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); + return 0; + } + break; + case EbtInt: + switch (node->getBasicType()) { + case EbtBool: newOp = EOpConvBoolToInt; break; + case EbtFloat: newOp = EOpConvFloatToInt; break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); + return 0; + } + break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion type", node->getLine()); + return 0; + } + + TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray()); + newNode = new TIntermUnary(newOp, type); + newNode->setLine(node->getLine()); + newNode->setOperand(node); + + return newNode; + } +} + +// +// Safe way to combine two nodes into an aggregate. Works with null pointers, +// a node that's not a aggregate yet, etc. +// +// Returns the resulting aggregate, unless 0 was passed in for +// both existing nodes. +// +TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, TSourceLoc line) +{ + if (left == 0 && right == 0) + return 0; + + TIntermAggregate* aggNode = 0; + if (left) + aggNode = left->getAsAggregate(); + if (!aggNode || aggNode->getOp() != EOpNull) { + aggNode = new TIntermAggregate; + if (left) + aggNode->getSequence().push_back(left); + } + + if (right) + aggNode->getSequence().push_back(right); + + if (line != 0) + aggNode->setLine(line); + + return aggNode; +} + +// +// Turn an existing node into an aggregate. +// +// Returns an aggregate, unless 0 was passed in for the existing node. +// +TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, TSourceLoc line) +{ + if (node == 0) + return 0; + + TIntermAggregate* aggNode = new TIntermAggregate; + aggNode->getSequence().push_back(node); + + if (line != 0) + aggNode->setLine(line); + else + aggNode->setLine(node->getLine()); + + return aggNode; +} + +// +// For "if" test nodes. There are three children; a condition, +// a true path, and a false path. The two paths are in the +// nodePair. +// +// Returns the selection node created. +// +TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, TSourceLoc line) +{ + // + // For compile time constant selections, prune the code and + // test now. + // + + if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) { + if (cond->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->getBConst() == true) + return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL; + else + return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL; + } + + TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2); + node->setLine(line); + + return node; +} + + +TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc line) +{ + if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) { + return right; + } else { + TIntermTyped *commaAggregate = growAggregate(left, right, line); + commaAggregate->getAsAggregate()->setOp(EOpComma); + commaAggregate->setType(right->getType()); + commaAggregate->getTypePointer()->setQualifier(EvqTemporary); + return commaAggregate; + } +} + +// +// For "?:" test nodes. There are three children; a condition, +// a true path, and a false path. The two paths are specified +// as separate parameters. +// +// Returns the selection node created, or 0 if one could not be. +// +TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc line) +{ + // + // Get compatible types. + // + TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock); + if (child) + falseBlock = child; + else { + child = addConversion(EOpSequence, falseBlock->getType(), trueBlock); + if (child) + trueBlock = child; + else + return 0; + } + + // + // See if all the operands are constant, then fold it otherwise not. + // + + if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) { + if (cond->getAsConstantUnion()->getUnionArrayPointer()->getBConst()) + return trueBlock; + else + return falseBlock; + } + + // + // Make a selection node. + // + TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType()); + node->getTypePointer()->setQualifier(EvqTemporary); + node->setLine(line); + + return node; +} + +// +// Constant terminal nodes. Has a union that contains bool, float or int constants +// +// Returns the constant union node created. +// + +TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, TSourceLoc line) +{ + TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t); + node->setLine(line); + + return node; +} + +TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, TSourceLoc line) +{ + + TIntermAggregate* node = new TIntermAggregate(EOpSequence); + + node->setLine(line); + TIntermConstantUnion* constIntNode; + TIntermSequence &sequenceVector = node->getSequence(); + ConstantUnion* unionArray; + + for (int i = 0; i < fields.num; i++) { + unionArray = new ConstantUnion[1]; + unionArray->setIConst(fields.offsets[i]); + constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line); + sequenceVector.push_back(constIntNode); + } + + return node; +} + +// +// Create loop nodes. +// +TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, TSourceLoc line) +{ + TIntermNode* node = new TIntermLoop(type, init, cond, expr, body); + node->setLine(line); + + return node; +} + +// +// Add branches. +// +TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TSourceLoc line) +{ + return addBranch(branchOp, 0, line); +} + +TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, TSourceLoc line) +{ + TIntermBranch* node = new TIntermBranch(branchOp, expression); + node->setLine(line); + + return node; +} + +// +// This is to be executed once the final root is put on top by the parsing +// process. +// +bool TIntermediate::postProcess(TIntermNode* root) +{ + if (root == 0) + return true; + + // + // First, finish off the top level sequence, if any + // + TIntermAggregate* aggRoot = root->getAsAggregate(); + if (aggRoot && aggRoot->getOp() == EOpNull) + aggRoot->setOp(EOpSequence); + + return true; +} + +// +// This deletes the tree. +// +void TIntermediate::remove(TIntermNode* root) +{ + if (root) + RemoveAllTreeNodes(root); +} + +//////////////////////////////////////////////////////////////// +// +// Member functions of the nodes used for building the tree. +// +//////////////////////////////////////////////////////////////// + +// +// Say whether or not an operation node changes the value of a variable. +// +// Returns true if state is modified. +// +bool TIntermOperator::modifiesState() const +{ + switch (op) { + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + case EOpAssign: + case EOpAddAssign: + case EOpSubAssign: + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + case EOpDivAssign: + return true; + default: + return false; + } +} + +// +// returns true if the operator is for one of the constructors +// +bool TIntermOperator::isConstructor() const +{ + switch (op) { + case EOpConstructVec2: + case EOpConstructVec3: + case EOpConstructVec4: + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: + case EOpConstructFloat: + case EOpConstructIVec2: + case EOpConstructIVec3: + case EOpConstructIVec4: + case EOpConstructInt: + case EOpConstructBVec2: + case EOpConstructBVec3: + case EOpConstructBVec4: + case EOpConstructBool: + case EOpConstructStruct: + return true; + default: + return false; + } +} +// +// Make sure the type of a unary operator is appropriate for its +// combination of operation and operand type. +// +// Returns false in nothing makes sense. +// +bool TIntermUnary::promote(TInfoSink&) +{ + switch (op) { + case EOpLogicalNot: + if (operand->getBasicType() != EbtBool) + return false; + break; + case EOpNegative: + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + if (operand->getBasicType() == EbtBool) + return false; + break; + + // operators for built-ins are already type checked against their prototype + case EOpAny: + case EOpAll: + case EOpVectorLogicalNot: + return true; + + default: + if (operand->getBasicType() != EbtFloat) + return false; + } + + setType(operand->getType()); + + // Unary operations results in temporary variables unless const. + if (operand->getQualifier() != EvqConst) { + getTypePointer()->setQualifier(EvqTemporary); + } + + return true; +} + +// +// Establishes the type of the resultant operation, as well as +// makes the operator the correct one for the operands. +// +// Returns false if operator can't work on operands. +// +bool TIntermBinary::promote(TInfoSink& infoSink) +{ + // This function only handles scalars, vectors, and matrices. + if (left->isArray() || right->isArray()) { + infoSink.info.message(EPrefixInternalError, "Invalid operation for arrays", getLine()); + return false; + } + + // GLSL ES 2.0 does not support implicit type casting. + // So the basic type should always match. + if (left->getBasicType() != right->getBasicType()) + return false; + + // + // Base assumption: just make the type the same as the left + // operand. Then only deviations from this need be coded. + // + setType(left->getType()); + + // The result gets promoted to the highest precision. + TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision()); + getTypePointer()->setPrecision(higherPrecision); + + // Binary operations results in temporary variables unless both + // operands are const. + if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst) { + getTypePointer()->setQualifier(EvqTemporary); + } + + int size = std::max(left->getNominalSize(), right->getNominalSize()); + + // + // All scalars. Code after this test assumes this case is removed! + // + if (size == 1) { + switch (op) { + // + // Promote to conditional + // + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + setType(TType(EbtBool, EbpUndefined)); + break; + + // + // And and Or operate on conditionals + // + case EOpLogicalAnd: + case EOpLogicalOr: + // Both operands must be of type bool. + if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool) + return false; + setType(TType(EbtBool, EbpUndefined)); + break; + + default: + break; + } + return true; + } + + // If we reach here, at least one of the operands is vector or matrix. + // The other operand could be a scalar, vector, or matrix. + // Are the sizes compatible? + // + if (left->getNominalSize() != right->getNominalSize()) { + // If the nominal size of operands do not match: + // One of them must be scalar. + if (left->getNominalSize() != 1 && right->getNominalSize() != 1) + return false; + // Operator cannot be of type pure assignment. + if (op == EOpAssign || op == EOpInitialize) + return false; + } + + // + // Can these two operands be combined? + // + TBasicType basicType = left->getBasicType(); + switch (op) { + case EOpMul: + if (!left->isMatrix() && right->isMatrix()) { + if (left->isVector()) + op = EOpVectorTimesMatrix; + else { + op = EOpMatrixTimesScalar; + setType(TType(basicType, higherPrecision, EvqTemporary, size, true)); + } + } else if (left->isMatrix() && !right->isMatrix()) { + if (right->isVector()) { + op = EOpMatrixTimesVector; + setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); + } else { + op = EOpMatrixTimesScalar; + } + } else if (left->isMatrix() && right->isMatrix()) { + op = EOpMatrixTimesMatrix; + } else if (!left->isMatrix() && !right->isMatrix()) { + if (left->isVector() && right->isVector()) { + // leave as component product + } else if (left->isVector() || right->isVector()) { + op = EOpVectorTimesScalar; + setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); + } + } else { + infoSink.info.message(EPrefixInternalError, "Missing elses", getLine()); + return false; + } + break; + case EOpMulAssign: + if (!left->isMatrix() && right->isMatrix()) { + if (left->isVector()) + op = EOpVectorTimesMatrixAssign; + else { + return false; + } + } else if (left->isMatrix() && !right->isMatrix()) { + if (right->isVector()) { + return false; + } else { + op = EOpMatrixTimesScalarAssign; + } + } else if (left->isMatrix() && right->isMatrix()) { + op = EOpMatrixTimesMatrixAssign; + } else if (!left->isMatrix() && !right->isMatrix()) { + if (left->isVector() && right->isVector()) { + // leave as component product + } else if (left->isVector() || right->isVector()) { + if (! left->isVector()) + return false; + op = EOpVectorTimesScalarAssign; + setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); + } + } else { + infoSink.info.message(EPrefixInternalError, "Missing elses", getLine()); + return false; + } + break; + + case EOpAssign: + case EOpInitialize: + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpAddAssign: + case EOpSubAssign: + case EOpDivAssign: + if ((left->isMatrix() && right->isVector()) || + (left->isVector() && right->isMatrix())) + return false; + setType(TType(basicType, higherPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix())); + break; + + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + if ((left->isMatrix() && right->isVector()) || + (left->isVector() && right->isMatrix())) + return false; + setType(TType(EbtBool, EbpUndefined)); + break; + + default: + return false; + } + + return true; +} + +bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray) +{ + const TTypeList* fields = leftNodeType.getStruct(); + + size_t structSize = fields->size(); + int index = 0; + + for (size_t j = 0; j < structSize; j++) { + int size = (*fields)[j].type->getObjectSize(); + for (int i = 0; i < size; i++) { + if ((*fields)[j].type->getBasicType() == EbtStruct) { + if (!CompareStructure(*(*fields)[j].type, &rightUnionArray[index], &leftUnionArray[index])) + return false; + } else { + if (leftUnionArray[index] != rightUnionArray[index]) + return false; + index++; + } + + } + } + return true; +} + +bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray) +{ + if (leftNodeType.isArray()) { + TType typeWithoutArrayness = leftNodeType; + typeWithoutArrayness.clearArrayness(); + + int arraySize = leftNodeType.getArraySize(); + + for (int i = 0; i < arraySize; ++i) { + int offset = typeWithoutArrayness.getObjectSize() * i; + if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset])) + return false; + } + } else + return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray); + + return true; +} + +// +// The fold functions see if an operation on a constant can be done in place, +// without generating run-time code. +// +// Returns the node to keep using, which may or may not be the node passed in. +// + +TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink) +{ + ConstantUnion *unionArray = getUnionArrayPointer(); + int objectSize = getType().getObjectSize(); + + if (constantNode) { // binary operations + TIntermConstantUnion *node = constantNode->getAsConstantUnion(); + ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); + TType returnType = getType(); + + // for a case like float f = 1.2 + vec4(2,3,4,5); + if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) { + rightUnionArray = new ConstantUnion[objectSize]; + for (int i = 0; i < objectSize; ++i) + rightUnionArray[i] = *node->getUnionArrayPointer(); + returnType = getType(); + } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) { + // for a case like float f = vec4(2,3,4,5) + 1.2; + unionArray = new ConstantUnion[constantNode->getType().getObjectSize()]; + for (int i = 0; i < constantNode->getType().getObjectSize(); ++i) + unionArray[i] = *getUnionArrayPointer(); + returnType = node->getType(); + objectSize = constantNode->getType().getObjectSize(); + } + + ConstantUnion* tempConstArray = 0; + TIntermConstantUnion *tempNode; + + bool boolNodeFlag = false; + switch(op) { + case EOpAdd: + tempConstArray = new ConstantUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] + rightUnionArray[i]; + } + break; + case EOpSub: + tempConstArray = new ConstantUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] - rightUnionArray[i]; + } + break; + + case EOpMul: + case EOpVectorTimesScalar: + case EOpMatrixTimesScalar: + tempConstArray = new ConstantUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] * rightUnionArray[i]; + } + break; + case EOpMatrixTimesMatrix: + if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) { + infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix multiply", getLine()); + return 0; + } + {// support MSVC++6.0 + int size = getNominalSize(); + tempConstArray = new ConstantUnion[size*size]; + for (int row = 0; row < size; row++) { + for (int column = 0; column < size; column++) { + tempConstArray[size * column + row].setFConst(0.0f); + for (int i = 0; i < size; i++) { + tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst())); + } + } + } + } + break; + case EOpDiv: + tempConstArray = new ConstantUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) { + switch (getType().getBasicType()) { + case EbtFloat: + if (rightUnionArray[i] == 0.0f) { + infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine()); + tempConstArray[i].setFConst(FLT_MAX); + } else + tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst()); + break; + + case EbtInt: + if (rightUnionArray[i] == 0) { + infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine()); + tempConstArray[i].setIConst(INT_MAX); + } else + tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst()); + break; + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"/\"", getLine()); + return 0; + } + } + } + break; + + case EOpMatrixTimesVector: + if (node->getBasicType() != EbtFloat) { + infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix times vector", getLine()); + return 0; + } + tempConstArray = new ConstantUnion[getNominalSize()]; + + {// support MSVC++6.0 + for (int size = getNominalSize(), i = 0; i < size; i++) { + tempConstArray[i].setFConst(0.0f); + for (int j = 0; j < size; j++) { + tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst())); + } + } + } + + tempNode = new TIntermConstantUnion(tempConstArray, node->getType()); + tempNode->setLine(getLine()); + + return tempNode; + + case EOpVectorTimesMatrix: + if (getType().getBasicType() != EbtFloat) { + infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for vector times matrix", getLine()); + return 0; + } + + tempConstArray = new ConstantUnion[getNominalSize()]; + {// support MSVC++6.0 + for (int size = getNominalSize(), i = 0; i < size; i++) { + tempConstArray[i].setFConst(0.0f); + for (int j = 0; j < size; j++) { + tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst())); + } + } + } + break; + + case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently + tempConstArray = new ConstantUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] && rightUnionArray[i]; + } + break; + + case EOpLogicalOr: // this code is written for possible future use, will not get executed currently + tempConstArray = new ConstantUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] || rightUnionArray[i]; + } + break; + + case EOpLogicalXor: + tempConstArray = new ConstantUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + switch (getType().getBasicType()) { + case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break; + default: assert(false && "Default missing"); + } + } + break; + + case EOpLessThan: + assert(objectSize == 1); + tempConstArray = new ConstantUnion[1]; + tempConstArray->setBConst(*unionArray < *rightUnionArray); + returnType = TType(EbtBool, EbpUndefined, EvqConst); + break; + case EOpGreaterThan: + assert(objectSize == 1); + tempConstArray = new ConstantUnion[1]; + tempConstArray->setBConst(*unionArray > *rightUnionArray); + returnType = TType(EbtBool, EbpUndefined, EvqConst); + break; + case EOpLessThanEqual: + { + assert(objectSize == 1); + ConstantUnion constant; + constant.setBConst(*unionArray > *rightUnionArray); + tempConstArray = new ConstantUnion[1]; + tempConstArray->setBConst(!constant.getBConst()); + returnType = TType(EbtBool, EbpUndefined, EvqConst); + break; + } + case EOpGreaterThanEqual: + { + assert(objectSize == 1); + ConstantUnion constant; + constant.setBConst(*unionArray < *rightUnionArray); + tempConstArray = new ConstantUnion[1]; + tempConstArray->setBConst(!constant.getBConst()); + returnType = TType(EbtBool, EbpUndefined, EvqConst); + break; + } + + case EOpEqual: + if (getType().getBasicType() == EbtStruct) { + if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) + boolNodeFlag = true; + } else { + for (int i = 0; i < objectSize; i++) { + if (unionArray[i] != rightUnionArray[i]) { + boolNodeFlag = true; + break; // break out of for loop + } + } + } + + tempConstArray = new ConstantUnion[1]; + if (!boolNodeFlag) { + tempConstArray->setBConst(true); + } + else { + tempConstArray->setBConst(false); + } + + tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); + tempNode->setLine(getLine()); + + return tempNode; + + case EOpNotEqual: + if (getType().getBasicType() == EbtStruct) { + if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) + boolNodeFlag = true; + } else { + for (int i = 0; i < objectSize; i++) { + if (unionArray[i] == rightUnionArray[i]) { + boolNodeFlag = true; + break; // break out of for loop + } + } + } + + tempConstArray = new ConstantUnion[1]; + if (!boolNodeFlag) { + tempConstArray->setBConst(true); + } + else { + tempConstArray->setBConst(false); + } + + tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); + tempNode->setLine(getLine()); + + return tempNode; + + default: + infoSink.info.message(EPrefixInternalError, "Invalid operator for constant folding", getLine()); + return 0; + } + tempNode = new TIntermConstantUnion(tempConstArray, returnType); + tempNode->setLine(getLine()); + + return tempNode; + } else { + // + // Do unary operations + // + TIntermConstantUnion *newNode = 0; + ConstantUnion* tempConstArray = new ConstantUnion[objectSize]; + for (int i = 0; i < objectSize; i++) { + switch(op) { + case EOpNegative: + switch (getType().getBasicType()) { + case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break; + case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break; + default: + infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine()); + return 0; + } + break; + case EOpLogicalNot: // this code is written for possible future use, will not get executed currently + switch (getType().getBasicType()) { + case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break; + default: + infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine()); + return 0; + } + break; + default: + return 0; + } + } + newNode = new TIntermConstantUnion(tempConstArray, getType()); + newNode->setLine(getLine()); + return newNode; + } +} + +TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) +{ + ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); + int size = node->getType().getObjectSize(); + + ConstantUnion *leftUnionArray = new ConstantUnion[size]; + + for (int i=0; i < size; i++) { + + switch (promoteTo) { + case EbtFloat: + switch (node->getType().getBasicType()) { + case EbtInt: + leftUnionArray[i].setFConst(static_cast<float>(rightUnionArray[i].getIConst())); + break; + case EbtBool: + leftUnionArray[i].setFConst(static_cast<float>(rightUnionArray[i].getBConst())); + break; + case EbtFloat: + leftUnionArray[i] = rightUnionArray[i]; + break; + default: + infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine()); + return 0; + } + break; + case EbtInt: + switch (node->getType().getBasicType()) { + case EbtInt: + leftUnionArray[i] = rightUnionArray[i]; + break; + case EbtBool: + leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getBConst())); + break; + case EbtFloat: + leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getFConst())); + break; + default: + infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine()); + return 0; + } + break; + case EbtBool: + switch (node->getType().getBasicType()) { + case EbtInt: + leftUnionArray[i].setBConst(rightUnionArray[i].getIConst() != 0); + break; + case EbtBool: + leftUnionArray[i] = rightUnionArray[i]; + break; + case EbtFloat: + leftUnionArray[i].setBConst(rightUnionArray[i].getFConst() != 0.0f); + break; + default: + infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine()); + return 0; + } + + break; + default: + infoSink.info.message(EPrefixInternalError, "Incorrect data type found", node->getLine()); + return 0; + } + + } + + const TType& t = node->getType(); + + return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine()); +} +
diff --git a/src/GLES2/compiler/MMap.h b/src/GLES2/compiler/MMap.h new file mode 100644 index 0000000..a308671 --- /dev/null +++ b/src/GLES2/compiler/MMap.h
@@ -0,0 +1,56 @@ +// +// 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. +// + +#ifndef _MMAP_INCLUDED_ +#define _MMAP_INCLUDED_ + +// +// Encapsulate memory mapped files +// + +class TMMap { +public: + TMMap(const char* fileName) : + fSize(-1), // -1 is the error value returned by GetFileSize() + fp(NULL), + fBuff(0) // 0 is the error value returned by MapViewOfFile() + { + if ((fp = fopen(fileName, "r")) == NULL) + return; + char c = getc(fp); + fSize = 0; + while (c != EOF) { + fSize++; + c = getc(fp); + } + if (c == EOF) + fSize++; + rewind(fp); + fBuff = (char*)malloc(sizeof(char) * fSize); + int count = 0; + c = getc(fp); + while (c != EOF) { + fBuff[count++] = c; + c = getc(fp); + } + fBuff[count++] = c; + } + + char* getData() { return fBuff; } + int getSize() { return fSize; } + + ~TMMap() { + if (fp != NULL) + fclose(fp); + } + +private: + int fSize; // size of file to map in + FILE *fp; + char* fBuff; // the actual data; +}; + +#endif // _MMAP_INCLUDED_
diff --git a/src/GLES2/compiler/OutputASM.cpp b/src/GLES2/compiler/OutputASM.cpp new file mode 100644 index 0000000..713f031 --- /dev/null +++ b/src/GLES2/compiler/OutputASM.cpp
@@ -0,0 +1,2250 @@ +// SwiftShader Software Renderer +// +// Copyright(c) 2005-2013 TransGaming Inc. +// +// All rights reserved. No part of this software may be copied, distributed, transmitted, +// transcribed, stored in a retrieval system, translated into any human or computer +// language by any means, or disclosed to third parties without the explicit written +// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express +// or implied, including but not limited to any patent rights, are granted to you. +// + +#include "compiler/OutputASM.h" + +#include "common/debug.h" +#include "compiler/InfoSink.h" + +#include "libGLESv2/Shader.h" + +#define GL_APICALL +#include <GLES2/gl2.h> + +namespace sh +{ + static const unsigned char swizzleSize[5] = {0x00, 0x00, 0x54, 0xA4, 0xE4}; // (void), xxxx, xyyy, xyzz, xyzw + + // Integer to TString conversion + TString str(int i) + { + char buffer[20]; + sprintf(buffer, "%d", i); + return buffer; + } + + class Temporary : public TIntermSymbol + { + public: + Temporary(OutputASM *assembler) : TIntermSymbol(0, "tmp", TType(EbtFloat, EbpHigh, EvqTemporary, 4, false, false)), assembler(assembler) + { + } + + ~Temporary() + { + assembler->freeTemporary(this); + } + + private: + OutputASM *const assembler; + }; + + class Constant : public TIntermConstantUnion + { + public: + Constant(float x, float y, float z, float w) : TIntermConstantUnion(constants, TType(EbtFloat, EbpHigh, EvqConst, 4, false, false)) + { + constants[0].setFConst(x); + constants[1].setFConst(y); + constants[2].setFConst(z); + constants[3].setFConst(w); + } + + Constant(bool b) : TIntermConstantUnion(constants, TType(EbtBool, EbpHigh, EvqConst, 1, false, false)) + { + constants[0].setBConst(b); + } + + Constant(int i) : TIntermConstantUnion(constants, TType(EbtInt, EbpHigh, EvqConst, 1, false, false)) + { + constants[0].setIConst(i); + } + + ~Constant() + { + } + + private: + ConstantUnion constants[4]; + }; + + Uniform::Uniform(GLenum type, const std::string &name, int arraySize, int registerIndex) + { + this->type = type; + this->name = name; + this->arraySize = arraySize; + this->registerIndex = registerIndex; + } + + Attribute::Attribute() + { + type = GL_NONE; + arraySize = 0; + registerIndex = 0; + } + + Attribute::Attribute(GLenum type, const std::string &name, int arraySize, int registerIndex) + { + this->type = type; + this->name = name; + this->arraySize = arraySize; + this->registerIndex = registerIndex; + } + + OutputASM::OutputASM(TParseContext &context, gl::Shader *shaderObject) : TIntermTraverser(true, true, true), mContext(context), shaderObject(shaderObject) + { + shader = 0; + pixelShader = 0; + vertexShader = 0; + + if(shaderObject) + { + shader = shaderObject->getShader(); + pixelShader = shaderObject->getPixelShader(); + vertexShader = shaderObject->getVertexShader(); + } + + functionArray.push_back(Function(0, "main(", 0, 0)); + currentFunction = 0; + } + + OutputASM::~OutputASM() + { + } + + void OutputASM::output() + { + if(shader) + { + emitShader(GLOBAL); + + if(functionArray.size() > 1) // Only call main() when there are other functions + { + Instruction *callMain = emit(sw::Shader::OPCODE_CALL); + callMain->dst.type = sw::Shader::PARAMETER_LABEL; + callMain->dst.index = 0; // main() + + emit(sw::Shader::OPCODE_RET); + } + + emitShader(FUNCTION); + } + } + + void OutputASM::emitShader(Scope scope) + { + emitScope = scope; + currentScope = GLOBAL; + mContext.treeRoot->traverse(this); + } + + void OutputASM::freeTemporary(Temporary *temporary) + { + free(temporaries, temporary); + } + + void OutputASM::visitSymbol(TIntermSymbol *symbol) + { + if(symbol->getQualifier() == EvqVaryingOut || symbol->getQualifier() == EvqInvariantVaryingOut) + { + // Vertex varyings don't have to be actively used to successfully link + // against pixel shaders that use them. So make sure they're declared. + declareVarying(symbol, -1); + } + } + + bool OutputASM::visitBinary(Visit visit, TIntermBinary *node) + { + if(currentScope != emitScope) + { + return false; + } + + TIntermTyped *result = node; + TIntermTyped *left = node->getLeft(); + TIntermTyped *right = node->getRight(); + const TType &leftType = left->getType(); + const TType &rightType = right->getType(); + const TType &resultType = node->getType(); + + switch(node->getOp()) + { + case EOpAssign: + if(visit == PostVisit) + { + assignLvalue(left, right); + copy(result, right); + } + break; + case EOpInitialize: + if(visit == PostVisit) + { + copy(left, right); + } + break; + case EOpMatrixTimesScalarAssign: + if(visit == PostVisit) + { + for(int i = 0; i < leftType.getNominalSize(); i++) + { + Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right); + mul->dst.index += i; + argument(mul->src[0], left, i); + } + + assignLvalue(left, result); + } + break; + case EOpVectorTimesMatrixAssign: + if(visit == PostVisit) + { + int size = leftType.getNominalSize(); + + for(int i = 0; i < size; i++) + { + Instruction *dot = emit(sw::Shader::OPCODE_DP(size), result, left, right); + dot->dst.mask = 1 << i; + argument(dot->src[1], right, i); + } + + assignLvalue(left, result); + } + break; + case EOpMatrixTimesMatrixAssign: + if(visit == PostVisit) + { + int dim = leftType.getNominalSize(); + + for(int i = 0; i < dim; i++) + { + Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right); + mul->dst.index += i; + argument(mul->src[1], right, i); + mul->src[1].swizzle = 0x00; + + for(int j = 1; j < dim; j++) + { + Instruction *mad = emit(sw::Shader::OPCODE_MAD, result, left, right, result); + mad->dst.index += i; + argument(mad->src[0], left, j); + argument(mad->src[1], right, i); + mad->src[1].swizzle = j * 0x55; + argument(mad->src[2], result, i); + } + } + + assignLvalue(left, result); + } + break; + case EOpIndexDirect: + if(visit == PostVisit) + { + int index = right->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); + + if(result->isMatrix() || result->isStruct()) + { + ASSERT(left->isArray()); + copy(result, left, index * left->elementRegisterCount()); + } + else if(result->isRegister()) + { + Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, left); + + if(left->isRegister()) + { + mov->src[0].swizzle = index; + } + else if(left->isArray()) + { + argument(mov->src[0], left, index * left->elementRegisterCount()); + } + else if(left->isMatrix()) + { + ASSERT(index < left->getNominalSize()); // FIXME: Report semantic error + argument(mov->src[0], left, index); + } + else UNREACHABLE(); + } + else UNREACHABLE(); + } + break; + case EOpIndexIndirect: + if(visit == PostVisit) + { + if(left->isArray() || left->isMatrix()) + { + for(int index = 0; index < result->totalRegisterCount(); index++) + { + Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, left); + + mov->dst.index += index; + argument(mov->src[0], left, index); + + if(left->totalRegisterCount() > 1) + { + sw::Shader::SourceParameter relativeRegister; + argument(relativeRegister, right); + + mov->src[0].rel.type = relativeRegister.type; + mov->src[0].rel.index = relativeRegister.index; + mov->src[0].rel.scale = result->totalRegisterCount(); + mov->src[0].rel.deterministic = !(vertexShader && left->getQualifier() == EvqUniform); + } + } + } + else if(left->isRegister()) + { + emit(sw::Shader::OPCODE_EXTRACT, result, left, right); + } + else UNREACHABLE(); + } + break; + case EOpIndexDirectStruct: + if(visit == PostVisit) + { + ASSERT(leftType.isStruct()); + + const TTypeList *structure = leftType.getStruct(); + const TString &fieldName = rightType.getFieldName(); + int fieldOffset = 0; + + for(size_t i = 0; i < structure->size(); i++) + { + const TType &fieldType = *(*structure)[i].type; + + if(fieldType.getFieldName() == fieldName) + { + break; + } + + fieldOffset += fieldType.totalRegisterCount(); + } + + copy(result, left, fieldOffset); + } + break; + case EOpVectorSwizzle: + if(visit == PostVisit) + { + int swizzle = 0; + TIntermAggregate *components = right->getAsAggregate(); + + if(components) + { + TIntermSequence &sequence = components->getSequence(); + int component = 0; + + for(TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) + { + TIntermConstantUnion *element = (*sit)->getAsConstantUnion(); + + if(element) + { + int i = element->getUnionArrayPointer()[0].getIConst(); + swizzle |= i << (component * 2); + component++; + } + else UNREACHABLE(); + } + } + else UNREACHABLE(); + + Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, left); + mov->src[0].swizzle = swizzle; + } + break; + case EOpAddAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_ADD, result, left, left, right); break; + case EOpAdd: if(visit == PostVisit) emit(sw::Shader::OPCODE_ADD, result, left, right); break; + case EOpSubAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_SUB, result, left, left, right); break; + case EOpSub: if(visit == PostVisit) emit(sw::Shader::OPCODE_SUB, result, left, right); break; + case EOpMulAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_MUL, result, left, left, right); break; + case EOpMul: if(visit == PostVisit) emit(sw::Shader::OPCODE_MUL, result, left, right); break; + case EOpDivAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_DIV, result, left, left, right); break; + case EOpDiv: if(visit == PostVisit) emit(sw::Shader::OPCODE_DIV, result, left, right); break; + case EOpEqual: + if(visit == PostVisit) + { + emitCmp(sw::Shader::CONTROL_EQ, result, left, right); + + for(int index = 1; index < left->totalRegisterCount(); index++) + { + Temporary equal(this); + emitCmp(sw::Shader::CONTROL_EQ, &equal, left, right, index); + emit(sw::Shader::OPCODE_AND, result, result, &equal); + } + } + break; + case EOpNotEqual: + if(visit == PostVisit) + { + emitCmp(sw::Shader::CONTROL_NE, result, left, right); + + for(int index = 1; index < left->totalRegisterCount(); index++) + { + Temporary notEqual(this); + emitCmp(sw::Shader::CONTROL_NE, ¬Equal, left, right, index); + emit(sw::Shader::OPCODE_OR, result, result, ¬Equal); + } + } + break; + case EOpLessThan: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LT, result, left, right); break; + case EOpGreaterThan: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GT, result, left, right); break; + case EOpLessThanEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LE, result, left, right); break; + case EOpGreaterThanEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GE, result, left, right); break; + case EOpVectorTimesScalarAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_MUL, result, left, left, right); break; + case EOpVectorTimesScalar: if(visit == PostVisit) emit(sw::Shader::OPCODE_MUL, result, left, right); break; + case EOpMatrixTimesScalar: + if(visit == PostVisit) + { + for(int i = 0; i < leftType.getNominalSize(); i++) + { + Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right); + mul->dst.index += i; + argument(mul->src[0], left, i); + } + } + break; + case EOpVectorTimesMatrix: + if(visit == PostVisit) + { + int size = leftType.getNominalSize(); + + for(int i = 0; i < size; i++) + { + Instruction *dot = emit(sw::Shader::OPCODE_DP(size), result, left, right); + dot->dst.mask = 1 << i; + argument(dot->src[1], right, i); + } + } + break; + case EOpMatrixTimesVector: + if(visit == PostVisit) + { + Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right); + mul->src[1].swizzle = 0x00; + + for(int i = 1; i < leftType.getNominalSize(); i++) + { + Instruction *mad = emit(sw::Shader::OPCODE_MAD, result, left, right, result); + argument(mad->src[0], left, i); + mad->src[1].swizzle = i * 0x55; + } + } + break; + case EOpMatrixTimesMatrix: + if(visit == PostVisit) + { + int dim = leftType.getNominalSize(); + + for(int i = 0; i < dim; i++) + { + Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right); + mul->dst.index += i; + argument(mul->src[1], right, i); + mul->src[1].swizzle = 0x00; + + for(int j = 1; j < dim; j++) + { + Instruction *mad = emit(sw::Shader::OPCODE_MAD, result, left, right, result); + mad->dst.index += i; + argument(mad->src[0], left, j); + argument(mad->src[1], right, i); + mad->src[1].swizzle = j * 0x55; + argument(mad->src[2], result, i); + } + } + } + break; + case EOpLogicalOr: + if(trivial(right, 6)) + { + if(visit == PostVisit) + { + emit(sw::Shader::OPCODE_OR, result, left, right); + } + } + else // Short-circuit evaluation + { + if(visit == InVisit) + { + emit(sw::Shader::OPCODE_MOV, result, left); + Instruction *ifnot = emit(sw::Shader::OPCODE_IF, 0, result); + ifnot->src[0].modifier = sw::Shader::MODIFIER_NOT; + } + else if(visit == PostVisit) + { + emit(sw::Shader::OPCODE_MOV, result, right); + emit(sw::Shader::OPCODE_ENDIF); + } + } + break; + case EOpLogicalXor: if(visit == PostVisit) emit(sw::Shader::OPCODE_XOR, result, left, right); break; + case EOpLogicalAnd: + if(trivial(right, 6)) + { + if(visit == PostVisit) + { + emit(sw::Shader::OPCODE_AND, result, left, right); + } + } + else // Short-circuit evaluation + { + if(visit == InVisit) + { + emit(sw::Shader::OPCODE_MOV, result, left); + emit(sw::Shader::OPCODE_IF, 0, result); + } + else if(visit == PostVisit) + { + emit(sw::Shader::OPCODE_MOV, result, right); + emit(sw::Shader::OPCODE_ENDIF); + } + } + break; + default: UNREACHABLE(); + } + + return true; + } + + bool OutputASM::visitUnary(Visit visit, TIntermUnary *node) + { + if(currentScope != emitScope) + { + return false; + } + + Constant one(1.0f, 1.0f, 1.0f, 1.0f); + Constant rad(1.74532925e-2f, 1.74532925e-2f, 1.74532925e-2f, 1.74532925e-2f); + Constant deg(5.72957795e+1f, 5.72957795e+1f, 5.72957795e+1f, 5.72957795e+1f); + + TIntermTyped *result = node; + TIntermTyped *arg = node->getOperand(); + + switch(node->getOp()) + { + case EOpNegative: + if(visit == PostVisit) + { + for(int index = 0; index < arg->totalRegisterCount(); index++) + { + Instruction *neg = emit(sw::Shader::OPCODE_MOV, result, arg); + neg->dst.index += index; + argument(neg->src[0], arg, index); + neg->src[0].modifier = sw::Shader::MODIFIER_NEGATE; + } + } + break; + case EOpVectorLogicalNot: if(visit == PostVisit) emit(sw::Shader::OPCODE_NOT, result, arg); break; + case EOpLogicalNot: if(visit == PostVisit) emit(sw::Shader::OPCODE_NOT, result, arg); break; + case EOpPostIncrement: + if(visit == PostVisit) + { + copy(result, arg); + + for(int index = 0; index < arg->totalRegisterCount(); index++) + { + Instruction *add = emit(sw::Shader::OPCODE_ADD, arg, arg, &one); + add->dst.index += index; + argument(add->src[0], arg, index); + } + + assignLvalue(arg, arg); + } + break; + case EOpPostDecrement: + if(visit == PostVisit) + { + copy(result, arg); + + for(int index = 0; index < arg->totalRegisterCount(); index++) + { + Instruction *sub = emit(sw::Shader::OPCODE_SUB, arg, arg, &one); + sub->dst.index += index; + argument(sub->src[0], arg, index); + } + + assignLvalue(arg, arg); + } + break; + case EOpPreIncrement: + if(visit == PostVisit) + { + for(int index = 0; index < arg->totalRegisterCount(); index++) + { + Instruction *add = emit(sw::Shader::OPCODE_ADD, result, arg, &one); + add->dst.index += index; + argument(add->src[0], arg, index); + } + + assignLvalue(arg, result); + } + break; + case EOpPreDecrement: + if(visit == PostVisit) + { + for(int index = 0; index < arg->totalRegisterCount(); index++) + { + Instruction *sub = emit(sw::Shader::OPCODE_SUB, result, arg, &one); + sub->dst.index += index; + argument(sub->src[0], arg, index); + } + + assignLvalue(arg, result); + } + break; + case EOpConvIntToBool: if(visit == PostVisit) emit(sw::Shader::OPCODE_F2B, result, arg); break; // Integers are implemented as float + case EOpConvFloatToBool: if(visit == PostVisit) emit(sw::Shader::OPCODE_F2B, result, arg); break; + case EOpConvBoolToFloat: if(visit == PostVisit) emit(sw::Shader::OPCODE_B2F, result, arg); break; + case EOpConvIntToFloat: if(visit == PostVisit) emit(sw::Shader::OPCODE_MOV, result, arg); break; // Integers are implemented as float + case EOpConvFloatToInt: if(visit == PostVisit) emit(sw::Shader::OPCODE_TRUNC, result, arg); break; // Integers are implemented as float + case EOpConvBoolToInt: if(visit == PostVisit) emit(sw::Shader::OPCODE_B2F, result, arg); break; // Integers are implemented as float + case EOpRadians: if(visit == PostVisit) emit(sw::Shader::OPCODE_MUL, result, arg, &rad); break; + case EOpDegrees: if(visit == PostVisit) emit(sw::Shader::OPCODE_MUL, result, arg, °); break; + case EOpSin: if(visit == PostVisit) emit(sw::Shader::OPCODE_SIN, result, arg); break; + case EOpCos: if(visit == PostVisit) emit(sw::Shader::OPCODE_COS, result, arg); break; + case EOpTan: if(visit == PostVisit) emit(sw::Shader::OPCODE_TAN, result, arg); break; + case EOpAsin: if(visit == PostVisit) emit(sw::Shader::OPCODE_ASIN, result, arg); break; + case EOpAcos: if(visit == PostVisit) emit(sw::Shader::OPCODE_ACOS, result, arg); break; + case EOpAtan: if(visit == PostVisit) emit(sw::Shader::OPCODE_ATAN, result, arg); break; + case EOpExp: if(visit == PostVisit) emit(sw::Shader::OPCODE_EXP, result, arg); break; + case EOpLog: if(visit == PostVisit) emit(sw::Shader::OPCODE_LOG, result, arg); break; + case EOpExp2: if(visit == PostVisit) emit(sw::Shader::OPCODE_EXP2, result, arg); break; + case EOpLog2: if(visit == PostVisit) emit(sw::Shader::OPCODE_LOG2, result, arg); break; + case EOpSqrt: if(visit == PostVisit) emit(sw::Shader::OPCODE_SQRT, result, arg); break; + case EOpInverseSqrt: if(visit == PostVisit) emit(sw::Shader::OPCODE_RSQ, result, arg); break; + case EOpAbs: if(visit == PostVisit) emit(sw::Shader::OPCODE_ABS, result, arg); break; + case EOpSign: if(visit == PostVisit) emit(sw::Shader::OPCODE_SGN, result, arg); break; + case EOpFloor: if(visit == PostVisit) emit(sw::Shader::OPCODE_FLOOR, result, arg); break; + case EOpCeil: if(visit == PostVisit) emit(sw::Shader::OPCODE_CEIL, result, arg, result); break; + case EOpFract: if(visit == PostVisit) emit(sw::Shader::OPCODE_FRC, result, arg); break; + case EOpLength: if(visit == PostVisit) emit(sw::Shader::OPCODE_LEN(dim(arg)), result, arg); break; + case EOpNormalize: if(visit == PostVisit) emit(sw::Shader::OPCODE_NRM(dim(arg)), result, arg); break; + case EOpDFdx: if(visit == PostVisit) emit(sw::Shader::OPCODE_DFDX, result, arg); break; + case EOpDFdy: if(visit == PostVisit) emit(sw::Shader::OPCODE_DFDY, result, arg); break; + case EOpFwidth: if(visit == PostVisit) emit(sw::Shader::OPCODE_FWIDTH, result, arg); break; + case EOpAny: if(visit == PostVisit) emit(sw::Shader::OPCODE_ANY, result, arg); break; + case EOpAll: if(visit == PostVisit) emit(sw::Shader::OPCODE_ALL, result, arg); break; + default: UNREACHABLE(); + } + + return true; + } + + bool OutputASM::visitAggregate(Visit visit, TIntermAggregate *node) + { + if(currentScope != emitScope && node->getOp() != EOpFunction && node->getOp() != EOpSequence) + { + return false; + } + + TIntermTyped *result = node; + const TType &resultType = node->getType(); + TIntermSequence &arg = node->getSequence(); + int argumentCount = arg.size(); + + switch(node->getOp()) + { + case EOpSequence: break; + case EOpDeclaration: break; + case EOpPrototype: break; + case EOpComma: + if(visit == PostVisit) + { + copy(result, arg[1]); + } + break; + case EOpFunction: + if(visit == PreVisit) + { + const TString &name = node->getName(); + + if(emitScope == FUNCTION) + { + if(functionArray.size() > 1) // No need for a label when there's only main() + { + Instruction *label = emit(sw::Shader::OPCODE_LABEL); + label->dst.type = sw::Shader::PARAMETER_LABEL; + + const Function &function = findFunction(name); + label->dst.index = function.label; + currentFunction = function.label; + } + } + else if(emitScope == GLOBAL) + { + if(name != "main(") + { + TIntermSequence &arguments = node->getSequence()[0]->getAsAggregate()->getSequence(); + functionArray.push_back(Function(functionArray.size(), name, &arguments, node)); + } + } + else UNREACHABLE(); + + currentScope = FUNCTION; + } + else if(visit == PostVisit) + { + if(emitScope == FUNCTION) + { + if(functionArray.size() > 1) // No need to return when there's only main() + { + emit(sw::Shader::OPCODE_RET); + } + } + + currentScope = GLOBAL; + } + break; + case EOpFunctionCall: + if(visit == PostVisit) + { + if(node->isUserDefined()) + { + const TString &name = node->getName(); + const Function &function = findFunction(name); + TIntermSequence &arguments = *function.arg; + + for(int i = 0; i < argumentCount; i++) + { + TIntermTyped *in = arguments[i]->getAsTyped(); + + if(in->getQualifier() == EvqIn || + in->getQualifier() == EvqInOut || + in->getQualifier() == EvqConstReadOnly) + { + copy(in, arg[i]); + } + } + + Instruction *call = emit(sw::Shader::OPCODE_CALL); + call->dst.type = sw::Shader::PARAMETER_LABEL; + call->dst.index = function.label; + + if(function.ret && function.ret->getType().getBasicType() != EbtVoid) + { + copy(result, function.ret); + } + + for(int i = 0; i < argumentCount; i++) + { + TIntermTyped *argument = arguments[i]->getAsTyped(); + TIntermTyped *out = arg[i]->getAsTyped(); + + if(argument->getQualifier() == EvqOut || + argument->getQualifier() == EvqInOut) + { + copy(out, argument); + } + } + } + else + { + TString name = TFunction::unmangleName(node->getName()); + + if(name == "texture2D" || name == "textureCube") + { + if(argumentCount == 2) + { + emit(sw::Shader::OPCODE_TEX, result, arg[1], arg[0]); + } + else if(argumentCount == 3) // bias + { + Temporary uvwb(this); + emit(sw::Shader::OPCODE_MOV, &uvwb, arg[1]); + Instruction *bias = emit(sw::Shader::OPCODE_MOV, &uvwb, arg[2]); + bias->dst.mask = 0x8; + + Instruction *tex = emit(sw::Shader::OPCODE_TEX, result, &uvwb, arg[0]); // FIXME: Implement an efficient TEXLDB instruction + tex->bias = true; + } + else UNREACHABLE(); + } + else if(name == "texture2DProj") + { + TIntermTyped *t = arg[1]->getAsTyped(); + + if(argumentCount == 2) + { + Instruction *tex = emit(sw::Shader::OPCODE_TEX, result, arg[1], arg[0]); + tex->project = true; + + if(t->getNominalSize() == 3) + { + tex->src[0].swizzle = 0xA4; + } + else ASSERT(t->getNominalSize() == 4); + } + else if(argumentCount == 3) // bias + { + Temporary proj(this); + emit(sw::Shader::OPCODE_MOV, &proj, arg[1]); + + if(t->getNominalSize() == 3) + { + Instruction *div = emit(sw::Shader::OPCODE_DIV, &proj, &proj); + div->src[0].swizzle = 0xAA; + div->dst.mask = 0x3; + } + else if(t->getNominalSize() == 4) + { + Instruction *div = emit(sw::Shader::OPCODE_DIV, &proj, &proj); + div->src[0].swizzle = 0xFF; + div->dst.mask = 0x3; + } + else UNREACHABLE(); + + Instruction *bias = emit(sw::Shader::OPCODE_MOV, &proj, arg[2]); + bias->dst.mask = 0x8; + + Instruction *tex = emit(sw::Shader::OPCODE_TEX, result, &proj, arg[0]); + tex->bias = true; + } + else UNREACHABLE(); + } + else if(name == "texture2DLod" || name == "textureCubeLod") + { + Temporary uvwb(this); + emit(sw::Shader::OPCODE_MOV, &uvwb, arg[1]); + Instruction *lod = emit(sw::Shader::OPCODE_MOV, &uvwb, arg[2]); + lod->dst.mask = 0x8; + + emit(sw::Shader::OPCODE_TEXLDL, result, &uvwb, arg[0]); + } + else if(name == "texture2DProjLod") + { + TIntermTyped *t = arg[1]->getAsTyped(); + + Temporary proj(this); + emit(sw::Shader::OPCODE_MOV, &proj, arg[1]); + + if(t->getNominalSize() == 3) + { + Instruction *div = emit(sw::Shader::OPCODE_DIV, &proj, &proj); + div->src[0].swizzle = 0xAA; + div->dst.mask = 0x3; + } + else if(t->getNominalSize() == 4) + { + Instruction *div = emit(sw::Shader::OPCODE_DIV, &proj, &proj); + div->src[0].swizzle = 0xFF; + div->dst.mask = 0x3; + } + else UNREACHABLE(); + + Instruction *lod = emit(sw::Shader::OPCODE_MOV, &proj, arg[2]); + lod->dst.mask = 0x8; + + emit(sw::Shader::OPCODE_TEXLDL, result, &proj, arg[0]); + } + else UNREACHABLE(); + } + } + break; + case EOpParameters: break; + case EOpConstructFloat: + case EOpConstructVec2: + case EOpConstructVec3: + case EOpConstructVec4: + case EOpConstructBool: + case EOpConstructBVec2: + case EOpConstructBVec3: + case EOpConstructBVec4: + case EOpConstructInt: + case EOpConstructIVec2: + case EOpConstructIVec3: + case EOpConstructIVec4: + if(visit == PostVisit) + { + int component = 0; + + for(int i = 0; i < argumentCount; i++) + { + TIntermTyped *argi = arg[i]->getAsTyped(); + int size = argi->getNominalSize(); + ASSERT(!argi->isMatrix()); + + Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, argi); + mov->dst.mask = (0xF << component) & 0xF; + mov->src[0].swizzle = swizzleSize[size] << (component * 2); + + component += size; + } + } + break; + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: + if(visit == PostVisit) + { + TIntermTyped *arg0 = arg[0]->getAsTyped(); + const int dim = result->getNominalSize(); + + if(arg0->isMatrix()) + { + for(int i = 0; i < dim; i++) + { + if(dim > dim2(arg0)) + { + // Initialize to identity matrix + Constant col((i == 0 ? 1.0f : 0.0f), (i == 1 ? 1.0f : 0.0f), (i == 2 ? 1.0f : 0.0f), (i == 3 ? 1.0f : 0.0f)); + Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, &col); + mov->dst.index += i; + } + + if(i < dim2(arg0)) + { + Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, arg0); + mov->dst.index += i; + mov->dst.mask = 0xF >> (4 - dim2(arg0)); + argument(mov->src[0], arg0, i); + } + } + } + else + { + int column = 0; + int row = 0; + + for(int i = 0; i < argumentCount; i++) + { + TIntermTyped *argi = arg[i]->getAsTyped(); + int size = argi->getNominalSize(); + int element = 0; + + while(element < size) + { + Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, argi); + mov->dst.index += column; + mov->dst.mask = (0xF << row) & 0xF; + mov->src[0].swizzle = (swizzleSize[size] << (row * 2)) + 0x55 * element; + + int end = row + size - element; + column = end >= dim ? column + 1 : column; + element = element + dim - row; + row = end >= dim ? 0 : end; + } + } + } + } + break; + case EOpConstructStruct: + if(visit == PostVisit) + { + int offset = 0; + for(int i = 0; i < argumentCount; i++) + { + TIntermTyped *argi = arg[i]->getAsTyped(); + int size = argi->totalRegisterCount(); + + for(int index = 0; index < size; index++) + { + Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, argi); + mov->dst.index += index + offset; + mov->dst.mask = writeMask(result, offset + index); + argument(mov->src[0], argi, index); + } + + offset += size; + } + } + break; + case EOpLessThan: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LT, result, arg[0], arg[1]); break; + case EOpGreaterThan: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GT, result, arg[0], arg[1]); break; + case EOpLessThanEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LE, result, arg[0], arg[1]); break; + case EOpGreaterThanEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GE, result, arg[0], arg[1]); break; + case EOpVectorEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_EQ, result, arg[0], arg[1]); break; + case EOpVectorNotEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_NE, result, arg[0], arg[1]); break; + case EOpMod: if(visit == PostVisit) emit(sw::Shader::OPCODE_MOD, result, arg[0], arg[1]); break; + case EOpPow: if(visit == PostVisit) emit(sw::Shader::OPCODE_POW, result, arg[0], arg[1]); break; + case EOpAtan: if(visit == PostVisit) emit(sw::Shader::OPCODE_ATAN2, result, arg[0], arg[1]); break; + case EOpMin: if(visit == PostVisit) emit(sw::Shader::OPCODE_MIN, result, arg[0], arg[1]); break; + case EOpMax: if(visit == PostVisit) emit(sw::Shader::OPCODE_MAX, result, arg[0], arg[1]); break; + case EOpClamp: + if(visit == PostVisit) + { + emit(sw::Shader::OPCODE_MAX, result, arg[0], arg[1]); + emit(sw::Shader::OPCODE_MIN, result, result, arg[2]); + } + break; + case EOpMix: if(visit == PostVisit) emit(sw::Shader::OPCODE_LRP, result, arg[2], arg[1], arg[0]); break; + case EOpStep: if(visit == PostVisit) emit(sw::Shader::OPCODE_STEP, result, arg[0], arg[1]); break; + case EOpSmoothStep: if(visit == PostVisit) emit(sw::Shader::OPCODE_SMOOTH, result, arg[0], arg[1], arg[2]); break; + case EOpDistance: if(visit == PostVisit) emit(sw::Shader::OPCODE_DIST(dim(arg[0])), result, arg[0], arg[1]); break; + case EOpDot: if(visit == PostVisit) emit(sw::Shader::OPCODE_DP(dim(arg[0])), result, arg[0], arg[1]); break; + case EOpCross: if(visit == PostVisit) emit(sw::Shader::OPCODE_CRS, result, arg[0], arg[1]); break; + case EOpFaceForward: if(visit == PostVisit) emit(sw::Shader::OPCODE_FORWARD(dim(arg[0])), result, arg[0], arg[1], arg[2]); break; + case EOpReflect: if(visit == PostVisit) emit(sw::Shader::OPCODE_REFLECT(dim(arg[0])), result, arg[0], arg[1]); break; + case EOpRefract: if(visit == PostVisit) emit(sw::Shader::OPCODE_REFRACT(dim(arg[0])), result, arg[0], arg[1], arg[2]); break; + case EOpMul: + if(visit == PostVisit) + { + ASSERT(dim2(arg[0]) == dim2(arg[1])); + + for(int i = 0; i < dim2(arg[0]); i++) + { + Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, arg[0], arg[1]); + mul->dst.index += i; + argument(mul->src[0], arg[0], i); + argument(mul->src[1], arg[1], i); + } + } + break; + default: UNREACHABLE(); + } + + return true; + } + + bool OutputASM::visitSelection(Visit visit, TIntermSelection *node) + { + if(currentScope != emitScope) + { + return false; + } + + TIntermTyped *condition = node->getCondition(); + TIntermNode *trueBlock = node->getTrueBlock(); + TIntermNode *falseBlock = node->getFalseBlock(); + TIntermConstantUnion *constantCondition = condition->getAsConstantUnion(); + + condition->traverse(this); + + if(node->usesTernaryOperator()) + { + if(constantCondition) + { + bool trueCondition = constantCondition->getUnionArrayPointer()->getBConst(); + + if(trueCondition) + { + trueBlock->traverse(this); + copy(node, trueBlock); + } + else + { + falseBlock->traverse(this); + copy(node, falseBlock); + } + } + else if(trivial(node, 6)) // Fast to compute both potential results and no side effects + { + trueBlock->traverse(this); + falseBlock->traverse(this); + emit(sw::Shader::OPCODE_SELECT, node, condition, trueBlock, falseBlock); + } + else + { + emit(sw::Shader::OPCODE_IF, 0, condition); + + if(trueBlock) + { + trueBlock->traverse(this); + copy(node, trueBlock); + } + + if(falseBlock) + { + emit(sw::Shader::OPCODE_ELSE); + falseBlock->traverse(this); + copy(node, falseBlock); + } + + emit(sw::Shader::OPCODE_ENDIF); + } + } + else // if/else statement + { + if(constantCondition) + { + bool trueCondition = constantCondition->getUnionArrayPointer()->getBConst(); + + if(trueCondition) + { + if(trueBlock) + { + trueBlock->traverse(this); + } + } + else + { + if(falseBlock) + { + falseBlock->traverse(this); + } + } + } + else + { + emit(sw::Shader::OPCODE_IF, 0, condition); + + if(trueBlock) + { + trueBlock->traverse(this); + } + + if(falseBlock) + { + emit(sw::Shader::OPCODE_ELSE); + falseBlock->traverse(this); + } + + emit(sw::Shader::OPCODE_ENDIF); + } + } + + return false; + } + + bool OutputASM::visitLoop(Visit visit, TIntermLoop *node) + { + if(currentScope != emitScope) + { + return false; + } + + TIntermNode *init = node->getInit(); + TIntermTyped *condition = node->getCondition(); + TIntermTyped *expression = node->getExpression(); + TIntermNode *body = node->getBody(); + + if(node->getType() == ELoopDoWhile) + { + Temporary iterate(this); + Constant True(true); + emit(sw::Shader::OPCODE_MOV, &iterate, &True); + + emit(sw::Shader::OPCODE_WHILE, 0, &iterate); // FIXME: Implement real do-while + + if(body) + { + body->traverse(this); + } + + emit(sw::Shader::OPCODE_TEST); + + condition->traverse(this); + emit(sw::Shader::OPCODE_MOV, &iterate, condition); + + emit(sw::Shader::OPCODE_ENDWHILE); + } + else + { + if(init) + { + init->traverse(this); + } + + condition->traverse(this); + + emit(sw::Shader::OPCODE_WHILE, 0, condition); + + if(body) + { + body->traverse(this); + } + + emit(sw::Shader::OPCODE_TEST); + + if(expression) + { + expression->traverse(this); + } + + condition->traverse(this); + + emit(sw::Shader::OPCODE_ENDWHILE); + } + + return false; + } + + bool OutputASM::visitBranch(Visit visit, TIntermBranch *node) + { + if(currentScope != emitScope) + { + return false; + } + + switch(node->getFlowOp()) + { + case EOpKill: if(visit == PostVisit) emit(sw::Shader::OPCODE_DISCARD); break; + case EOpBreak: if(visit == PostVisit) emit(sw::Shader::OPCODE_BREAK); break; + case EOpContinue: if(visit == PostVisit) emit(sw::Shader::OPCODE_CONTINUE); break; + case EOpReturn: + if(visit == PostVisit) + { + TIntermTyped *value = node->getExpression(); + + if(value) + { + copy(functionArray[currentFunction].ret, value); + } + + emit(sw::Shader::OPCODE_LEAVE); + } + break; + default: UNREACHABLE(); + } + + return true; + } + + Instruction *OutputASM::emit(sw::Shader::Opcode op, TIntermTyped *dst, TIntermNode *src0, TIntermNode *src1, TIntermNode *src2) + { + if(dst && registerType(dst) == sw::Shader::PARAMETER_SAMPLER) + { + op = sw::Shader::OPCODE_NOP; // Can't assign to a sampler, but this will be hit when indexing sampler arrays + } + + Instruction *instruction = new Instruction(op); + + if(dst) + { + instruction->dst.type = registerType(dst); + instruction->dst.index = registerIndex(dst); + instruction->dst.mask = writeMask(dst); + instruction->dst.integer = (dst->getBasicType() == EbtInt); + } + + argument(instruction->src[0], src0); + argument(instruction->src[1], src1); + argument(instruction->src[2], src2); + + shader->append(instruction); + + return instruction; + } + + void OutputASM::emitAssign(sw::Shader::Opcode op, TIntermTyped *result, TIntermTyped *lhs, TIntermTyped *src0, TIntermTyped *src1) + { + emit(op, result, src0, src1); + assignLvalue(lhs, result); + } + + void OutputASM::emitCmp(sw::Shader::Control cmpOp, TIntermTyped *dst, TIntermNode *left, TIntermNode *right, int index) + { + bool boolean = (left->getAsTyped()->getBasicType() == EbtBool); + sw::Shader::Opcode opcode = boolean ? sw::Shader::OPCODE_ICMP : sw::Shader::OPCODE_CMP; + + Instruction *cmp = emit(opcode, dst, left, right); + cmp->control = cmpOp; + argument(cmp->src[0], left, index); + argument(cmp->src[1], right, index); + } + + int componentCount(const TType &type, int registers) + { + if(registers == 0) + { + return 0; + } + + if(type.isArray() && registers >= type.elementRegisterCount()) + { + int index = registers / type.elementRegisterCount(); + registers -= index * type.elementRegisterCount(); + return index * type.getElementSize() + componentCount(type, registers); + } + + if(type.isStruct()) + { + TTypeList *structure = type.getStruct(); + int elements = 0; + + for(TTypeList::const_iterator field = structure->begin(); field != structure->end(); field++) + { + const TType &fieldType = *field->type; + + if(fieldType.totalRegisterCount() <= registers) + { + registers -= fieldType.totalRegisterCount(); + elements += fieldType.getObjectSize(); + } + else // Register within this field + { + return elements + componentCount(fieldType, registers); + } + } + } + else if(type.isMatrix()) + { + return registers * type.getNominalSize(); + } + + UNREACHABLE(); + return 0; + } + + int registerSize(const TType &type, int registers) + { + if(registers == 0) + { + if(type.isStruct()) + { + return registerSize(*type.getStruct()->begin()->type, 0); + } + + return type.getNominalSize(); + } + + if(type.isArray() && registers >= type.elementRegisterCount()) + { + int index = registers / type.elementRegisterCount(); + registers -= index * type.elementRegisterCount(); + return registerSize(type, registers); + } + + if(type.isStruct()) + { + TTypeList *structure = type.getStruct(); + int elements = 0; + + for(TTypeList::const_iterator field = structure->begin(); field != structure->end(); field++) + { + const TType &fieldType = *field->type; + + if(fieldType.totalRegisterCount() <= registers) + { + registers -= fieldType.totalRegisterCount(); + elements += fieldType.getObjectSize(); + } + else // Register within this field + { + return registerSize(fieldType, registers); + } + } + } + else if(type.isMatrix()) + { + return registerSize(type, 0); + } + + UNREACHABLE(); + return 0; + } + + void OutputASM::argument(sw::Shader::SourceParameter ¶meter, TIntermNode *argument, int index) + { + if(argument) + { + TIntermTyped *arg = argument->getAsTyped(); + const TType &type = arg->getType(); + const TTypeList *structure = type.getStruct(); + ASSERT(index < arg->totalRegisterCount()); + + int size = registerSize(type, index); + + parameter.type = registerType(arg); + + if(arg->getQualifier() == EvqConst) + { + int component = componentCount(type, index); + ConstantUnion *constants = arg->getAsConstantUnion()->getUnionArrayPointer(); + + for(int i = 0; i < 4; i++) + { + if(size == 1) // Replicate + { + parameter.value[i] = constants[component + 0].getAsFloat(); + } + else if(i < size) + { + parameter.value[i] = constants[component + i].getAsFloat(); + } + else + { + parameter.value[i] = 0.0f; + } + } + } + else + { + parameter.index = registerIndex(arg) + index; + + if(registerType(arg) == sw::Shader::PARAMETER_SAMPLER) + { + TIntermBinary *binary = argument->getAsBinaryNode(); + + if(binary) + { + TIntermTyped *left = binary->getLeft(); + TIntermTyped *right = binary->getRight(); + + if(binary->getOp() == EOpIndexDirect) + { + parameter.index += right->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); + } + else if(binary->getOp() == EOpIndexIndirect) + { + if(left->getArraySize() > 1) + { + parameter.rel.type = registerType(binary->getRight()); + parameter.rel.index = registerIndex(binary->getRight()); + parameter.rel.scale = 1; + parameter.rel.deterministic = true; + } + } + else UNREACHABLE(); + } + } + } + + if(!IsSampler(arg->getBasicType())) + { + parameter.swizzle = swizzleSize[size]; + } + } + } + + void OutputASM::copy(TIntermTyped *dst, TIntermNode *src, int offset) + { + for(int index = 0; index < dst->totalRegisterCount(); index++) + { + Instruction *mov = emit(sw::Shader::OPCODE_MOV, dst, src); + mov->dst.index += index; + mov->dst.mask = writeMask(dst, index); + argument(mov->src[0], src, offset + index); + } + } + + int swizzleElement(int swizzle, int index) + { + return (swizzle >> (index * 2)) & 0x03; + } + + int swizzleSwizzle(int leftSwizzle, int rightSwizzle) + { + return (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 0)) << 0) | + (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 1)) << 2) | + (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 2)) << 4) | + (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 3)) << 6); + } + + void OutputASM::assignLvalue(TIntermTyped *dst, TIntermNode *src) + { + TIntermBinary *binary = dst->getAsBinaryNode(); + + if(binary && binary->getOp() == EOpIndexIndirect && dst->isScalar()) + { + Instruction *insert = new Instruction(sw::Shader::OPCODE_INSERT); + + Temporary address(this); + lvalue(insert->dst, address, dst); + + insert->src[0].type = insert->dst.type; + insert->src[0].index = insert->dst.index; + insert->src[0].rel = insert->dst.rel; + argument(insert->src[1], src); + argument(insert->src[2], binary->getRight()); + + shader->append(insert); + } + else + { + for(int offset = 0; offset < dst->totalRegisterCount(); offset++) + { + Instruction *mov = new Instruction(sw::Shader::OPCODE_MOV); + + Temporary address(this); + int swizzle = lvalue(mov->dst, address, dst); + mov->dst.index += offset; + + if(offset > 0) + { + mov->dst.mask = writeMask(dst, offset); + } + + argument(mov->src[0], src, offset); + mov->src[0].swizzle = swizzleSwizzle(mov->src[0].swizzle, swizzle); + + shader->append(mov); + } + } + } + + int OutputASM::lvalue(sw::Shader::DestinationParameter &dst, Temporary &address, TIntermTyped *node) + { + TIntermTyped *result = node; + TIntermBinary *binary = node->getAsBinaryNode(); + TIntermSymbol *symbol = node->getAsSymbolNode(); + + if(binary) + { + TIntermTyped *left = binary->getLeft(); + TIntermTyped *right = binary->getRight(); + + int leftSwizzle = lvalue(dst, address, left); // Resolve the l-value of the left side + + switch(binary->getOp()) + { + case EOpIndexDirect: + { + int rightIndex = right->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); + + if(left->isRegister()) + { + int leftMask = dst.mask; + + dst.mask = 1; + while((leftMask & dst.mask) == 0) + { + dst.mask = dst.mask << 1; + } + + int element = swizzleElement(leftSwizzle, rightIndex); + dst.mask = 1 << element; + + return element; + } + else if(left->isArray() || left->isMatrix()) + { + dst.index += rightIndex * result->totalRegisterCount(); + return 0xE4; + } + else UNREACHABLE(); + } + break; + case EOpIndexIndirect: + { + if(left->isRegister()) + { + // Requires INSERT instruction (handled by calling function) + } + else if(left->isArray() || left->isMatrix()) + { + int scale = result->totalRegisterCount(); + + if(dst.rel.type == sw::Shader::PARAMETER_VOID) // Use the index register as the relative address directly + { + if(left->totalRegisterCount() > 1) + { + sw::Shader::SourceParameter relativeRegister; + argument(relativeRegister, right); + + dst.rel.index = relativeRegister.index; + dst.rel.type = relativeRegister.type; + dst.rel.scale = scale; + dst.rel.deterministic = !(vertexShader && left->getQualifier() == EvqUniform); + } + } + else if(dst.rel.index != registerIndex(&address)) // Move the previous index register to the address register + { + if(scale == 1) + { + Constant oldScale((int)dst.rel.scale); + Instruction *mad = emit(sw::Shader::OPCODE_MAD, &address, &address, &oldScale, right); + mad->src[0].index = dst.rel.index; + mad->src[0].type = dst.rel.type; + } + else + { + Constant oldScale((int)dst.rel.scale); + Instruction *mul = emit(sw::Shader::OPCODE_MUL, &address, &address, &oldScale); + mul->src[0].index = dst.rel.index; + mul->src[0].type = dst.rel.type; + + Constant newScale(scale); + emit(sw::Shader::OPCODE_MAD, &address, right, &newScale, &address); + } + + dst.rel.type = sw::Shader::PARAMETER_TEMP; + dst.rel.index = registerIndex(&address); + dst.rel.scale = 1; + } + else // Just add the new index to the address register + { + if(scale == 1) + { + emit(sw::Shader::OPCODE_ADD, &address, &address, right); + } + else + { + Constant newScale(scale); + emit(sw::Shader::OPCODE_MAD, &address, right, &newScale, &address); + } + } + } + else UNREACHABLE(); + } + break; + case EOpIndexDirectStruct: + { + const TTypeList *structure = left->getType().getStruct(); + const TString &fieldName = right->getType().getFieldName(); + + int offset = 0; + for(TTypeList::const_iterator field = structure->begin(); field != structure->end(); field++) + { + if(field->type->getFieldName() == fieldName) + { + dst.type = registerType(left); + dst.index += offset; + dst.mask = writeMask(right); + + return 0xE4; + } + + offset += field->type->totalRegisterCount(); + } + } + break; + case EOpVectorSwizzle: + { + ASSERT(left->isRegister()); + + int leftMask = dst.mask; + + int swizzle = 0; + int rightMask = 0; + + TIntermSequence &sequence = right->getAsAggregate()->getSequence(); + + for(unsigned int i = 0; i < sequence.size(); i++) + { + int index = sequence[i]->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); + + int element = swizzleElement(leftSwizzle, index); + rightMask = rightMask | (1 << element); + swizzle = swizzle | swizzleElement(leftSwizzle, i) << (element * 2); + } + + dst.mask = leftMask & rightMask; + + return swizzle; + } + break; + default: + UNREACHABLE(); // Not an l-value operator + break; + } + } + else if(symbol) + { + dst.type = registerType(symbol); + dst.index = registerIndex(symbol); + dst.mask = writeMask(symbol); + return 0xE4; + } + + return 0xE4; + } + + sw::Shader::ParameterType OutputASM::registerType(TIntermTyped *operand) + { + if(IsSampler(operand->getBasicType()) && (operand->getQualifier() == EvqUniform || operand->getQualifier() == EvqTemporary)) // Function parameters are temporaries + { + return sw::Shader::PARAMETER_SAMPLER; + } + + switch(operand->getQualifier()) + { + case EvqTemporary: return sw::Shader::PARAMETER_TEMP; + case EvqGlobal: return sw::Shader::PARAMETER_TEMP; + case EvqConst: return sw::Shader::PARAMETER_FLOAT4LITERAL; // All converted to float + case EvqAttribute: return sw::Shader::PARAMETER_INPUT; + case EvqVaryingIn: return sw::Shader::PARAMETER_INPUT; + case EvqVaryingOut: return sw::Shader::PARAMETER_OUTPUT; + case EvqInvariantVaryingIn: return sw::Shader::PARAMETER_INPUT; // FIXME: Guarantee invariance at the backend + case EvqInvariantVaryingOut: return sw::Shader::PARAMETER_OUTPUT; // FIXME: Guarantee invariance at the backend + case EvqUniform: return sw::Shader::PARAMETER_CONST; + case EvqIn: return sw::Shader::PARAMETER_TEMP; + case EvqOut: return sw::Shader::PARAMETER_TEMP; + case EvqInOut: return sw::Shader::PARAMETER_TEMP; + case EvqConstReadOnly: return sw::Shader::PARAMETER_TEMP; + case EvqPosition: return sw::Shader::PARAMETER_OUTPUT; + case EvqPointSize: return sw::Shader::PARAMETER_OUTPUT; + case EvqFragCoord: return sw::Shader::PARAMETER_MISCTYPE; + case EvqFrontFacing: return sw::Shader::PARAMETER_MISCTYPE; + case EvqPointCoord: return sw::Shader::PARAMETER_INPUT; + case EvqFragColor: return sw::Shader::PARAMETER_COLOROUT; + case EvqFragData: return sw::Shader::PARAMETER_COLOROUT; + default: UNREACHABLE(); + } + + return sw::Shader::PARAMETER_VOID; + } + + int OutputASM::registerIndex(TIntermTyped *operand) + { + if(registerType(operand) == sw::Shader::PARAMETER_SAMPLER) + { + return samplerRegister(operand); + } + + switch(operand->getQualifier()) + { + case EvqTemporary: return temporaryRegister(operand); + case EvqGlobal: return temporaryRegister(operand); + case EvqConst: UNREACHABLE(); + case EvqAttribute: return attributeRegister(operand); + case EvqVaryingIn: return varyingRegister(operand); + case EvqVaryingOut: return varyingRegister(operand); + case EvqInvariantVaryingIn: return varyingRegister(operand); + case EvqInvariantVaryingOut: return varyingRegister(operand); + case EvqUniform: return uniformRegister(operand); + case EvqIn: return temporaryRegister(operand); + case EvqOut: return temporaryRegister(operand); + case EvqInOut: return temporaryRegister(operand); + case EvqConstReadOnly: return temporaryRegister(operand); + case EvqPosition: return varyingRegister(operand); + case EvqPointSize: return varyingRegister(operand); + case EvqFragCoord: pixelShader->vPosDeclared = true; return 0; + case EvqFrontFacing: pixelShader->vFaceDeclared = true; return 1; + case EvqPointCoord: return varyingRegister(operand); + case EvqFragColor: return 0; + case EvqFragData: return 0; + default: UNREACHABLE(); + } + + return 0; + } + + int OutputASM::writeMask(TIntermTyped *destination, int index) + { + if(destination->getQualifier() == EvqPointSize) + { + return 0x2; // Point size stored in the y component + } + + return 0xF >> (4 - registerSize(destination->getType(), index)); + } + + // Conservatively checks whether an expression is fast to compute and has no side effects + bool OutputASM::trivial(TIntermTyped *expression, int budget) + { + if(!expression->isRegister()) + { + return false; + } + + return cost(expression, budget) >= 0; + } + + // Returns the remaining computing budget (if < 0 the expression is too expensive or has side effects) + int OutputASM::cost(TIntermNode *expression, int budget) + { + if(budget < 0) + { + return budget; + } + + if(expression->getAsSymbolNode()) + { + return budget; + } + else if(expression->getAsConstantUnion()) + { + return budget; + } + else if(expression->getAsBinaryNode()) + { + TIntermBinary *binary = expression->getAsBinaryNode(); + + switch(binary->getOp()) + { + case EOpVectorSwizzle: + case EOpIndexDirect: + case EOpIndexDirectStruct: + return cost(binary->getLeft(), budget - 0); + case EOpAdd: + case EOpSub: + case EOpMul: + return cost(binary->getLeft(), cost(binary->getRight(), budget - 1)); + default: + return -1; + } + } + else if(expression->getAsUnaryNode()) + { + TIntermUnary *unary = expression->getAsUnaryNode(); + + switch(unary->getOp()) + { + case EOpAbs: + case EOpNegative: + return cost(unary->getOperand(), budget - 1); + default: + return -1; + } + } + else if(expression->getAsSelectionNode()) + { + TIntermSelection *selection = expression->getAsSelectionNode(); + + if(selection->usesTernaryOperator()) + { + TIntermTyped *condition = selection->getCondition(); + TIntermNode *trueBlock = selection->getTrueBlock(); + TIntermNode *falseBlock = selection->getFalseBlock(); + TIntermConstantUnion *constantCondition = condition->getAsConstantUnion(); + + if(constantCondition) + { + bool trueCondition = constantCondition->getUnionArrayPointer()->getBConst(); + + if(trueCondition) + { + return cost(trueBlock, budget - 0); + } + else + { + return cost(falseBlock, budget - 0); + } + } + else + { + return cost(trueBlock, cost(falseBlock, budget - 2)); + } + } + } + + return -1; + } + + const Function &OutputASM::findFunction(const TString &name) + { + for(unsigned int f = 0; f < functionArray.size(); f++) + { + if(functionArray[f].name == name) + { + return functionArray[f]; + } + } + + UNREACHABLE(); + return functionArray[0]; + } + + int OutputASM::temporaryRegister(TIntermTyped *temporary) + { + return allocate(temporaries, temporary); + } + + int OutputASM::varyingRegister(TIntermTyped *varying) + { + int var = lookup(varyings, varying); + + if(var == -1) + { + var = allocate(varyings, varying); + int componentCount = varying->getNominalSize(); + int registerCount = varying->totalRegisterCount(); + + if(pixelShader && (var + registerCount) <= sw::PixelShader::MAX_INPUT_VARYINGS) + { + if(varying->getQualifier() == EvqPointCoord) + { + ASSERT(varying->isRegister()); + if(componentCount >= 1) pixelShader->semantic[var][0] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var); + if(componentCount >= 2) pixelShader->semantic[var][1] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var); + if(componentCount >= 3) pixelShader->semantic[var][2] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var); + if(componentCount >= 4) pixelShader->semantic[var][3] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var); + } + else + { + for(int i = 0; i < varying->totalRegisterCount(); i++) + { + if(componentCount >= 1) pixelShader->semantic[var + i][0] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i); + if(componentCount >= 2) pixelShader->semantic[var + i][1] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i); + if(componentCount >= 3) pixelShader->semantic[var + i][2] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i); + if(componentCount >= 4) pixelShader->semantic[var + i][3] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i); + } + } + } + else if(vertexShader && (var + registerCount) <= sw::VertexShader::MAX_OUTPUT_VARYINGS) + { + if(varying->getQualifier() == EvqPosition) + { + ASSERT(varying->isRegister()); + vertexShader->output[var][0] = sw::Shader::Semantic(sw::Shader::USAGE_POSITION, 0); + vertexShader->output[var][1] = sw::Shader::Semantic(sw::Shader::USAGE_POSITION, 0); + vertexShader->output[var][2] = sw::Shader::Semantic(sw::Shader::USAGE_POSITION, 0); + vertexShader->output[var][3] = sw::Shader::Semantic(sw::Shader::USAGE_POSITION, 0); + vertexShader->positionRegister = var; + } + else if(varying->getQualifier() == EvqPointSize) + { + ASSERT(varying->isRegister()); + vertexShader->output[var][0] = sw::Shader::Semantic(sw::Shader::USAGE_PSIZE, 0); + vertexShader->output[var][1] = sw::Shader::Semantic(sw::Shader::USAGE_PSIZE, 0); + vertexShader->output[var][2] = sw::Shader::Semantic(sw::Shader::USAGE_PSIZE, 0); + vertexShader->output[var][3] = sw::Shader::Semantic(sw::Shader::USAGE_PSIZE, 0); + vertexShader->pointSizeRegister = var; + } + else + { + // Semantic indexes for user varyings will be assigned during program link to match the pixel shader + } + } + else UNREACHABLE(); + + declareVarying(varying, var); + } + + return var; + } + + void OutputASM::declareVarying(TIntermTyped *varying, int reg) + { + if(varying->getQualifier() != EvqPointCoord) // gl_PointCoord does not need linking + { + const TType &type = varying->getType(); + const char *name = varying->getAsSymbolNode()->getSymbol().c_str(); + gl::VaryingList &activeVaryings = shaderObject->varyings; + + // Check if this varying has been declared before without having a register assigned + for(gl::VaryingList::iterator v = activeVaryings.begin(); v != activeVaryings.end(); v++) + { + if(v->name == name) + { + if(reg >= 0) + { + ASSERT(v->reg < 0 || v->reg == reg); + v->reg = reg; + } + + return; + } + } + + activeVaryings.push_back(gl::Varying(glVariableType(type), name, varying->getArraySize(), reg, 0)); + } + } + + int OutputASM::uniformRegister(TIntermTyped *uniform) + { + const TType &type = uniform->getType(); + ASSERT(!IsSampler(type.getBasicType())); + TIntermSymbol *symbol = uniform->getAsSymbolNode(); + ASSERT(symbol); + + if(symbol) + { + int index = lookup(uniforms, uniform); + + if(index == -1) + { + index = allocate(uniforms, uniform); + const TString &name = symbol->getSymbol().c_str(); + + declareUniform(type, name, index); + } + + return index; + } + + return 0; + } + + int OutputASM::attributeRegister(TIntermTyped *attribute) + { + ASSERT(!attribute->isArray()); + ASSERT(attribute->getBasicType() == EbtFloat); + + int index = lookup(attributes, attribute); + + if(index == -1) + { + TIntermSymbol *symbol = attribute->getAsSymbolNode(); + ASSERT(symbol); + + if(symbol) + { + index = allocate(attributes, attribute); + const TType &type = attribute->getType(); + int registerCount = attribute->totalRegisterCount(); + + if(vertexShader && (index + registerCount) <= sw::VertexShader::MAX_INPUT_ATTRIBUTES) + { + for(int i = 0; i < registerCount; i++) + { + vertexShader->input[index + i] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, index + i); + } + } + + ActiveAttributes &activeAttributes = shaderObject->activeAttributes; + + const char *name = symbol->getSymbol().c_str(); + activeAttributes.push_back(Attribute(glVariableType(type), name, 0, index)); + } + } + + return index; + } + + int OutputASM::samplerRegister(TIntermTyped *sampler) + { + const TType &type = sampler->getType(); + ASSERT(IsSampler(type.getBasicType())); + TIntermSymbol *symbol = sampler->getAsSymbolNode(); + TIntermBinary *binary = sampler->getAsBinaryNode(); + + if(symbol) + { + int index = lookup(samplers, sampler); + + if(index == -1) + { + index = allocate(samplers, sampler); + ActiveUniforms &activeUniforms = shaderObject->activeUniforms; + const char *name = symbol->getSymbol().c_str(); + activeUniforms.push_back(Uniform(glVariableType(type), name, sampler->getArraySize(), index)); + + for(int i = 0; i < sampler->totalRegisterCount(); i++) + { + shader->declareSampler(index + i); + } + } + + return index; + } + else if(binary) + { + ASSERT(binary->getOp() == EOpIndexDirect || binary->getOp() == EOpIndexIndirect); + + return samplerRegister(binary->getLeft()); // Index added later + } + else UNREACHABLE(); + + return 0; + } + + int OutputASM::lookup(VariableArray &list, TIntermTyped *variable) + { + for(unsigned int i = 0; i < list.size(); i++) + { + if(list[i] == variable) + { + return i; // Pointer match + } + } + + TIntermSymbol *varSymbol = variable->getAsSymbolNode(); + + if(varSymbol) + { + for(unsigned int i = 0; i < list.size(); i++) + { + if(list[i]) + { + TIntermSymbol *listSymbol = list[i]->getAsSymbolNode(); + + if(listSymbol) + { + if(listSymbol->getId() == varSymbol->getId()) + { + ASSERT(listSymbol->getSymbol() == varSymbol->getSymbol()); + ASSERT(listSymbol->getType() == varSymbol->getType()); + ASSERT(listSymbol->getQualifier() == varSymbol->getQualifier()); + + return i; + } + } + } + } + } + + return -1; + } + + int OutputASM::allocate(VariableArray &list, TIntermTyped *variable) + { + int index = lookup(list, variable); + + if(index == -1) + { + unsigned int registerCount = variable->totalRegisterCount(); + + for(unsigned int i = 0; i < list.size(); i++) + { + if(list[i] == 0) + { + unsigned int j = 1; + for( ; j < registerCount && (i + j) < list.size(); j++) + { + if(list[i + j] != 0) + { + break; + } + } + + if(j == registerCount) // Found free slots + { + for(unsigned int j = 0; j < registerCount; j++) + { + list[i + j] = variable; + } + + return i; + } + } + } + + index = list.size(); + + for(unsigned int i = 0; i < registerCount; i++) + { + list.push_back(variable); + } + } + + return index; + } + + void OutputASM::free(VariableArray &list, TIntermTyped *variable) + { + int index = lookup(list, variable); + + if(index >= 0) + { + list[index] = 0; + } + } + + void OutputASM::declareUniform(const TType &type, const TString &name, int index) + { + const TTypeList *structure = type.getStruct(); + ActiveUniforms &activeUniforms = shaderObject->activeUniforms; + + if(!structure) + { + activeUniforms.push_back(Uniform(glVariableType(type), name.c_str(), type.getArraySize(), index)); + } + else + { + if(type.isArray()) + { + int elementIndex = index; + + for(int i = 0; i < type.getArraySize(); i++) + { + for(size_t j = 0; j < structure->size(); j++) + { + const TType &fieldType = *(*structure)[j].type; + const TString &fieldName = fieldType.getFieldName(); + + const TString uniformName = name + "[" + str(i) + "]." + fieldName; + declareUniform(fieldType, uniformName, elementIndex); + elementIndex += fieldType.totalRegisterCount(); + } + } + } + else + { + int fieldIndex = index; + + for(size_t i = 0; i < structure->size(); i++) + { + const TType &fieldType = *(*structure)[i].type; + const TString &fieldName = fieldType.getFieldName(); + + const TString uniformName = name + "." + fieldName; + declareUniform(fieldType, uniformName, fieldIndex); + fieldIndex += fieldType.totalRegisterCount(); + } + } + } + } + + GLenum OutputASM::glVariableType(const TType &type) + { + if(type.getBasicType() == EbtFloat) + { + if(type.isScalar()) + { + return GL_FLOAT; + } + else if(type.isVector()) + { + switch(type.getNominalSize()) + { + case 2: return GL_FLOAT_VEC2; + case 3: return GL_FLOAT_VEC3; + case 4: return GL_FLOAT_VEC4; + default: UNREACHABLE(); + } + } + else if(type.isMatrix()) + { + switch(type.getNominalSize()) + { + case 2: return GL_FLOAT_MAT2; + case 3: return GL_FLOAT_MAT3; + case 4: return GL_FLOAT_MAT4; + default: UNREACHABLE(); + } + } + else UNREACHABLE(); + } + else if(type.getBasicType() == EbtInt) + { + if(type.isScalar()) + { + return GL_INT; + } + else if(type.isVector()) + { + switch(type.getNominalSize()) + { + case 2: return GL_INT_VEC2; + case 3: return GL_INT_VEC3; + case 4: return GL_INT_VEC4; + default: UNREACHABLE(); + } + } + else UNREACHABLE(); + } + else if(type.getBasicType() == EbtBool) + { + if(type.isScalar()) + { + return GL_BOOL; + } + else if(type.isVector()) + { + switch(type.getNominalSize()) + { + case 2: return GL_BOOL_VEC2; + case 3: return GL_BOOL_VEC3; + case 4: return GL_BOOL_VEC4; + default: UNREACHABLE(); + } + } + else UNREACHABLE(); + } + else if(type.getBasicType() == EbtSampler2D) + { + return GL_SAMPLER_2D; + } + else if(type.getBasicType() == EbtSamplerCube) + { + return GL_SAMPLER_CUBE; + } + else UNREACHABLE(); + + return GL_NONE; + } + + int OutputASM::dim(TIntermNode *v) + { + TIntermTyped *vector = v->getAsTyped(); + ASSERT(vector && vector->isRegister()); + return vector->getNominalSize(); + } + + int OutputASM::dim2(TIntermNode *m) + { + TIntermTyped *matrix = m->getAsTyped(); + ASSERT(matrix && matrix->isMatrix() && !matrix->isArray()); + return matrix->getNominalSize(); + } +}
diff --git a/src/GLES2/compiler/OutputASM.h b/src/GLES2/compiler/OutputASM.h new file mode 100644 index 0000000..c07864f --- /dev/null +++ b/src/GLES2/compiler/OutputASM.h
@@ -0,0 +1,162 @@ +// SwiftShader Software Renderer +// +// Copyright(c) 2005-2013 TransGaming Inc. +// +// All rights reserved. No part of this software may be copied, distributed, transmitted, +// transcribed, stored in a retrieval system, translated into any human or computer +// language by any means, or disclosed to third parties without the explicit written +// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express +// or implied, including but not limited to any patent rights, are granted to you. +// + +#ifndef COMPILER_OUTPUTASM_H_ +#define COMPILER_OUTPUTASM_H_ + +#include "intermediate.h" +#include "ParseHelper.h" +#include "Shader/PixelShader.hpp" +#include "Shader/VertexShader.hpp" + +#define GL_APICALL +#include <GLES2/gl2.h> + +#include <list> +#include <set> +#include <map> + +namespace gl +{ + class Shader; +} + +namespace sh +{ + struct Uniform + { + Uniform(GLenum type, const std::string &name, int arraySize, int registerIndex); + + GLenum type; + std::string name; + int arraySize; + + int registerIndex; + }; + + typedef std::vector<Uniform> ActiveUniforms; + + struct Attribute + { + Attribute(); + Attribute(GLenum type, const std::string &name, int arraySize, int registerIndex); + + GLenum type; + std::string name; + int arraySize; + + int registerIndex; + }; + + struct Function + { + Function(int label, const char *name, TIntermSequence *arg, TIntermTyped *ret) : label(label), name(name), arg(arg), ret(ret) + { + } + + Function(int label, const TString &name, TIntermSequence *arg, TIntermTyped *ret) : label(label), name(name), arg(arg), ret(ret) + { + } + + int label; + TString name; + TIntermSequence *arg; + TIntermTyped *ret; + }; + + typedef sw::Shader::Instruction Instruction; + typedef std::vector<Attribute> ActiveAttributes; + + class Temporary; + + class OutputASM : public TIntermTraverser + { + public: + explicit OutputASM(TParseContext &context, gl::Shader *shaderObject); + ~OutputASM(); + + void output(); + + void freeTemporary(Temporary *temporary); + + protected: + enum Scope + { + GLOBAL, + FUNCTION + }; + + void emitShader(Scope scope); + + // Visit AST nodes and output their code to the body stream + virtual void visitSymbol(TIntermSymbol*); + virtual bool visitBinary(Visit visit, TIntermBinary*); + virtual bool visitUnary(Visit visit, TIntermUnary*); + virtual bool visitSelection(Visit visit, TIntermSelection*); + virtual bool visitAggregate(Visit visit, TIntermAggregate*); + virtual bool visitLoop(Visit visit, TIntermLoop*); + virtual bool visitBranch(Visit visit, TIntermBranch*); + + Instruction *emit(sw::Shader::Opcode op, TIntermTyped *dst = 0, TIntermNode *src0 = 0, TIntermNode *src1 = 0, TIntermNode *src2 = 0); + void emitAssign(sw::Shader::Opcode op, TIntermTyped *result, TIntermTyped *lhs, TIntermTyped *src0, TIntermTyped *src1 = 0); + void emitCmp(sw::Shader::Control cmpOp, TIntermTyped *dst, TIntermNode *left, TIntermNode *right, int index = 0); + void argument(sw::Shader::SourceParameter ¶meter, TIntermNode *argument, int index = 0); + void copy(TIntermTyped *dst, TIntermNode *src, int offset = 0); + void assignLvalue(TIntermTyped *dst, TIntermNode *src); + int lvalue(sw::Shader::DestinationParameter &dst, Temporary &address, TIntermTyped *node); + sw::Shader::ParameterType registerType(TIntermTyped *operand); + int registerIndex(TIntermTyped *operand); + int writeMask(TIntermTyped *destination, int index = 0); + bool trivial(TIntermTyped *expression, int budget); // Fast to compute and no side effects + int cost(TIntermNode *expression, int budget); + const Function &findFunction(const TString &name); + + int temporaryRegister(TIntermTyped *temporary); + int varyingRegister(TIntermTyped *varying); + void declareVarying(TIntermTyped *varying, int reg); + int uniformRegister(TIntermTyped *uniform); + int attributeRegister(TIntermTyped *attribute); + int samplerRegister(TIntermTyped *sampler); + + typedef std::vector<TIntermTyped*> VariableArray; + + int lookup(VariableArray &list, TIntermTyped *variable); + int allocate(VariableArray &list, TIntermTyped *variable); + void free(VariableArray &list, TIntermTyped *variable); + + void declareUniform(const TType &type, const TString &name, int index); + GLenum glVariableType(const TType &type); + + static int dim(TIntermNode *v); + static int dim2(TIntermNode *m); + + gl::Shader *const shaderObject; + sw::Shader *shader; + sw::PixelShader *pixelShader; + sw::VertexShader *vertexShader; + + VariableArray temporaries; + VariableArray uniforms; + VariableArray varyings; + VariableArray attributes; + VariableArray samplers; + + Scope emitScope; + Scope currentScope; + + int currentFunction; + std::vector<Function> functionArray; + + TParseContext &mContext; + }; +} + +#endif // COMPILER_OUTPUTASM_H_
diff --git a/src/GLES2/compiler/ParseHelper.cpp b/src/GLES2/compiler/ParseHelper.cpp new file mode 100644 index 0000000..2107300 --- /dev/null +++ b/src/GLES2/compiler/ParseHelper.cpp
@@ -0,0 +1,1524 @@ +// +// Copyright (c) 2002-2012 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/ParseHelper.h" + +#include <stdarg.h> +#include <stdio.h> + +#include "compiler/glslang.h" +#include "compiler/preprocessor/SourceLocation.h" + +/////////////////////////////////////////////////////////////////////// +// +// Sub- vector and matrix fields +// +//////////////////////////////////////////////////////////////////////// + +// +// Look at a '.' field selector string and change it into offsets +// for a vector. +// +bool TParseContext::parseVectorFields(const TString& compString, int vecSize, TVectorFields& fields, int line) +{ + fields.num = (int) compString.size(); + if (fields.num > 4) { + error(line, "illegal vector field selection", compString.c_str()); + return false; + } + + enum { + exyzw, + ergba, + estpq, + } fieldSet[4]; + + for (int i = 0; i < fields.num; ++i) { + switch (compString[i]) { + case 'x': + fields.offsets[i] = 0; + fieldSet[i] = exyzw; + break; + case 'r': + fields.offsets[i] = 0; + fieldSet[i] = ergba; + break; + case 's': + fields.offsets[i] = 0; + fieldSet[i] = estpq; + break; + case 'y': + fields.offsets[i] = 1; + fieldSet[i] = exyzw; + break; + case 'g': + fields.offsets[i] = 1; + fieldSet[i] = ergba; + break; + case 't': + fields.offsets[i] = 1; + fieldSet[i] = estpq; + break; + case 'z': + fields.offsets[i] = 2; + fieldSet[i] = exyzw; + break; + case 'b': + fields.offsets[i] = 2; + fieldSet[i] = ergba; + break; + case 'p': + fields.offsets[i] = 2; + fieldSet[i] = estpq; + break; + + case 'w': + fields.offsets[i] = 3; + fieldSet[i] = exyzw; + break; + case 'a': + fields.offsets[i] = 3; + fieldSet[i] = ergba; + break; + case 'q': + fields.offsets[i] = 3; + fieldSet[i] = estpq; + break; + default: + error(line, "illegal vector field selection", compString.c_str()); + return false; + } + } + + for (int i = 0; i < fields.num; ++i) { + if (fields.offsets[i] >= vecSize) { + error(line, "vector field selection out of range", compString.c_str()); + return false; + } + + if (i > 0) { + if (fieldSet[i] != fieldSet[i-1]) { + error(line, "illegal - vector component fields not from the same set", compString.c_str()); + return false; + } + } + } + + return true; +} + + +// +// Look at a '.' field selector string and change it into offsets +// for a matrix. +// +bool TParseContext::parseMatrixFields(const TString& compString, int matSize, TMatrixFields& fields, int line) +{ + fields.wholeRow = false; + fields.wholeCol = false; + fields.row = -1; + fields.col = -1; + + if (compString.size() != 2) { + error(line, "illegal length of matrix field selection", compString.c_str()); + return false; + } + + if (compString[0] == '_') { + if (compString[1] < '0' || compString[1] > '3') { + error(line, "illegal matrix field selection", compString.c_str()); + return false; + } + fields.wholeCol = true; + fields.col = compString[1] - '0'; + } else if (compString[1] == '_') { + if (compString[0] < '0' || compString[0] > '3') { + error(line, "illegal matrix field selection", compString.c_str()); + return false; + } + fields.wholeRow = true; + fields.row = compString[0] - '0'; + } else { + if (compString[0] < '0' || compString[0] > '3' || + compString[1] < '0' || compString[1] > '3') { + error(line, "illegal matrix field selection", compString.c_str()); + return false; + } + fields.row = compString[0] - '0'; + fields.col = compString[1] - '0'; + } + + if (fields.row >= matSize || fields.col >= matSize) { + error(line, "matrix field selection out of range", compString.c_str()); + return false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////// +// +// Errors +// +//////////////////////////////////////////////////////////////////////// + +// +// Track whether errors have occurred. +// +void TParseContext::recover() +{ +} + +// +// Used by flex/bison to output all syntax and parsing errors. +// +void TParseContext::error(TSourceLoc loc, + const char* reason, const char* token, + const char* extraInfo) +{ + pp::SourceLocation srcLoc; + DecodeSourceLoc(loc, &srcLoc.file, &srcLoc.line); + diagnostics.writeInfo(pp::Diagnostics::PP_ERROR, + srcLoc, reason, token, extraInfo); + +} + +void TParseContext::warning(TSourceLoc loc, + const char* reason, const char* token, + const char* extraInfo) { + pp::SourceLocation srcLoc; + DecodeSourceLoc(loc, &srcLoc.file, &srcLoc.line); + diagnostics.writeInfo(pp::Diagnostics::PP_WARNING, + srcLoc, reason, token, extraInfo); +} + +void TParseContext::trace(const char* str) +{ + diagnostics.writeDebug(str); +} + +// +// Same error message for all places assignments don't work. +// +void TParseContext::assignError(int line, const char* op, TString left, TString right) +{ + std::stringstream extraInfoStream; + extraInfoStream << "cannot convert from '" << right << "' to '" << left << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, "", op, extraInfo.c_str()); +} + +// +// Same error message for all places unary operations don't work. +// +void TParseContext::unaryOpError(int line, const char* op, TString operand) +{ + std::stringstream extraInfoStream; + extraInfoStream << "no operation '" << op << "' exists that takes an operand of type " << operand + << " (or there is no acceptable conversion)"; + std::string extraInfo = extraInfoStream.str(); + error(line, " wrong operand type", op, extraInfo.c_str()); +} + +// +// Same error message for all binary operations don't work. +// +void TParseContext::binaryOpError(int line, const char* op, TString left, TString right) +{ + std::stringstream extraInfoStream; + extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '" << left + << "' and a right operand of type '" << right << "' (or there is no acceptable conversion)"; + std::string extraInfo = extraInfoStream.str(); + error(line, " wrong operand types ", op, extraInfo.c_str()); +} + +bool TParseContext::precisionErrorCheck(int line, TPrecision precision, TBasicType type){ + if (!checksPrecisionErrors) + return false; + switch( type ){ + case EbtFloat: + if( precision == EbpUndefined ){ + error( line, "No precision specified for (float)", "" ); + return true; + } + break; + case EbtInt: + if( precision == EbpUndefined ){ + error( line, "No precision specified (int)", "" ); + return true; + } + break; + default: + return false; + } + return false; +} + +// +// Both test and if necessary, spit out an error, to see if the node is really +// an l-value that can be operated on this way. +// +// Returns true if the was an error. +// +bool TParseContext::lValueErrorCheck(int line, const char* op, TIntermTyped* node) +{ + TIntermSymbol* symNode = node->getAsSymbolNode(); + TIntermBinary* binaryNode = node->getAsBinaryNode(); + + if (binaryNode) { + bool errorReturn; + + switch(binaryNode->getOp()) { + case EOpIndexDirect: + case EOpIndexIndirect: + case EOpIndexDirectStruct: + return lValueErrorCheck(line, op, binaryNode->getLeft()); + case EOpVectorSwizzle: + errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft()); + if (!errorReturn) { + int offset[4] = {0,0,0,0}; + + TIntermTyped* rightNode = binaryNode->getRight(); + TIntermAggregate *aggrNode = rightNode->getAsAggregate(); + + for (TIntermSequence::iterator p = aggrNode->getSequence().begin(); + p != aggrNode->getSequence().end(); p++) { + int value = (*p)->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); + offset[value]++; + if (offset[value] > 1) { + error(line, " l-value of swizzle cannot have duplicate components", op); + + return true; + } + } + } + + return errorReturn; + default: + break; + } + error(line, " l-value required", op); + + return true; + } + + + const char* symbol = 0; + if (symNode != 0) + symbol = symNode->getSymbol().c_str(); + + const char* message = 0; + switch (node->getQualifier()) { + case EvqConst: message = "can't modify a const"; break; + case EvqConstReadOnly: message = "can't modify a const"; break; + case EvqAttribute: message = "can't modify an attribute"; break; + case EvqUniform: message = "can't modify a uniform"; break; + case EvqVaryingIn: message = "can't modify a varying"; break; + case EvqInput: message = "can't modify an input"; break; + case EvqFragCoord: message = "can't modify gl_FragCoord"; break; + case EvqFrontFacing: message = "can't modify gl_FrontFacing"; break; + case EvqPointCoord: message = "can't modify gl_PointCoord"; break; + default: + + // + // Type that can't be written to? + // + switch (node->getBasicType()) { + case EbtSampler2D: + case EbtSamplerCube: + message = "can't modify a sampler"; + break; + case EbtVoid: + message = "can't modify void"; + break; + default: + break; + } + } + + if (message == 0 && binaryNode == 0 && symNode == 0) { + error(line, " l-value required", op); + + return true; + } + + + // + // Everything else is okay, no error. + // + if (message == 0) + return false; + + // + // If we get here, we have an error and a message. + // + if (symNode) { + std::stringstream extraInfoStream; + extraInfoStream << "\"" << symbol << "\" (" << message << ")"; + std::string extraInfo = extraInfoStream.str(); + error(line, " l-value required", op, extraInfo.c_str()); + } + else { + std::stringstream extraInfoStream; + extraInfoStream << "(" << message << ")"; + std::string extraInfo = extraInfoStream.str(); + error(line, " l-value required", op, extraInfo.c_str()); + } + + return true; +} + +// +// Both test, and if necessary spit out an error, to see if the node is really +// a constant. +// +// Returns true if the was an error. +// +bool TParseContext::constErrorCheck(TIntermTyped* node) +{ + if (node->getQualifier() == EvqConst) + return false; + + error(node->getLine(), "constant expression required", ""); + + return true; +} + +// +// Both test, and if necessary spit out an error, to see if the node is really +// an integer. +// +// Returns true if the was an error. +// +bool TParseContext::integerErrorCheck(TIntermTyped* node, const char* token) +{ + if (node->getBasicType() == EbtInt && node->getNominalSize() == 1) + return false; + + error(node->getLine(), "integer expression required", token); + + return true; +} + +// +// Both test, and if necessary spit out an error, to see if we are currently +// globally scoped. +// +// Returns true if the was an error. +// +bool TParseContext::globalErrorCheck(int line, bool global, const char* token) +{ + if (global) + return false; + + error(line, "only allowed at global scope", token); + + return true; +} + +// +// For now, keep it simple: if it starts "gl_", it's reserved, independent +// of scope. Except, if the symbol table is at the built-in push-level, +// which is when we are parsing built-ins. +// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a +// webgl shader. +// +// Returns true if there was an error. +// +bool TParseContext::reservedErrorCheck(int line, const TString& identifier) +{ + static const char* reservedErrMsg = "reserved built-in name"; + if (!symbolTable.atBuiltInLevel()) { + if (identifier.compare(0, 3, "gl_") == 0) { + error(line, reservedErrMsg, "gl_"); + return true; + } + if (shaderSpec == SH_WEBGL_SPEC) { + if (identifier.compare(0, 6, "webgl_") == 0) { + error(line, reservedErrMsg, "webgl_"); + return true; + } + if (identifier.compare(0, 7, "_webgl_") == 0) { + error(line, reservedErrMsg, "_webgl_"); + return true; + } + } + if (identifier.find("__") != TString::npos) { + error(line, "identifiers containing two consecutive underscores (__) are reserved as possible future keywords", identifier.c_str()); + return true; + } + } + + return false; +} + +// +// Make sure there is enough data provided to the constructor to build +// something of the type of the constructor. Also returns the type of +// the constructor. +// +// Returns true if there was an error in construction. +// +bool TParseContext::constructorErrorCheck(int line, TIntermNode* node, TFunction& function, TOperator op, TType* type) +{ + *type = function.getReturnType(); + + bool constructingMatrix = false; + switch(op) { + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: + constructingMatrix = true; + break; + default: + break; + } + + // + // Note: It's okay to have too many components available, but not okay to have unused + // arguments. 'full' will go to true when enough args have been seen. If we loop + // again, there is an extra argument, so 'overfull' will become true. + // + + int size = 0; + bool constType = true; + bool full = false; + bool overFull = false; + bool matrixInMatrix = false; + bool arrayArg = false; + for (int i = 0; i < function.getParamCount(); ++i) { + const TParameter& param = function.getParam(i); + size += param.type->getObjectSize(); + + if (constructingMatrix && param.type->isMatrix()) + matrixInMatrix = true; + if (full) + overFull = true; + if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize()) + full = true; + if (param.type->getQualifier() != EvqConst) + constType = false; + if (param.type->isArray()) + arrayArg = true; + } + + if (constType) + type->setQualifier(EvqConst); + + if (type->isArray() && type->getArraySize() != function.getParamCount()) { + error(line, "array constructor needs one argument per array element", "constructor"); + return true; + } + + if (arrayArg && op != EOpConstructStruct) { + error(line, "constructing from a non-dereferenced array", "constructor"); + return true; + } + + if (matrixInMatrix && !type->isArray()) { + if (function.getParamCount() != 1) { + error(line, "constructing matrix from matrix can only take one argument", "constructor"); + return true; + } + } + + if (overFull) { + error(line, "too many arguments", "constructor"); + return true; + } + + if (op == EOpConstructStruct && !type->isArray() && int(type->getStruct()->size()) != function.getParamCount()) { + error(line, "Number of constructor parameters does not match the number of structure fields", "constructor"); + return true; + } + + if (!type->isMatrix() || !matrixInMatrix) { + if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) || + (op == EOpConstructStruct && size < type->getObjectSize())) { + error(line, "not enough data provided for construction", "constructor"); + return true; + } + } + + TIntermTyped *typed = node ? node->getAsTyped() : 0; + if (typed == 0) { + error(line, "constructor argument does not have a type", "constructor"); + return true; + } + if (op != EOpConstructStruct && IsSampler(typed->getBasicType())) { + error(line, "cannot convert a sampler", "constructor"); + return true; + } + if (typed->getBasicType() == EbtVoid) { + error(line, "cannot convert a void", "constructor"); + return true; + } + + return false; +} + +// This function checks to see if a void variable has been declared and raise an error message for such a case +// +// returns true in case of an error +// +bool TParseContext::voidErrorCheck(int line, const TString& identifier, const TPublicType& pubType) +{ + if (pubType.type == EbtVoid) { + error(line, "illegal use of type 'void'", identifier.c_str()); + return true; + } + + return false; +} + +// This function checks to see if the node (for the expression) contains a scalar boolean expression or not +// +// returns true in case of an error +// +bool TParseContext::boolErrorCheck(int line, const TIntermTyped* type) +{ + if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) { + error(line, "boolean expression expected", ""); + return true; + } + + return false; +} + +// This function checks to see if the node (for the expression) contains a scalar boolean expression or not +// +// returns true in case of an error +// +bool TParseContext::boolErrorCheck(int line, const TPublicType& pType) +{ + if (pType.type != EbtBool || pType.array || pType.matrix || (pType.size > 1)) { + error(line, "boolean expression expected", ""); + return true; + } + + return false; +} + +bool TParseContext::samplerErrorCheck(int line, const TPublicType& pType, const char* reason) +{ + if (pType.type == EbtStruct) { + if (containsSampler(*pType.userDef)) { + error(line, reason, getBasicString(pType.type), "(structure contains a sampler)"); + + return true; + } + + return false; + } else if (IsSampler(pType.type)) { + error(line, reason, getBasicString(pType.type)); + + return true; + } + + return false; +} + +bool TParseContext::structQualifierErrorCheck(int line, const TPublicType& pType) +{ + if ((pType.qualifier == EvqVaryingIn || pType.qualifier == EvqVaryingOut || pType.qualifier == EvqAttribute) && + pType.type == EbtStruct) { + error(line, "cannot be used with a structure", getQualifierString(pType.qualifier)); + + return true; + } + + if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform")) + return true; + + return false; +} + +bool TParseContext::parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type) +{ + if ((qualifier == EvqOut || qualifier == EvqInOut) && + type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) { + error(line, "samplers cannot be output parameters", type.getBasicString()); + return true; + } + + return false; +} + +bool TParseContext::containsSampler(TType& type) +{ + if (IsSampler(type.getBasicType())) + return true; + + if (type.getBasicType() == EbtStruct) { + TTypeList& structure = *type.getStruct(); + for (unsigned int i = 0; i < structure.size(); ++i) { + if (containsSampler(*structure[i].type)) + return true; + } + } + + return false; +} + +// +// Do size checking for an array type's size. +// +// Returns true if there was an error. +// +bool TParseContext::arraySizeErrorCheck(int line, TIntermTyped* expr, int& size) +{ + TIntermConstantUnion* constant = expr->getAsConstantUnion(); + if (constant == 0 || constant->getBasicType() != EbtInt) { + error(line, "array size must be a constant integer expression", ""); + return true; + } + + size = constant->getUnionArrayPointer()->getIConst(); + + if (size <= 0) { + error(line, "array size must be a positive integer", ""); + size = 1; + return true; + } + + return false; +} + +// +// See if this qualifier can be an array. +// +// Returns true if there is an error. +// +bool TParseContext::arrayQualifierErrorCheck(int line, TPublicType type) +{ + if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqConst)) { + error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str()); + return true; + } + + return false; +} + +// +// See if this type can be an array. +// +// Returns true if there is an error. +// +bool TParseContext::arrayTypeErrorCheck(int line, TPublicType type) +{ + // + // Can the type be an array? + // + if (type.array) { + error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str()); + return true; + } + + return false; +} + +// +// Do all the semantic checking for declaring an array, with and +// without a size, and make the right changes to the symbol table. +// +// size == 0 means no specified size. +// +// Returns true if there was an error. +// +bool TParseContext::arrayErrorCheck(int line, TString& identifier, TPublicType type, TVariable*& variable) +{ + // + // Don't check for reserved word use until after we know it's not in the symbol table, + // because reserved arrays can be redeclared. + // + + bool builtIn = false; + bool sameScope = false; + TSymbol* symbol = symbolTable.find(identifier, &builtIn, &sameScope); + if (symbol == 0 || !sameScope) { + if (reservedErrorCheck(line, identifier)) + return true; + + variable = new TVariable(&identifier, TType(type)); + + if (type.arraySize) + variable->getType().setArraySize(type.arraySize); + + if (! symbolTable.insert(*variable)) { + delete variable; + error(line, "INTERNAL ERROR inserting new symbol", identifier.c_str()); + return true; + } + } else { + if (! symbol->isVariable()) { + error(line, "variable expected", identifier.c_str()); + return true; + } + + variable = static_cast<TVariable*>(symbol); + if (! variable->getType().isArray()) { + error(line, "redeclaring non-array as array", identifier.c_str()); + return true; + } + if (variable->getType().getArraySize() > 0) { + error(line, "redeclaration of array with size", identifier.c_str()); + return true; + } + + if (! variable->getType().sameElementType(TType(type))) { + error(line, "redeclaration of array with a different type", identifier.c_str()); + return true; + } + + TType* t = variable->getArrayInformationType(); + while (t != 0) { + if (t->getMaxArraySize() > type.arraySize) { + error(line, "higher index value already used for the array", identifier.c_str()); + return true; + } + t->setArraySize(type.arraySize); + t = t->getArrayInformationType(); + } + + if (type.arraySize) + variable->getType().setArraySize(type.arraySize); + } + + if (voidErrorCheck(line, identifier, type)) + return true; + + return false; +} + +bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size, bool updateFlag, TSourceLoc line) +{ + bool builtIn = false; + TSymbol* symbol = symbolTable.find(node->getSymbol(), &builtIn); + if (symbol == 0) { + error(line, " undeclared identifier", node->getSymbol().c_str()); + return true; + } + TVariable* variable = static_cast<TVariable*>(symbol); + + type->setArrayInformationType(variable->getArrayInformationType()); + variable->updateArrayInformationType(type); + + // special casing to test index value of gl_FragData. If the accessed index is >= gl_MaxDrawBuffers + // its an error + if (node->getSymbol() == "gl_FragData") { + TSymbol* fragData = symbolTable.find("gl_MaxDrawBuffers", &builtIn); + ASSERT(fragData); + + int fragDataValue = static_cast<TVariable*>(fragData)->getConstPointer()[0].getIConst(); + if (fragDataValue <= size) { + error(line, "", "[", "gl_FragData can only have a max array size of up to gl_MaxDrawBuffers"); + return true; + } + } + + // we dont want to update the maxArraySize when this flag is not set, we just want to include this + // node type in the chain of node types so that its updated when a higher maxArraySize comes in. + if (!updateFlag) + return false; + + size++; + variable->getType().setMaxArraySize(size); + type->setMaxArraySize(size); + TType* tt = type; + + while(tt->getArrayInformationType() != 0) { + tt = tt->getArrayInformationType(); + tt->setMaxArraySize(size); + } + + return false; +} + +// +// Enforce non-initializer type/qualifier rules. +// +// Returns true if there was an error. +// +bool TParseContext::nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type, bool array) +{ + if (type.qualifier == EvqConst) + { + // Make the qualifier make sense. + type.qualifier = EvqTemporary; + + if (array) + { + error(line, "arrays may not be declared constant since they cannot be initialized", identifier.c_str()); + } + else if (type.isStructureContainingArrays()) + { + error(line, "structures containing arrays may not be declared constant since they cannot be initialized", identifier.c_str()); + } + else + { + error(line, "variables with qualifier 'const' must be initialized", identifier.c_str()); + } + + return true; + } + + return false; +} + +// +// Do semantic checking for a variable declaration that has no initializer, +// and update the symbol table. +// +// Returns true if there was an error. +// +bool TParseContext::nonInitErrorCheck(int line, TString& identifier, TPublicType& type, TVariable*& variable) +{ + if (reservedErrorCheck(line, identifier)) + recover(); + + variable = new TVariable(&identifier, TType(type)); + + if (! symbolTable.insert(*variable)) { + error(line, "redefinition", variable->getName().c_str()); + delete variable; + variable = 0; + return true; + } + + if (voidErrorCheck(line, identifier, type)) + return true; + + return false; +} + +bool TParseContext::paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type) +{ + if (qualifier != EvqConst && qualifier != EvqTemporary) { + error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier)); + return true; + } + if (qualifier == EvqConst && paramQualifier != EvqIn) { + error(line, "qualifier not allowed with ", getQualifierString(qualifier), getQualifierString(paramQualifier)); + return true; + } + + if (qualifier == EvqConst) + type->setQualifier(EvqConstReadOnly); + else + type->setQualifier(paramQualifier); + + return false; +} + +bool TParseContext::extensionErrorCheck(int line, const TString& extension) +{ + const TExtensionBehavior& extBehavior = extensionBehavior(); + TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str()); + if (iter == extBehavior.end()) { + error(line, "extension", extension.c_str(), "is not supported"); + return true; + } + // In GLSL ES, an extension's default behavior is "disable". + if (iter->second == EBhDisable || iter->second == EBhUndefined) { + error(line, "extension", extension.c_str(), "is disabled"); + return true; + } + if (iter->second == EBhWarn) { + warning(line, "extension", extension.c_str(), "is being used"); + return false; + } + + return false; +} + +bool TParseContext::supportsExtension(const char* extension) +{ + const TExtensionBehavior& extbehavior = extensionBehavior(); + TExtensionBehavior::const_iterator iter = extbehavior.find(extension); + return (iter != extbehavior.end()); +} + +void TParseContext::handleExtensionDirective(int line, const char* extName, const char* behavior) +{ + pp::SourceLocation loc; + DecodeSourceLoc(line, &loc.file, &loc.line); + directiveHandler.handleExtension(loc, extName, behavior); +} + +void TParseContext::handlePragmaDirective(int line, const char* name, const char* value) +{ + pp::SourceLocation loc; + DecodeSourceLoc(line, &loc.file, &loc.line); + directiveHandler.handlePragma(loc, name, value); +} + +///////////////////////////////////////////////////////////////////////////////// +// +// Non-Errors. +// +///////////////////////////////////////////////////////////////////////////////// + +// +// Look up a function name in the symbol table, and make sure it is a function. +// +// Return the function symbol if found, otherwise 0. +// +const TFunction* TParseContext::findFunction(int line, TFunction* call, bool *builtIn) +{ + // First find by unmangled name to check whether the function name has been + // hidden by a variable name or struct typename. + const TSymbol* symbol = symbolTable.find(call->getName(), builtIn); + if (symbol == 0) { + symbol = symbolTable.find(call->getMangledName(), builtIn); + } + + if (symbol == 0) { + error(line, "no matching overloaded function found", call->getName().c_str()); + return 0; + } + + if (!symbol->isFunction()) { + error(line, "function name expected", call->getName().c_str()); + return 0; + } + + return static_cast<const TFunction*>(symbol); +} + +// +// Initializers show up in several places in the grammar. Have one set of +// code to handle them here. +// +bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType, + TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable) +{ + TType type = TType(pType); + + if (variable == 0) { + if (reservedErrorCheck(line, identifier)) + return true; + + if (voidErrorCheck(line, identifier, pType)) + return true; + + // + // add variable to symbol table + // + variable = new TVariable(&identifier, type); + if (! symbolTable.insert(*variable)) { + error(line, "redefinition", variable->getName().c_str()); + return true; + // don't delete variable, it's used by error recovery, and the pool + // pop will take care of the memory + } + } + + // + // identifier must be of type constant, a global, or a temporary + // + TQualifier qualifier = variable->getType().getQualifier(); + if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) { + error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString()); + return true; + } + // + // test for and propagate constant + // + + if (qualifier == EvqConst) { + if (qualifier != initializer->getType().getQualifier()) { + std::stringstream extraInfoStream; + extraInfoStream << "'" << variable->getType().getCompleteString() << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, " assigning non-constant to", "=", extraInfo.c_str()); + variable->getType().setQualifier(EvqTemporary); + return true; + } + if (type != initializer->getType()) { + error(line, " non-matching types for const initializer ", + variable->getType().getQualifierString()); + variable->getType().setQualifier(EvqTemporary); + return true; + } + if (initializer->getAsConstantUnion()) { + ConstantUnion* unionArray = variable->getConstPointer(); + + if (type.getObjectSize() == 1 && type.getBasicType() != EbtStruct) { + *unionArray = (initializer->getAsConstantUnion()->getUnionArrayPointer())[0]; + } else { + variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer()); + } + } else if (initializer->getAsSymbolNode()) { + const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol()); + const TVariable* tVar = static_cast<const TVariable*>(symbol); + + ConstantUnion* constArray = tVar->getConstPointer(); + variable->shareConstPointer(constArray); + } else { + std::stringstream extraInfoStream; + extraInfoStream << "'" << variable->getType().getCompleteString() << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, " cannot assign to", "=", extraInfo.c_str()); + variable->getType().setQualifier(EvqTemporary); + return true; + } + } + + if (qualifier != EvqConst) { + TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line); + intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line); + if (intermNode == 0) { + assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString()); + return true; + } + } else + intermNode = 0; + + return false; +} + +bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode) +{ + ASSERT(aggrNode != NULL); + if (!aggrNode->isConstructor()) + return false; + + bool allConstant = true; + + // check if all the child nodes are constants so that they can be inserted into + // the parent node + TIntermSequence &sequence = aggrNode->getSequence() ; + for (TIntermSequence::iterator p = sequence.begin(); p != sequence.end(); ++p) { + if (!(*p)->getAsTyped()->getAsConstantUnion()) + return false; + } + + return allConstant; +} + +// This function is used to test for the correctness of the parameters passed to various constructor functions +// and also convert them to the right datatype if it is allowed and required. +// +// Returns 0 for an error or the constructed node (aggregate or typed) for no error. +// +TIntermTyped* TParseContext::addConstructor(TIntermNode* node, const TType* type, TOperator op, TFunction* fnCall, TSourceLoc line) +{ + if (node == 0) + return 0; + + TIntermAggregate* aggrNode = node->getAsAggregate(); + + TTypeList::const_iterator memberTypes; + if (op == EOpConstructStruct) + memberTypes = type->getStruct()->begin(); + + TType elementType = *type; + if (type->isArray()) + elementType.clearArrayness(); + + bool singleArg; + if (aggrNode) { + if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1) + singleArg = true; + else + singleArg = false; + } else + singleArg = true; + + TIntermTyped *newNode; + if (singleArg) { + // If structure constructor or array constructor is being called + // for only one parameter inside the structure, we need to call constructStruct function once. + if (type->isArray()) + newNode = constructStruct(node, &elementType, 1, node->getLine(), false); + else if (op == EOpConstructStruct) + newNode = constructStruct(node, (*memberTypes).type, 1, node->getLine(), false); + else + newNode = constructBuiltIn(type, op, node, node->getLine(), false); + + if (newNode && newNode->getAsAggregate()) { + TIntermTyped* constConstructor = foldConstConstructor(newNode->getAsAggregate(), *type); + if (constConstructor) + return constConstructor; + } + + return newNode; + } + + // + // Handle list of arguments. + // + TIntermSequence &sequenceVector = aggrNode->getSequence() ; // Stores the information about the parameter to the constructor + // if the structure constructor contains more than one parameter, then construct + // each parameter + + int paramCount = 0; // keeps a track of the constructor parameter number being checked + + // for each parameter to the constructor call, check to see if the right type is passed or convert them + // to the right type if possible (and allowed). + // for structure constructors, just check if the right type is passed, no conversion is allowed. + + for (TIntermSequence::iterator p = sequenceVector.begin(); + p != sequenceVector.end(); p++, paramCount++) { + if (type->isArray()) + newNode = constructStruct(*p, &elementType, paramCount+1, node->getLine(), true); + else if (op == EOpConstructStruct) + newNode = constructStruct(*p, (memberTypes[paramCount]).type, paramCount+1, node->getLine(), true); + else + newNode = constructBuiltIn(type, op, *p, node->getLine(), true); + + if (newNode) { + *p = newNode; + } + } + + TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, line); + TIntermTyped* constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type); + if (constConstructor) + return constConstructor; + + return constructor; +} + +TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type) +{ + bool canBeFolded = areAllChildConst(aggrNode); + aggrNode->setType(type); + if (canBeFolded) { + bool returnVal = false; + ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()]; + if (aggrNode->getSequence().size() == 1) { + returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type, true); + } + else { + returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type); + } + if (returnVal) + return 0; + + return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine()); + } + + return 0; +} + +// Function for constructor implementation. Calls addUnaryMath with appropriate EOp value +// for the parameter to the constructor (passed to this function). Essentially, it converts +// the parameter types correctly. If a constructor expects an int (like ivec2) and is passed a +// float, then float is converted to int. +// +// Returns 0 for an error or the constructed node. +// +TIntermTyped* TParseContext::constructBuiltIn(const TType* type, TOperator op, TIntermNode* node, TSourceLoc line, bool subset) +{ + TIntermTyped* newNode; + TOperator basicOp; + + // + // First, convert types as needed. + // + switch (op) { + case EOpConstructVec2: + case EOpConstructVec3: + case EOpConstructVec4: + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: + case EOpConstructFloat: + basicOp = EOpConstructFloat; + break; + + case EOpConstructIVec2: + case EOpConstructIVec3: + case EOpConstructIVec4: + case EOpConstructInt: + basicOp = EOpConstructInt; + break; + + case EOpConstructBVec2: + case EOpConstructBVec3: + case EOpConstructBVec4: + case EOpConstructBool: + basicOp = EOpConstructBool; + break; + + default: + error(line, "unsupported construction", ""); + recover(); + + return 0; + } + newNode = intermediate.addUnaryMath(basicOp, node, node->getLine(), symbolTable); + if (newNode == 0) { + error(line, "can't convert", "constructor"); + return 0; + } + + // + // Now, if there still isn't an operation to do the construction, and we need one, add one. + // + + // Otherwise, skip out early. + if (subset || (newNode != node && newNode->getType() == *type)) + return newNode; + + // setAggregateOperator will insert a new node for the constructor, as needed. + return intermediate.setAggregateOperator(newNode, op, line); +} + +// This function tests for the type of the parameters to the structures constructors. Raises +// an error message if the expected type does not match the parameter passed to the constructor. +// +// Returns 0 for an error or the input node itself if the expected and the given parameter types match. +// +TIntermTyped* TParseContext::constructStruct(TIntermNode* node, TType* type, int paramCount, TSourceLoc line, bool subset) +{ + if (*type == node->getAsTyped()->getType()) { + if (subset) + return node->getAsTyped(); + else + return intermediate.setAggregateOperator(node->getAsTyped(), EOpConstructStruct, line); + } else { + std::stringstream extraInfoStream; + extraInfoStream << "cannot convert parameter " << paramCount + << " from '" << node->getAsTyped()->getType().getBasicString() + << "' to '" << type->getBasicString() << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, "", "constructor", extraInfo.c_str()); + recover(); + } + + return 0; +} + +// +// This function returns the tree representation for the vector field(s) being accessed from contant vector. +// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is +// returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol +// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of +// a constant matrix. +// +TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, TSourceLoc line) +{ + TIntermTyped* typedNode; + TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); + + ConstantUnion *unionArray; + if (tempConstantNode) { + unionArray = tempConstantNode->getUnionArrayPointer(); + ASSERT(unionArray); + + if (!unionArray) { + return node; + } + } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error + error(line, "Cannot offset into the vector", "Error"); + recover(); + + return 0; + } + + ConstantUnion* constArray = new ConstantUnion[fields.num]; + + for (int i = 0; i < fields.num; i++) { + if (fields.offsets[i] >= node->getType().getObjectSize()) { + std::stringstream extraInfoStream; + extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, "", "[", extraInfo.c_str()); + recover(); + fields.offsets[i] = 0; + } + + constArray[i] = unionArray[fields.offsets[i]]; + + } + typedNode = intermediate.addConstantUnion(constArray, node->getType(), line); + return typedNode; +} + +// +// This function returns the column being accessed from a constant matrix. The values are retrieved from +// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input +// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a +// constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure) +// +TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, TSourceLoc line) +{ + TIntermTyped* typedNode; + TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); + + if (index >= node->getType().getNominalSize()) { + std::stringstream extraInfoStream; + extraInfoStream << "matrix field selection out of range '" << index << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, "", "[", extraInfo.c_str()); + recover(); + index = 0; + } + + if (tempConstantNode) { + ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer(); + int size = tempConstantNode->getType().getNominalSize(); + typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line); + } else { + error(line, "Cannot offset into the matrix", "Error"); + recover(); + + return 0; + } + + return typedNode; +} + + +// +// This function returns an element of an array accessed from a constant array. The values are retrieved from +// the symbol table and parse-tree is built for the type of the element. The input +// to the function could either be a symbol node (a[0] where a is a constant array)that represents a +// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure) +// +TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line) +{ + TIntermTyped* typedNode; + TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); + TType arrayElementType = node->getType(); + arrayElementType.clearArrayness(); + + if (index >= node->getType().getArraySize()) { + std::stringstream extraInfoStream; + extraInfoStream << "array field selection out of range '" << index << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, "", "[", extraInfo.c_str()); + recover(); + index = 0; + } + + int arrayElementSize = arrayElementType.getObjectSize(); + + if (tempConstantNode) { + ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer(); + typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line); + } else { + error(line, "Cannot offset into the array", "Error"); + recover(); + + return 0; + } + + return typedNode; +} + + +// +// This function returns the value of a particular field inside a constant structure from the symbol table. +// If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr +// function and returns the parse-tree with the values of the embedded/nested struct. +// +TIntermTyped* TParseContext::addConstStruct(TString& identifier, TIntermTyped* node, TSourceLoc line) +{ + const TTypeList* fields = node->getType().getStruct(); + TIntermTyped *typedNode; + int instanceSize = 0; + unsigned int index = 0; + TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion(); + + for ( index = 0; index < fields->size(); ++index) { + if ((*fields)[index].type->getFieldName() == identifier) { + break; + } else { + instanceSize += (*fields)[index].type->getObjectSize(); + } + } + + if (tempConstantNode) { + ConstantUnion* constArray = tempConstantNode->getUnionArrayPointer(); + + typedNode = intermediate.addConstantUnion(constArray+instanceSize, tempConstantNode->getType(), line); // type will be changed in the calling function + } else { + error(line, "Cannot offset into the structure", "Error"); + recover(); + + return 0; + } + + return typedNode; +} + +bool TParseContext::enterStructDeclaration(int line, const TString& identifier) +{ + ++structNestingLevel; + + // Embedded structure definitions are not supported per GLSL ES spec. + // They aren't allowed in GLSL either, but we need to detect this here + // so we don't rely on the GLSL compiler to catch it. + if (structNestingLevel > 1) { + error(line, "", "Embedded struct definitions are not allowed"); + return true; + } + + return false; +} + +void TParseContext::exitStructDeclaration() +{ + --structNestingLevel; +} + +namespace { + +const int kWebGLMaxStructNesting = 4; + +} // namespace + +bool TParseContext::structNestingErrorCheck(TSourceLoc line, const TType& fieldType) +{ + if (shaderSpec != SH_WEBGL_SPEC) { + return false; + } + + if (fieldType.getBasicType() != EbtStruct) { + return false; + } + + // We're already inside a structure definition at this point, so add + // one to the field's struct nesting. + if (1 + fieldType.getDeepestStructNesting() > kWebGLMaxStructNesting) { + std::stringstream extraInfoStream; + extraInfoStream << "Reference of struct type " << fieldType.getTypeName() + << " exceeds maximum struct nesting of " << kWebGLMaxStructNesting; + std::string extraInfo = extraInfoStream.str(); + error(line, "", "", extraInfo.c_str()); + return true; + } + + return false; +} + +// +// Parse an array of strings using yyparse. +// +// Returns 0 for success. +// +int PaParseStrings(int count, const char* const string[], const int length[], + TParseContext* context) { + if ((count == 0) || (string == NULL)) + return 1; + + if (glslang_initialize(context)) + return 1; + + int error = glslang_scan(count, string, length, context); + if (!error) + error = glslang_parse(context); + + glslang_finalize(context); + + return (error == 0) && (context->numErrors() == 0) ? 0 : 1; +} + + +
diff --git a/src/GLES2/compiler/ParseHelper.h b/src/GLES2/compiler/ParseHelper.h new file mode 100644 index 0000000..668e52a --- /dev/null +++ b/src/GLES2/compiler/ParseHelper.h
@@ -0,0 +1,140 @@ +// +// Copyright (c) 2002-2012 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. +// +#ifndef _PARSER_HELPER_INCLUDED_ +#define _PARSER_HELPER_INCLUDED_ + +#include "compiler/Diagnostics.h" +#include "compiler/DirectiveHandler.h" +#include "compiler/localintermediate.h" +#include "compiler/preprocessor/Preprocessor.h" +#include "compiler/ShHandle.h" +#include "compiler/SymbolTable.h" + +struct TMatrixFields { + bool wholeRow; + bool wholeCol; + int row; + int col; +}; + +// +// The following are extra variables needed during parsing, grouped together so +// they can be passed to the parser without needing a global. +// +struct TParseContext { + TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, ShShaderType type, ShShaderSpec spec, int options, bool checksPrecErrors, const char* sourcePath, TInfoSink& is) : + intermediate(interm), + symbolTable(symt), + shaderType(type), + shaderSpec(spec), + compileOptions(options), + sourcePath(sourcePath), + treeRoot(0), + lexAfterType(false), + loopNestingLevel(0), + structNestingLevel(0), + inTypeParen(false), + currentFunctionType(NULL), + functionReturnsValue(false), + checksPrecisionErrors(checksPrecErrors), + diagnostics(is), + directiveHandler(ext, diagnostics), + preprocessor(&diagnostics, &directiveHandler), + scanner(NULL) { } + TIntermediate& intermediate; // to hold and build a parse tree + TSymbolTable& symbolTable; // symbol table that goes with the language currently being parsed + ShShaderType shaderType; // vertex or fragment language (future: pack or unpack) + ShShaderSpec shaderSpec; // The language specification compiler conforms to - GLES2 or WebGL. + int compileOptions; + const char* sourcePath; // Path of source file or NULL. + TIntermNode* treeRoot; // root of parse tree being created + bool lexAfterType; // true if we've recognized a type, so can only be looking for an identifier + int loopNestingLevel; // 0 if outside all loops + int structNestingLevel; // incremented while parsing a struct declaration + bool inTypeParen; // true if in parentheses, looking only for an identifier + const TType* currentFunctionType; // the return type of the function that's currently being parsed + bool functionReturnsValue; // true if a non-void function has a return + bool checksPrecisionErrors; // true if an error will be generated when a variable is declared without precision, explicit or implicit. + TString HashErrMsg; + bool AfterEOF; + TDiagnostics diagnostics; + TDirectiveHandler directiveHandler; + pp::Preprocessor preprocessor; + void* scanner; + + int numErrors() const { return diagnostics.numErrors(); } + TInfoSink& infoSink() { return diagnostics.infoSink(); } + void error(TSourceLoc loc, const char *reason, const char* token, + const char* extraInfo=""); + void warning(TSourceLoc loc, const char* reason, const char* token, + const char* extraInfo=""); + void trace(const char* str); + void recover(); + + bool parseVectorFields(const TString&, int vecSize, TVectorFields&, int line); + bool parseMatrixFields(const TString&, int matSize, TMatrixFields&, int line); + + bool reservedErrorCheck(int line, const TString& identifier); + void assignError(int line, const char* op, TString left, TString right); + void unaryOpError(int line, const char* op, TString operand); + void binaryOpError(int line, const char* op, TString left, TString right); + bool precisionErrorCheck(int line, TPrecision precision, TBasicType type); + bool lValueErrorCheck(int line, const char* op, TIntermTyped*); + bool constErrorCheck(TIntermTyped* node); + bool integerErrorCheck(TIntermTyped* node, const char* token); + bool globalErrorCheck(int line, bool global, const char* token); + bool constructorErrorCheck(int line, TIntermNode*, TFunction&, TOperator, TType*); + bool arraySizeErrorCheck(int line, TIntermTyped* expr, int& size); + bool arrayQualifierErrorCheck(int line, TPublicType type); + bool arrayTypeErrorCheck(int line, TPublicType type); + bool arrayErrorCheck(int line, TString& identifier, TPublicType type, TVariable*& variable); + bool voidErrorCheck(int, const TString&, const TPublicType&); + bool boolErrorCheck(int, const TIntermTyped*); + bool boolErrorCheck(int, const TPublicType&); + bool samplerErrorCheck(int line, const TPublicType& pType, const char* reason); + bool structQualifierErrorCheck(int line, const TPublicType& pType); + bool parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type); + bool nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type, bool array); + bool nonInitErrorCheck(int line, TString& identifier, TPublicType& type, TVariable*& variable); + bool paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type); + bool extensionErrorCheck(int line, const TString&); + + const TExtensionBehavior& extensionBehavior() const { return directiveHandler.extensionBehavior(); } + bool supportsExtension(const char* extension); + void handleExtensionDirective(int line, const char* extName, const char* behavior); + + const TPragma& pragma() const { return directiveHandler.pragma(); } + void handlePragmaDirective(int line, const char* name, const char* value); + + bool containsSampler(TType& type); + bool areAllChildConst(TIntermAggregate* aggrNode); + const TFunction* findFunction(int line, TFunction* pfnCall, bool *builtIn = 0); + bool executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType, + TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0); + bool arraySetMaxSize(TIntermSymbol*, TType*, int, bool, TSourceLoc); + + TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, TSourceLoc); + TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type); + TIntermTyped* constructStruct(TIntermNode*, TType*, int, TSourceLoc, bool subset); + TIntermTyped* constructBuiltIn(const TType*, TOperator, TIntermNode*, TSourceLoc, bool subset); + TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, TSourceLoc); + TIntermTyped* addConstMatrixNode(int , TIntermTyped*, TSourceLoc); + TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line); + TIntermTyped* addConstStruct(TString& , TIntermTyped*, TSourceLoc); + + // Performs an error check for embedded struct declarations. + // Returns true if an error was raised due to the declaration of + // this struct. + bool enterStructDeclaration(TSourceLoc line, const TString& identifier); + void exitStructDeclaration(); + + bool structNestingErrorCheck(TSourceLoc line, const TType& fieldType); +}; + +int PaParseStrings(int count, const char* const string[], const int length[], + TParseContext* context); + +#endif // _PARSER_HELPER_INCLUDED_
diff --git a/src/GLES2/compiler/PoolAlloc.cpp b/src/GLES2/compiler/PoolAlloc.cpp new file mode 100644 index 0000000..c0ae1ec --- /dev/null +++ b/src/GLES2/compiler/PoolAlloc.cpp
@@ -0,0 +1,309 @@ +// +// Copyright (c) 2002-2012 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/PoolAlloc.h" + +#ifndef _MSC_VER +#include <stdint.h> +#endif +#include <stdio.h> + +#include "compiler/InitializeGlobals.h" +#include "compiler/osinclude.h" + +OS_TLSIndex PoolIndex = OS_INVALID_TLS_INDEX; + +void InitializeGlobalPools() +{ + TThreadGlobalPools* globalPools= static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex)); + if (globalPools) + return; + + TThreadGlobalPools* threadData = new TThreadGlobalPools(); + threadData->globalPoolAllocator = 0; + + OS_SetTLSValue(PoolIndex, threadData); +} + +void FreeGlobalPools() +{ + // Release the allocated memory for this thread. + TThreadGlobalPools* globalPools= static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex)); + if (!globalPools) + return; + + delete globalPools; +} + +bool InitializePoolIndex() +{ + // Allocate a TLS index. + if ((PoolIndex = OS_AllocTLSIndex()) == OS_INVALID_TLS_INDEX) + return false; + + return true; +} + +void FreePoolIndex() +{ + // Release the TLS index. + OS_FreeTLSIndex(PoolIndex); +} + +TPoolAllocator& GetGlobalPoolAllocator() +{ + TThreadGlobalPools* threadData = static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex)); + + return *threadData->globalPoolAllocator; +} + +void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator) +{ + TThreadGlobalPools* threadData = static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex)); + + threadData->globalPoolAllocator = poolAllocator; +} + +// +// Implement the functionality of the TPoolAllocator class, which +// is documented in PoolAlloc.h. +// +TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) : + pageSize(growthIncrement), + alignment(allocationAlignment), + freeList(0), + inUseList(0), + numCalls(0), + totalBytes(0) +{ + // + // Don't allow page sizes we know are smaller than all common + // OS page sizes. + // + if (pageSize < 4*1024) + pageSize = 4*1024; + + // + // A large currentPageOffset indicates a new page needs to + // be obtained to allocate memory. + // + currentPageOffset = pageSize; + + // + // Adjust alignment to be at least pointer aligned and + // power of 2. + // + size_t minAlign = sizeof(void*); + alignment &= ~(minAlign - 1); + if (alignment < minAlign) + alignment = minAlign; + size_t a = 1; + while (a < alignment) + a <<= 1; + alignment = a; + alignmentMask = a - 1; + + // + // Align header skip + // + headerSkip = minAlign; + if (headerSkip < sizeof(tHeader)) { + headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask; + } +} + +TPoolAllocator::~TPoolAllocator() +{ + while (inUseList) { + tHeader* next = inUseList->nextPage; + inUseList->~tHeader(); + delete [] reinterpret_cast<char*>(inUseList); + inUseList = next; + } + + // We should not check the guard blocks + // here, because we did it already when the block was + // placed into the free list. + // + while (freeList) { + tHeader* next = freeList->nextPage; + delete [] reinterpret_cast<char*>(freeList); + freeList = next; + } +} + +// Support MSVC++ 6.0 +const unsigned char TAllocation::guardBlockBeginVal = 0xfb; +const unsigned char TAllocation::guardBlockEndVal = 0xfe; +const unsigned char TAllocation::userDataFill = 0xcd; + +#ifdef GUARD_BLOCKS + const size_t TAllocation::guardBlockSize = 16; +#else + const size_t TAllocation::guardBlockSize = 0; +#endif + +// +// Check a single guard block for damage +// +void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const +{ +#ifdef GUARD_BLOCKS + for (size_t x = 0; x < guardBlockSize; x++) { + if (blockMem[x] != val) { + char assertMsg[80]; + + // We don't print the assert message. It's here just to be helpful. + #if defined(_MSC_VER) + _snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %Iu byte allocation at 0x%p\n", + locText, size, data()); + #else + snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %zu byte allocation at 0x%p\n", + locText, size, data()); + #endif + assert(0 && "PoolAlloc: Damage in guard block"); + } + } +#endif +} + + +void TPoolAllocator::push() +{ + tAllocState state = { currentPageOffset, inUseList }; + + stack.push_back(state); + + // + // Indicate there is no current page to allocate from. + // + currentPageOffset = pageSize; +} + +// +// Do a mass-deallocation of all the individual allocations +// that have occurred since the last push(), or since the +// last pop(), or since the object's creation. +// +// The deallocated pages are saved for future allocations. +// +void TPoolAllocator::pop() +{ + if (stack.size() < 1) + return; + + tHeader* page = stack.back().page; + currentPageOffset = stack.back().offset; + + while (inUseList != page) { + // invoke destructor to free allocation list + inUseList->~tHeader(); + + tHeader* nextInUse = inUseList->nextPage; + if (inUseList->pageCount > 1) + delete [] reinterpret_cast<char*>(inUseList); + else { + inUseList->nextPage = freeList; + freeList = inUseList; + } + inUseList = nextInUse; + } + + stack.pop_back(); +} + +// +// Do a mass-deallocation of all the individual allocations +// that have occurred. +// +void TPoolAllocator::popAll() +{ + while (stack.size() > 0) + pop(); +} + +void* TPoolAllocator::allocate(size_t numBytes) +{ + // If we are using guard blocks, all allocations are bracketed by + // them: [guardblock][allocation][guardblock]. numBytes is how + // much memory the caller asked for. allocationSize is the total + // size including guard blocks. In release build, + // guardBlockSize=0 and this all gets optimized away. + size_t allocationSize = TAllocation::allocationSize(numBytes); + + // + // Just keep some interesting statistics. + // + ++numCalls; + totalBytes += numBytes; + + // + // Do the allocation, most likely case first, for efficiency. + // This step could be moved to be inline sometime. + // + if (currentPageOffset + allocationSize <= pageSize) { + // + // Safe to allocate from currentPageOffset. + // + unsigned char* memory = reinterpret_cast<unsigned char *>(inUseList) + currentPageOffset; + currentPageOffset += allocationSize; + currentPageOffset = (currentPageOffset + alignmentMask) & ~alignmentMask; + + return initializeAllocation(inUseList, memory, numBytes); + } + + if (allocationSize + headerSkip > pageSize) { + // + // Do a multi-page allocation. Don't mix these with the others. + // The OS is efficient and allocating and free-ing multiple pages. + // + size_t numBytesToAlloc = allocationSize + headerSkip; + tHeader* memory = reinterpret_cast<tHeader*>(::new char[numBytesToAlloc]); + if (memory == 0) + return 0; + + // Use placement-new to initialize header + new(memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize); + inUseList = memory; + + currentPageOffset = pageSize; // make next allocation come from a new page + + // No guard blocks for multi-page allocations (yet) + return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(memory) + headerSkip); + } + + // + // Need a simple page to allocate from. + // + tHeader* memory; + if (freeList) { + memory = freeList; + freeList = freeList->nextPage; + } else { + memory = reinterpret_cast<tHeader*>(::new char[pageSize]); + if (memory == 0) + return 0; + } + + // Use placement-new to initialize header + new(memory) tHeader(inUseList, 1); + inUseList = memory; + + unsigned char* ret = reinterpret_cast<unsigned char *>(inUseList) + headerSkip; + currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask; + + return initializeAllocation(inUseList, ret, numBytes); +} + + +// +// Check all allocations in a list for damage by calling check on each. +// +void TAllocation::checkAllocList() const +{ + for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc) + alloc->check(); +}
diff --git a/src/GLES2/compiler/PoolAlloc.h b/src/GLES2/compiler/PoolAlloc.h new file mode 100644 index 0000000..c33dfd9 --- /dev/null +++ b/src/GLES2/compiler/PoolAlloc.h
@@ -0,0 +1,306 @@ +// +// 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. +// + +#ifndef _POOLALLOC_INCLUDED_ +#define _POOLALLOC_INCLUDED_ + +#ifdef _DEBUG +#define GUARD_BLOCKS // define to enable guard block sanity checking +#endif + +// +// This header defines an allocator that can be used to efficiently +// allocate a large number of small requests for heap memory, with the +// intention that they are not individually deallocated, but rather +// collectively deallocated at one time. +// +// This simultaneously +// +// * Makes each individual allocation much more efficient; the +// typical allocation is trivial. +// * Completely avoids the cost of doing individual deallocation. +// * Saves the trouble of tracking down and plugging a large class of leaks. +// +// Individual classes can use this allocator by supplying their own +// new and delete methods. +// +// STL containers can use this allocator by using the pool_allocator +// class as the allocator (second) template argument. +// + +#include <stddef.h> +#include <string.h> +#include <vector> + +// If we are using guard blocks, we must track each indivual +// allocation. If we aren't using guard blocks, these +// never get instantiated, so won't have any impact. +// + +class TAllocation { +public: + TAllocation(size_t size, unsigned char* mem, TAllocation* prev = 0) : + size(size), mem(mem), prevAlloc(prev) { + // Allocations are bracketed: + // [allocationHeader][initialGuardBlock][userData][finalGuardBlock] + // This would be cleaner with if (guardBlockSize)..., but that + // makes the compiler print warnings about 0 length memsets, + // even with the if() protecting them. +#ifdef GUARD_BLOCKS + memset(preGuard(), guardBlockBeginVal, guardBlockSize); + memset(data(), userDataFill, size); + memset(postGuard(), guardBlockEndVal, guardBlockSize); +#endif + } + + void check() const { + checkGuardBlock(preGuard(), guardBlockBeginVal, "before"); + checkGuardBlock(postGuard(), guardBlockEndVal, "after"); + } + + void checkAllocList() const; + + // Return total size needed to accomodate user buffer of 'size', + // plus our tracking data. + inline static size_t allocationSize(size_t size) { + return size + 2 * guardBlockSize + headerSize(); + } + + // Offset from surrounding buffer to get to user data buffer. + inline static unsigned char* offsetAllocation(unsigned char* m) { + return m + guardBlockSize + headerSize(); + } + +private: + void checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const; + + // Find offsets to pre and post guard blocks, and user data buffer + unsigned char* preGuard() const { return mem + headerSize(); } + unsigned char* data() const { return preGuard() + guardBlockSize; } + unsigned char* postGuard() const { return data() + size; } + + size_t size; // size of the user data area + unsigned char* mem; // beginning of our allocation (pts to header) + TAllocation* prevAlloc; // prior allocation in the chain + + // Support MSVC++ 6.0 + const static unsigned char guardBlockBeginVal; + const static unsigned char guardBlockEndVal; + const static unsigned char userDataFill; + + const static size_t guardBlockSize; +#ifdef GUARD_BLOCKS + inline static size_t headerSize() { return sizeof(TAllocation); } +#else + inline static size_t headerSize() { return 0; } +#endif +}; + +// +// There are several stacks. One is to track the pushing and popping +// of the user, and not yet implemented. The others are simply a +// repositories of free pages or used pages. +// +// Page stacks are linked together with a simple header at the beginning +// of each allocation obtained from the underlying OS. Multi-page allocations +// are returned to the OS. Individual page allocations are kept for future +// re-use. +// +// The "page size" used is not, nor must it match, the underlying OS +// page size. But, having it be about that size or equal to a set of +// pages is likely most optimal. +// +class TPoolAllocator { +public: + TPoolAllocator(int growthIncrement = 8*1024, int allocationAlignment = 16); + + // + // Don't call the destructor just to free up the memory, call pop() + // + ~TPoolAllocator(); + + // + // Call push() to establish a new place to pop memory too. Does not + // have to be called to get things started. + // + void push(); + + // + // Call pop() to free all memory allocated since the last call to push(), + // or if no last call to push, frees all memory since first allocation. + // + void pop(); + + // + // Call popAll() to free all memory allocated. + // + void popAll(); + + // + // Call allocate() to actually acquire memory. Returns 0 if no memory + // available, otherwise a properly aligned pointer to 'numBytes' of memory. + // + void* allocate(size_t numBytes); + + // + // There is no deallocate. The point of this class is that + // deallocation can be skipped by the user of it, as the model + // of use is to simultaneously deallocate everything at once + // by calling pop(), and to not have to solve memory leak problems. + // + +protected: + friend struct tHeader; + + struct tHeader { + tHeader(tHeader* nextPage, size_t pageCount) : + nextPage(nextPage), + pageCount(pageCount) +#ifdef GUARD_BLOCKS + , lastAllocation(0) +#endif + { } + + ~tHeader() { +#ifdef GUARD_BLOCKS + if (lastAllocation) + lastAllocation->checkAllocList(); +#endif + } + + tHeader* nextPage; + size_t pageCount; +#ifdef GUARD_BLOCKS + TAllocation* lastAllocation; +#endif + }; + + struct tAllocState { + size_t offset; + tHeader* page; + }; + typedef std::vector<tAllocState> tAllocStack; + + // Track allocations if and only if we're using guard blocks + void* initializeAllocation(tHeader* block, unsigned char* memory, size_t numBytes) { +#ifdef GUARD_BLOCKS + new(memory) TAllocation(numBytes, memory, block->lastAllocation); + block->lastAllocation = reinterpret_cast<TAllocation*>(memory); +#endif + // This is optimized entirely away if GUARD_BLOCKS is not defined. + return TAllocation::offsetAllocation(memory); + } + + size_t pageSize; // granularity of allocation from the OS + size_t alignment; // all returned allocations will be aligned at + // this granularity, which will be a power of 2 + size_t alignmentMask; + size_t headerSkip; // amount of memory to skip to make room for the + // header (basically, size of header, rounded + // up to make it aligned + size_t currentPageOffset; // next offset in top of inUseList to allocate from + tHeader* freeList; // list of popped memory + tHeader* inUseList; // list of all memory currently being used + tAllocStack stack; // stack of where to allocate from, to partition pool + + int numCalls; // just an interesting statistic + size_t totalBytes; // just an interesting statistic +private: + TPoolAllocator& operator=(const TPoolAllocator&); // dont allow assignment operator + TPoolAllocator(const TPoolAllocator&); // dont allow default copy constructor +}; + + +// +// There could potentially be many pools with pops happening at +// different times. But a simple use is to have a global pop +// with everyone using the same global allocator. +// +extern TPoolAllocator& GetGlobalPoolAllocator(); +extern void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator); +#define GlobalPoolAllocator GetGlobalPoolAllocator() + +struct TThreadGlobalPools +{ + TPoolAllocator* globalPoolAllocator; +}; + +// +// This STL compatible allocator is intended to be used as the allocator +// parameter to templatized STL containers, like vector and map. +// +// It will use the pools for allocation, and not +// do any deallocation, but will still do destruction. +// +template<class T> +class pool_allocator { +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + template<class Other> + struct rebind { + typedef pool_allocator<Other> other; + }; + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } + + pool_allocator() : allocator(&GlobalPoolAllocator) { } + pool_allocator(TPoolAllocator& a) : allocator(&a) { } + pool_allocator(const pool_allocator<T>& p) : allocator(p.allocator) { } + + template <class Other> + pool_allocator<T>& operator=(const pool_allocator<Other>& p) { + allocator = p.allocator; + return *this; + } + + template<class Other> + pool_allocator(const pool_allocator<Other>& p) : allocator(&p.getAllocator()) { } + +#if defined(__SUNPRO_CC) && !defined(_RWSTD_ALLOCATOR) + // libCStd on some platforms have a different allocate/deallocate interface. + // Caller pre-bakes sizeof(T) into 'n' which is the number of bytes to be + // allocated, not the number of elements. + void* allocate(size_type n) { + return getAllocator().allocate(n); + } + void* allocate(size_type n, const void*) { + return getAllocator().allocate(n); + } + void deallocate(void*, size_type) {} +#else + pointer allocate(size_type n) { + return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T))); + } + pointer allocate(size_type n, const void*) { + return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T))); + } + void deallocate(pointer, size_type) {} +#endif // _RWSTD_ALLOCATOR + + void construct(pointer p, const T& val) { new ((void *)p) T(val); } + void destroy(pointer p) { p->T::~T(); } + + bool operator==(const pool_allocator& rhs) const { return &getAllocator() == &rhs.getAllocator(); } + bool operator!=(const pool_allocator& rhs) const { return &getAllocator() != &rhs.getAllocator(); } + + size_type max_size() const { return static_cast<size_type>(-1) / sizeof(T); } + size_type max_size(int size) const { return static_cast<size_type>(-1) / size; } + + void setAllocator(TPoolAllocator *a) { allocator = a; } + TPoolAllocator& getAllocator() const { return *allocator; } + +protected: + TPoolAllocator *allocator; +}; + +#endif // _POOLALLOC_INCLUDED_
diff --git a/src/GLES2/compiler/Pragma.h b/src/GLES2/compiler/Pragma.h new file mode 100644 index 0000000..2f74412 --- /dev/null +++ b/src/GLES2/compiler/Pragma.h
@@ -0,0 +1,19 @@ +// +// Copyright (c) 2012 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. +// + +#ifndef COMPILER_PRAGMA_H_ +#define COMPILER_PRAGMA_H_ + +struct TPragma { + // By default optimization is turned on and debug is turned off. + TPragma() : optimize(true), debug(false) { } + TPragma(bool o, bool d) : optimize(o), debug(d) { } + + bool optimize; + bool debug; +}; + +#endif // COMPILER_PRAGMA_H_
diff --git a/src/GLES2/compiler/QualifierAlive.cpp b/src/GLES2/compiler/QualifierAlive.cpp new file mode 100644 index 0000000..92a6874 --- /dev/null +++ b/src/GLES2/compiler/QualifierAlive.cpp
@@ -0,0 +1,58 @@ +// +// 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/intermediate.h" + +class TAliveTraverser : public TIntermTraverser { +public: + TAliveTraverser(TQualifier q) : TIntermTraverser(true, false, false, true), found(false), qualifier(q) + { + } + + bool wasFound() { return found; } + +protected: + bool found; + TQualifier qualifier; + + void visitSymbol(TIntermSymbol*); + bool visitSelection(Visit, TIntermSelection*); +}; + +// +// Report whether or not a variable of the given qualifier type +// is guaranteed written. Not always possible to determine if +// it is written conditionally. +// +// ?? It does not do this well yet, this is just a place holder +// that simply determines if it was reference at all, anywhere. +// +bool QualifierWritten(TIntermNode* node, TQualifier qualifier) +{ + TAliveTraverser it(qualifier); + + if (node) + node->traverse(&it); + + return it.wasFound(); +} + +void TAliveTraverser::visitSymbol(TIntermSymbol* node) +{ + // + // If it's what we're looking for, record it. + // + if (node->getQualifier() == qualifier) + found = true; +} + +bool TAliveTraverser::visitSelection(Visit preVisit, TIntermSelection* node) +{ + if (wasFound()) + return false; + + return true; +}
diff --git a/src/GLES2/compiler/QualifierAlive.h b/src/GLES2/compiler/QualifierAlive.h new file mode 100644 index 0000000..872a06f --- /dev/null +++ b/src/GLES2/compiler/QualifierAlive.h
@@ -0,0 +1,7 @@ +// +// 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. +// + +bool QualifierWritten(TIntermNode* root, TQualifier);
diff --git a/src/GLES2/compiler/RemoveTree.cpp b/src/GLES2/compiler/RemoveTree.cpp new file mode 100644 index 0000000..a4b8c1e --- /dev/null +++ b/src/GLES2/compiler/RemoveTree.cpp
@@ -0,0 +1,77 @@ +// +// 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/intermediate.h" +#include "compiler/RemoveTree.h" + +// +// Code to recursively delete the intermediate tree. +// + +class RemoveTree : public TIntermTraverser +{ +public: + RemoveTree() : TIntermTraverser(false, false, true) + { + } + +protected: + void visitSymbol(TIntermSymbol*); + void visitConstantUnion(TIntermConstantUnion*); + bool visitBinary(Visit visit, TIntermBinary*); + bool visitUnary(Visit visit, TIntermUnary*); + bool visitSelection(Visit visit, TIntermSelection*); + bool visitAggregate(Visit visit, TIntermAggregate*); +}; + +void RemoveTree::visitSymbol(TIntermSymbol* node) +{ + delete node; +} + +bool RemoveTree::visitBinary(Visit visit, TIntermBinary* node) +{ + delete node; + + return true; +} + +bool RemoveTree::visitUnary(Visit visit, TIntermUnary* node) +{ + delete node; + + return true; +} + +bool RemoveTree::visitAggregate(Visit visit, TIntermAggregate* node) +{ + delete node; + + return true; +} + +bool RemoveTree::visitSelection(Visit visit, TIntermSelection* node) +{ + delete node; + + return true; +} + +void RemoveTree::visitConstantUnion(TIntermConstantUnion* node) +{ + delete node; +} + +// +// Entry point. +// +void RemoveAllTreeNodes(TIntermNode* root) +{ + RemoveTree it; + + root->traverse(&it); +} +
diff --git a/src/GLES2/compiler/RemoveTree.h b/src/GLES2/compiler/RemoveTree.h new file mode 100644 index 0000000..97a8216 --- /dev/null +++ b/src/GLES2/compiler/RemoveTree.h
@@ -0,0 +1,7 @@ +// +// 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. +// + +void RemoveAllTreeNodes(TIntermNode*);
diff --git a/src/GLES2/compiler/ShHandle.h b/src/GLES2/compiler/ShHandle.h new file mode 100644 index 0000000..a0105ab --- /dev/null +++ b/src/GLES2/compiler/ShHandle.h
@@ -0,0 +1,108 @@ +// +// Copyright (c) 2002-2012 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. +// + +#ifndef _SHHANDLE_INCLUDED_ +#define _SHHANDLE_INCLUDED_ + +// +// Machine independent part of the compiler private objects +// sent as ShHandle to the driver. +// +// This should not be included by driver code. +// + +#include "GLSLANG/ShaderLang.h" + +#include "compiler/ExtensionBehavior.h" +#include "compiler/InfoSink.h" +#include "compiler/SymbolTable.h" +#include "compiler/VariableInfo.h" + +class TCompiler; + +// +// The base class used to back handles returned to the driver. +// +class TShHandleBase { +public: + TShHandleBase(); + virtual ~TShHandleBase(); + virtual TCompiler* getAsCompiler() { return 0; } + +protected: + // Memory allocator. Allocates and tracks memory required by the compiler. + // Deallocates all memory when compiler is destructed. + TPoolAllocator allocator; +}; + +// +// The base class for the machine dependent compiler to derive from +// for managing object code from the compile. +// +class TCompiler : public TShHandleBase { +public: + TCompiler(ShShaderType type, ShShaderSpec spec); + virtual ~TCompiler(); + virtual TCompiler* getAsCompiler() { return this; } + + bool Init(const ShBuiltInResources& resources); + bool compile(const char* const shaderStrings[], + const int numStrings, + int compileOptions); + + // Get results of the last compilation. + TInfoSink& getInfoSink() { return infoSink; } + const TVariableInfoList& getAttribs() const { return attribs; } + const TVariableInfoList& getUniforms() const { return uniforms; } + +protected: + ShShaderType getShaderType() const { return shaderType; } + ShShaderSpec getShaderSpec() const { return shaderSpec; } + // Initialize symbol-table with built-in symbols. + bool InitBuiltInSymbolTable(const ShBuiltInResources& resources); + // Clears the results from the previous compilation. + void clearResults(); + // Return true if function recursion is detected. + bool detectRecursion(TIntermNode* root); + // Returns true if the given shader does not exceed the minimum + // functionality mandated in GLSL 1.0 spec Appendix A. + bool validateLimitations(TIntermNode* root); + // Collect info for all attribs and uniforms. + void collectAttribsUniforms(TIntermNode* root); + // Translate to object code. + virtual void translate(TIntermNode* root) = 0; + // Get built-in extensions with default behavior. + const TExtensionBehavior& getExtensionBehavior() const; + +private: + ShShaderType shaderType; + ShShaderSpec shaderSpec; + + // Built-in symbol table for the given language, spec, and resources. + // It is preserved from compile-to-compile. + TSymbolTable symbolTable; + // Built-in extensions with default behavior. + TExtensionBehavior extensionBehavior; + + // Results of compilation. + TInfoSink infoSink; // Output sink. + TVariableInfoList attribs; // Active attributes in the compiled shader. + TVariableInfoList uniforms; // Active uniforms in the compiled shader. +}; + +// +// This is the interface between the machine independent code +// and the machine dependent code. +// +// The machine dependent code should derive from the classes +// above. Then Construct*() and Delete*() will create and +// destroy the machine dependent objects, which contain the +// above machine independent information. +// +TCompiler* ConstructCompiler(ShShaderType type, ShShaderSpec spec); +void DeleteCompiler(TCompiler*); + +#endif // _SHHANDLE_INCLUDED_
diff --git a/src/GLES2/compiler/ShaderLang.cpp b/src/GLES2/compiler/ShaderLang.cpp new file mode 100644 index 0000000..0da8247 --- /dev/null +++ b/src/GLES2/compiler/ShaderLang.cpp
@@ -0,0 +1,259 @@ +// +// Copyright (c) 2002-2012 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. +// + +// +// Implement the top-level of interface to the compiler, +// as defined in ShaderLang.h +// + +#include "GLSLANG/ShaderLang.h" + +#include "compiler/InitializeDll.h" +#include "compiler/preprocessor/length_limits.h" +#include "compiler/ShHandle.h" + +// +// This is the platform independent interface between an OGL driver +// and the shading language compiler. +// + +static bool checkActiveUniformAndAttribMaxLengths(const ShHandle handle, + int expectedValue) +{ + int activeUniformLimit = 0; + ShGetInfo(handle, SH_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformLimit); + int activeAttribLimit = 0; + ShGetInfo(handle, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttribLimit); + return (expectedValue == activeUniformLimit && expectedValue == activeAttribLimit); +} + +static void getVariableInfo(ShShaderInfo varType, + const ShHandle handle, + int index, + int* length, + int* size, + ShDataType* type, + char* name) +{ + if (!handle || !size || !type || !name) + return; + ASSERT((varType == SH_ACTIVE_ATTRIBUTES) || + (varType == SH_ACTIVE_UNIFORMS)); + + TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle); + TCompiler* compiler = base->getAsCompiler(); + if (compiler == 0) + return; + + const TVariableInfoList& varList = varType == SH_ACTIVE_ATTRIBUTES ? + compiler->getAttribs() : compiler->getUniforms(); + if (index < 0 || index >= static_cast<int>(varList.size())) + return; + + const TVariableInfo& varInfo = varList[index]; + if (length) *length = varInfo.name.size(); + *size = varInfo.size; + *type = varInfo.type; + + // This size must match that queried by + // SH_ACTIVE_UNIFORM_MAX_LENGTH and SH_ACTIVE_ATTRIBUTE_MAX_LENGTH + // in ShGetInfo, below. + int activeUniformAndAttribLength = 1 + MAX_SYMBOL_NAME_LEN; + ASSERT(checkActiveUniformAndAttribMaxLengths(handle, activeUniformAndAttribLength)); + strncpy(name, varInfo.name.c_str(), activeUniformAndAttribLength); + name[activeUniformAndAttribLength - 1] = 0; +} + +// +// Driver must call this first, once, before doing any other +// compiler operations. +// +int ShInitialize() +{ + if (!InitProcess()) + return 0; + + return 1; +} + +// +// Cleanup symbol tables +// +int ShFinalize() +{ + if (!DetachProcess()) + return 0; + + return 1; +} + +// +// Initialize built-in resources with minimum expected values. +// +void ShInitBuiltInResources(ShBuiltInResources* resources) +{ + // Constants. + resources->MaxVertexAttribs = 8; + resources->MaxVertexUniformVectors = 128; + resources->MaxVaryingVectors = 8; + resources->MaxVertexTextureImageUnits = 0; + resources->MaxCombinedTextureImageUnits = 8; + resources->MaxTextureImageUnits = 8; + resources->MaxFragmentUniformVectors = 16; + resources->MaxDrawBuffers = 1; + + // Extensions. + resources->OES_standard_derivatives = 0; +} + +// +// Driver calls these to create and destroy compiler objects. +// +ShHandle ShConstructCompiler(ShShaderType type, ShShaderSpec spec, + const ShBuiltInResources* resources) +{ + if (!InitThread()) + return 0; + + TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(type, spec)); + TCompiler* compiler = base->getAsCompiler(); + if (compiler == 0) + return 0; + + // Generate built-in symbol table. + if (!compiler->Init(*resources)) { + ShDestruct(base); + return 0; + } + + return reinterpret_cast<void*>(base); +} + +void ShDestruct(ShHandle handle) +{ + if (handle == 0) + return; + + TShHandleBase* base = static_cast<TShHandleBase*>(handle); + + if (base->getAsCompiler()) + DeleteCompiler(base->getAsCompiler()); +} + +// +// Do an actual compile on the given strings. The result is left +// in the given compile object. +// +// Return: The return value of ShCompile is really boolean, indicating +// success or failure. +// +int ShCompile( + const ShHandle handle, + const char* const shaderStrings[], + const int numStrings, + int compileOptions) +{ + if (!InitThread()) + return 0; + + if (handle == 0) + return 0; + + TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle); + TCompiler* compiler = base->getAsCompiler(); + if (compiler == 0) + return 0; + + bool success = compiler->compile(shaderStrings, numStrings, compileOptions); + return success ? 1 : 0; +} + +void ShGetInfo(const ShHandle handle, ShShaderInfo pname, int* params) +{ + if (!handle || !params) + return; + + TShHandleBase* base = static_cast<TShHandleBase*>(handle); + TCompiler* compiler = base->getAsCompiler(); + if (!compiler) return; + + switch(pname) + { + case SH_INFO_LOG_LENGTH: + *params = compiler->getInfoSink().info.size() + 1; + break; + case SH_OBJECT_CODE_LENGTH: + *params = compiler->getInfoSink().obj.size() + 1; + break; + case SH_ACTIVE_UNIFORMS: + *params = compiler->getUniforms().size(); + break; + case SH_ACTIVE_UNIFORM_MAX_LENGTH: + *params = 1 + MAX_SYMBOL_NAME_LEN; + break; + case SH_ACTIVE_ATTRIBUTES: + *params = compiler->getAttribs().size(); + break; + case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH: + *params = 1 + MAX_SYMBOL_NAME_LEN; + break; + default: UNREACHABLE(); + } +} + +// +// Return any compiler log of messages for the application. +// +void ShGetInfoLog(const ShHandle handle, char* infoLog) +{ + if (!handle || !infoLog) + return; + + TShHandleBase* base = static_cast<TShHandleBase*>(handle); + TCompiler* compiler = base->getAsCompiler(); + if (!compiler) return; + + TInfoSink& infoSink = compiler->getInfoSink(); + strcpy(infoLog, infoSink.info.c_str()); +} + +// +// Return any object code. +// +void ShGetObjectCode(const ShHandle handle, char* objCode) +{ + if (!handle || !objCode) + return; + + TShHandleBase* base = static_cast<TShHandleBase*>(handle); + TCompiler* compiler = base->getAsCompiler(); + if (!compiler) return; + + TInfoSink& infoSink = compiler->getInfoSink(); + strcpy(objCode, infoSink.obj.c_str()); +} + +void ShGetActiveAttrib(const ShHandle handle, + int index, + int* length, + int* size, + ShDataType* type, + char* name) +{ + getVariableInfo(SH_ACTIVE_ATTRIBUTES, + handle, index, length, size, type, name); +} + +void ShGetActiveUniform(const ShHandle handle, + int index, + int* length, + int* size, + ShDataType* type, + char* name) +{ + getVariableInfo(SH_ACTIVE_UNIFORMS, + handle, index, length, size, type, name); +}
diff --git a/src/GLES2/compiler/SymbolTable.cpp b/src/GLES2/compiler/SymbolTable.cpp new file mode 100644 index 0000000..adf56a8 --- /dev/null +++ b/src/GLES2/compiler/SymbolTable.cpp
@@ -0,0 +1,284 @@ +// +// Copyright (c) 2002-2012 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. +// + +// +// Symbol table for parsing. Most functionaliy and main ideas +// are documented in the header file. +// + +#if defined(_MSC_VER) +#pragma warning(disable: 4718) +#endif + +#include "compiler/SymbolTable.h" + +#include <stdio.h> +#include <algorithm> + +#if defined(_MSC_VER) +#define snprintf _snprintf +#endif + +TType::TType(const TPublicType &p) : + type(p.type), precision(p.precision), qualifier(p.qualifier), size(p.size), matrix(p.matrix), array(p.array), arraySize(p.arraySize), + maxArraySize(0), arrayInformationType(0), structure(0), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0), typeName(0) +{ + if (p.userDef) + { + structure = p.userDef->getStruct(); + typeName = NewPoolTString(p.userDef->getTypeName().c_str()); + computeDeepestStructNesting(); + } +} + +// +// Recursively generate mangled names. +// +void TType::buildMangledName(TString& mangledName) +{ + if (isMatrix()) + mangledName += 'm'; + else if (isVector()) + mangledName += 'v'; + + switch (type) { + case EbtFloat: mangledName += 'f'; break; + case EbtInt: mangledName += 'i'; break; + case EbtBool: mangledName += 'b'; break; + case EbtSampler2D: mangledName += "s2"; break; + case EbtSamplerCube: mangledName += "sC"; break; + case EbtStruct: + mangledName += "struct-"; + if (typeName) + mangledName += *typeName; + {// support MSVC++6.0 + for (unsigned int i = 0; i < structure->size(); ++i) { + mangledName += '-'; + (*structure)[i].type->buildMangledName(mangledName); + } + } + default: + break; + } + + mangledName += static_cast<char>('0' + getNominalSize()); + if (isArray()) { + char buf[20]; + snprintf(buf, sizeof(buf), "%d", arraySize); + mangledName += '['; + mangledName += buf; + mangledName += ']'; + } +} + +int TType::getStructSize() const +{ + if (!getStruct()) { + assert(false && "Not a struct"); + return 0; + } + + if (structureSize == 0) + for (TTypeList::const_iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++) + structureSize += ((*tl).type)->getObjectSize(); + + return structureSize; +} + +void TType::computeDeepestStructNesting() +{ + if (!structure) + { + return; + } + + int maxNesting = 0; + for (TTypeList::const_iterator tl = structure->begin(); tl != structure->end(); tl++) + { + maxNesting = std::max(maxNesting, ((*tl).type)->getDeepestStructNesting()); + } + + deepestStructNesting = 1 + maxNesting; +} + +bool TType::isStructureContainingArrays() const +{ + if (!structure) + { + return false; + } + + for (TTypeList::const_iterator member = structure->begin(); member != structure->end(); member++) + { + if (member->type->isArray() || + member->type->isStructureContainingArrays()) + { + return true; + } + } + + return false; +} + +// +// Dump functions. +// + +void TVariable::dump(TInfoSink& infoSink) const +{ + infoSink.debug << getName().c_str() << ": " << type.getQualifierString() << " " << type.getPrecisionString() << " " << type.getBasicString(); + if (type.isArray()) { + infoSink.debug << "[0]"; + } + infoSink.debug << "\n"; +} + +void TFunction::dump(TInfoSink &infoSink) const +{ + infoSink.debug << getName().c_str() << ": " << returnType.getBasicString() << " " << getMangledName().c_str() << "\n"; +} + +void TSymbolTableLevel::dump(TInfoSink &infoSink) const +{ + tLevel::const_iterator it; + for (it = level.begin(); it != level.end(); ++it) + (*it).second->dump(infoSink); +} + +void TSymbolTable::dump(TInfoSink &infoSink) const +{ + for (int level = currentLevel(); level >= 0; --level) { + infoSink.debug << "LEVEL " << level << "\n"; + table[level]->dump(infoSink); + } +} + +// +// Functions have buried pointers to delete. +// +TFunction::~TFunction() +{ + for (TParamList::iterator i = parameters.begin(); i != parameters.end(); ++i) + delete (*i).type; +} + +// +// Symbol table levels are a map of pointers to symbols that have to be deleted. +// +TSymbolTableLevel::~TSymbolTableLevel() +{ + for (tLevel::iterator it = level.begin(); it != level.end(); ++it) + delete (*it).second; +} + +// +// Change all function entries in the table with the non-mangled name +// to be related to the provided built-in operation. This is a low +// performance operation, and only intended for symbol tables that +// live across a large number of compiles. +// +void TSymbolTableLevel::relateToOperator(const char* name, TOperator op) +{ + tLevel::iterator it; + for (it = level.begin(); it != level.end(); ++it) { + if ((*it).second->isFunction()) { + TFunction* function = static_cast<TFunction*>((*it).second); + if (function->getName() == name) + function->relateToOperator(op); + } + } +} + +// +// Change all function entries in the table with the non-mangled name +// to be related to the provided built-in extension. This is a low +// performance operation, and only intended for symbol tables that +// live across a large number of compiles. +// +void TSymbolTableLevel::relateToExtension(const char* name, const TString& ext) +{ + for (tLevel::iterator it = level.begin(); it != level.end(); ++it) { + if (it->second->isFunction()) { + TFunction* function = static_cast<TFunction*>(it->second); + if (function->getName() == name) + function->relateToExtension(ext); + } + } +} + +TSymbol::TSymbol(const TSymbol& copyOf) +{ + name = NewPoolTString(copyOf.name->c_str()); + uniqueId = copyOf.uniqueId; +} + +TVariable::TVariable(const TVariable& copyOf, TStructureMap& remapper) : TSymbol(copyOf) +{ + type.copyType(copyOf.type, remapper); + userType = copyOf.userType; + // for builtIn symbol table level, unionArray and arrayInformation pointers should be NULL + assert(copyOf.arrayInformationType == 0); + arrayInformationType = 0; + + if (copyOf.unionArray) { + assert(!copyOf.type.getStruct()); + assert(copyOf.type.getObjectSize() == 1); + unionArray = new ConstantUnion[1]; + unionArray[0] = copyOf.unionArray[0]; + } else + unionArray = 0; +} + +TVariable* TVariable::clone(TStructureMap& remapper) +{ + TVariable *variable = new TVariable(*this, remapper); + + return variable; +} + +TFunction::TFunction(const TFunction& copyOf, TStructureMap& remapper) : TSymbol(copyOf) +{ + for (unsigned int i = 0; i < copyOf.parameters.size(); ++i) { + TParameter param; + parameters.push_back(param); + parameters.back().copyParam(copyOf.parameters[i], remapper); + } + + returnType.copyType(copyOf.returnType, remapper); + mangledName = copyOf.mangledName; + op = copyOf.op; + defined = copyOf.defined; +} + +TFunction* TFunction::clone(TStructureMap& remapper) +{ + TFunction *function = new TFunction(*this, remapper); + + return function; +} + +TSymbolTableLevel* TSymbolTableLevel::clone(TStructureMap& remapper) +{ + TSymbolTableLevel *symTableLevel = new TSymbolTableLevel(); + tLevel::iterator iter; + for (iter = level.begin(); iter != level.end(); ++iter) { + symTableLevel->insert(*iter->second->clone(remapper)); + } + + return symTableLevel; +} + +void TSymbolTable::copyTable(const TSymbolTable& copyOf) +{ + TStructureMap remapper; + uniqueId = copyOf.uniqueId; + for (unsigned int i = 0; i < copyOf.table.size(); ++i) { + table.push_back(copyOf.table[i]->clone(remapper)); + } + for( unsigned int i = 0; i < copyOf.precisionStack.size(); i++) { + precisionStack.push_back( copyOf.precisionStack[i] ); + } +}
diff --git a/src/GLES2/compiler/SymbolTable.h b/src/GLES2/compiler/SymbolTable.h new file mode 100644 index 0000000..40d7012 --- /dev/null +++ b/src/GLES2/compiler/SymbolTable.h
@@ -0,0 +1,359 @@ +// +// Copyright (c) 2002-2012 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. +// + +#ifndef _SYMBOL_TABLE_INCLUDED_ +#define _SYMBOL_TABLE_INCLUDED_ + +// +// Symbol table for parsing. Has these design characteristics: +// +// * Same symbol table can be used to compile many shaders, to preserve +// effort of creating and loading with the large numbers of built-in +// symbols. +// +// * Name mangling will be used to give each function a unique name +// so that symbol table lookups are never ambiguous. This allows +// a simpler symbol table structure. +// +// * Pushing and popping of scope, so symbol table will really be a stack +// of symbol tables. Searched from the top, with new inserts going into +// the top. +// +// * Constants: Compile time constant symbols will keep their values +// in the symbol table. The parser can substitute constants at parse +// time, including doing constant folding and constant propagation. +// +// * No temporaries: Temporaries made from operations (+, --, .xy, etc.) +// are tracked in the intermediate representation, not the symbol table. +// + +#include <assert.h> + +#include "compiler/InfoSink.h" +#include "compiler/intermediate.h" + +// +// Symbol base class. (Can build functions or variables out of these...) +// +class TSymbol { +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + TSymbol(const TString *n) : name(n) { } + virtual ~TSymbol() { /* don't delete name, it's from the pool */ } + const TString& getName() const { return *name; } + virtual const TString& getMangledName() const { return getName(); } + virtual bool isFunction() const { return false; } + virtual bool isVariable() const { return false; } + void setUniqueId(int id) { uniqueId = id; } + int getUniqueId() const { return uniqueId; } + virtual void dump(TInfoSink &infoSink) const = 0; + TSymbol(const TSymbol&); + virtual TSymbol* clone(TStructureMap& remapper) = 0; + +protected: + const TString *name; + unsigned int uniqueId; // For real comparing during code generation +}; + +// +// Variable class, meaning a symbol that's not a function. +// +// There could be a separate class heirarchy for Constant variables; +// Only one of int, bool, or float, (or none) is correct for +// any particular use, but it's easy to do this way, and doesn't +// seem worth having separate classes, and "getConst" can't simply return +// different values for different types polymorphically, so this is +// just simple and pragmatic. +// +class TVariable : public TSymbol { +public: + TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0), arrayInformationType(0) { } + virtual ~TVariable() { } + virtual bool isVariable() const { return true; } + TType& getType() { return type; } + const TType& getType() const { return type; } + bool isUserType() const { return userType; } + void setQualifier(TQualifier qualifier) { type.setQualifier(qualifier); } + void updateArrayInformationType(TType *t) { arrayInformationType = t; } + TType* getArrayInformationType() { return arrayInformationType; } + + virtual void dump(TInfoSink &infoSink) const; + + ConstantUnion* getConstPointer() + { + if (!unionArray) + unionArray = new ConstantUnion[type.getObjectSize()]; + + return unionArray; + } + + ConstantUnion* getConstPointer() const { return unionArray; } + + void shareConstPointer( ConstantUnion *constArray) + { + if (unionArray == constArray) + return; + + delete[] unionArray; + unionArray = constArray; + } + TVariable(const TVariable&, TStructureMap& remapper); // copy constructor + virtual TVariable* clone(TStructureMap& remapper); + +protected: + TType type; + bool userType; + // we are assuming that Pool Allocator will free the memory allocated to unionArray + // when this object is destroyed + ConstantUnion *unionArray; + TType *arrayInformationType; // this is used for updating maxArraySize in all the references to a given symbol +}; + +// +// The function sub-class of symbols and the parser will need to +// share this definition of a function parameter. +// +struct TParameter { + TString *name; + TType* type; + void copyParam(const TParameter& param, TStructureMap& remapper) + { + name = NewPoolTString(param.name->c_str()); + type = param.type->clone(remapper); + } +}; + +// +// The function sub-class of a symbol. +// +class TFunction : public TSymbol { +public: + TFunction(TOperator o) : + TSymbol(0), + returnType(TType(EbtVoid, EbpUndefined)), + op(o), + defined(false) { } + TFunction(const TString *name, TType& retType, TOperator tOp = EOpNull) : + TSymbol(name), + returnType(retType), + mangledName(TFunction::mangleName(*name)), + op(tOp), + defined(false) { } + virtual ~TFunction(); + virtual bool isFunction() const { return true; } + + static TString mangleName(const TString& name) { return name + '('; } + static TString unmangleName(const TString& mangledName) + { + return TString(mangledName.c_str(), mangledName.find_first_of('(')); + } + + void addParameter(TParameter& p) + { + parameters.push_back(p); + mangledName = mangledName + p.type->getMangledName(); + } + + const TString& getMangledName() const { return mangledName; } + const TType& getReturnType() const { return returnType; } + + void relateToOperator(TOperator o) { op = o; } + TOperator getBuiltInOp() const { return op; } + + void relateToExtension(const TString& ext) { extension = ext; } + const TString& getExtension() const { return extension; } + + void setDefined() { defined = true; } + bool isDefined() { return defined; } + + int getParamCount() const { return static_cast<int>(parameters.size()); } + const TParameter& getParam(int i) const { return parameters[i]; } + + virtual void dump(TInfoSink &infoSink) const; + TFunction(const TFunction&, TStructureMap& remapper); + virtual TFunction* clone(TStructureMap& remapper); + +protected: + typedef TVector<TParameter> TParamList; + TParamList parameters; + TType returnType; + TString mangledName; + TOperator op; + TString extension; + bool defined; +}; + + +class TSymbolTableLevel { +public: + typedef TMap<TString, TSymbol*> tLevel; + typedef tLevel::const_iterator const_iterator; + typedef const tLevel::value_type tLevelPair; + typedef std::pair<tLevel::iterator, bool> tInsertResult; + + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + TSymbolTableLevel() { } + ~TSymbolTableLevel(); + + bool insert(TSymbol& symbol) + { + // + // returning true means symbol was added to the table + // + tInsertResult result; + result = level.insert(tLevelPair(symbol.getMangledName(), &symbol)); + + return result.second; + } + + TSymbol* find(const TString& name) const + { + tLevel::const_iterator it = level.find(name); + if (it == level.end()) + return 0; + else + return (*it).second; + } + + const_iterator begin() const + { + return level.begin(); + } + + const_iterator end() const + { + return level.end(); + } + + void relateToOperator(const char* name, TOperator op); + void relateToExtension(const char* name, const TString& ext); + void dump(TInfoSink &infoSink) const; + TSymbolTableLevel* clone(TStructureMap& remapper); + +protected: + tLevel level; +}; + +class TSymbolTable { +public: + TSymbolTable() : uniqueId(0) + { + // + // The symbol table cannot be used until push() is called, but + // the lack of an initial call to push() can be used to detect + // that the symbol table has not been preloaded with built-ins. + // + } + + ~TSymbolTable() + { + // level 0 is always built In symbols, so we never pop that out + while (table.size() > 1) + pop(); + } + + // + // When the symbol table is initialized with the built-ins, there should + // 'push' calls, so that built-ins are at level 0 and the shader + // globals are at level 1. + // + bool isEmpty() { return table.size() == 0; } + bool atBuiltInLevel() { return table.size() == 1; } + bool atGlobalLevel() { return table.size() <= 2; } + void push() + { + table.push_back(new TSymbolTableLevel); + precisionStack.push_back( PrecisionStackLevel() ); + } + + void pop() + { + delete table[currentLevel()]; + table.pop_back(); + precisionStack.pop_back(); + } + + bool insert(TSymbol& symbol) + { + symbol.setUniqueId(++uniqueId); + return table[currentLevel()]->insert(symbol); + } + + TSymbol* find(const TString& name, bool* builtIn = 0, bool *sameScope = 0) + { + int level = currentLevel(); + TSymbol* symbol; + do { + symbol = table[level]->find(name); + --level; + } while (symbol == 0 && level >= 0); + level++; + if (builtIn) + *builtIn = level == 0; + if (sameScope) + *sameScope = level == currentLevel(); + return symbol; + } + + TSymbol *findBuiltIn(const TString &name) + { + return table[0]->find(name); + } + + TSymbolTableLevel* getGlobalLevel() { + assert(table.size() >= 2); + return table[1]; + } + + TSymbolTableLevel* getOuterLevel() { + assert(table.size() >= 2); + return table[currentLevel() - 1]; + } + + void relateToOperator(const char* name, TOperator op) { + table[0]->relateToOperator(name, op); + } + void relateToExtension(const char* name, const TString& ext) { + table[0]->relateToExtension(name, ext); + } + int getMaxSymbolId() { return uniqueId; } + void dump(TInfoSink &infoSink) const; + void copyTable(const TSymbolTable& copyOf); + + void setDefaultPrecision( TBasicType type, TPrecision prec ){ + if( type != EbtFloat && type != EbtInt ) return; // Only set default precision for int/float + int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1; + precisionStack[indexOfLastElement][type] = prec; // Uses map operator [], overwrites the current value + } + + // Searches down the precisionStack for a precision qualifier for the specified TBasicType + TPrecision getDefaultPrecision( TBasicType type){ + if( type != EbtFloat && type != EbtInt ) return EbpUndefined; + int level = static_cast<int>(precisionStack.size()) - 1; + assert( level >= 0); // Just to be safe. Should not happen. + PrecisionStackLevel::iterator it; + TPrecision prec = EbpUndefined; // If we dont find anything we return this. Should we error check this? + while( level >= 0 ){ + it = precisionStack[level].find( type ); + if( it != precisionStack[level].end() ){ + prec = (*it).second; + break; + } + level--; + } + return prec; + } + +protected: + int currentLevel() const { return static_cast<int>(table.size()) - 1; } + + std::vector<TSymbolTableLevel*> table; + typedef std::map< TBasicType, TPrecision > PrecisionStackLevel; + std::vector< PrecisionStackLevel > precisionStack; + int uniqueId; // for unique identification in code generation +}; + +#endif // _SYMBOL_TABLE_INCLUDED_
diff --git a/src/GLES2/compiler/TranslatorASM.cpp b/src/GLES2/compiler/TranslatorASM.cpp new file mode 100644 index 0000000..bffddf4 --- /dev/null +++ b/src/GLES2/compiler/TranslatorASM.cpp
@@ -0,0 +1,44 @@ +// SwiftShader Software Renderer +// +// Copyright(c) 2005-2012 TransGaming Inc. +// +// All rights reserved. No part of this software may be copied, distributed, transmitted, +// transcribed, stored in a retrieval system, translated into any human or computer +// language by any means, or disclosed to third parties without the explicit written +// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express +// or implied, including but not limited to any patent rights, are granted to you. +// + +#include "TranslatorASM.h" + +#include "InitializeParseContext.h" + +TranslatorASM::TranslatorASM(gl::Shader *shaderObject, ShShaderType type, ShShaderSpec spec) : TCompiler(type, spec), shaderObject(shaderObject) +{ +} + +void TranslatorASM::translate(TIntermNode* root) +{ + TParseContext& parseContext = *GetGlobalParseContext(); + sh::OutputASM outputASM(parseContext, shaderObject); + + outputASM.output(); +} + +// +// This function must be provided to create the actual +// compile object used by higher level code. It returns +// a subclass of TCompiler. +// +TCompiler* ConstructCompiler(ShShaderType type, ShShaderSpec spec) +{ + return new TranslatorASM(0, type, spec); +} + +// +// Delete the compiler made by ConstructCompiler +// +void DeleteCompiler(TCompiler* compiler) +{ + delete compiler; +} \ No newline at end of file
diff --git a/src/GLES2/compiler/TranslatorASM.h b/src/GLES2/compiler/TranslatorASM.h new file mode 100644 index 0000000..f6502dd --- /dev/null +++ b/src/GLES2/compiler/TranslatorASM.h
@@ -0,0 +1,37 @@ +// SwiftShader Software Renderer +// +// Copyright(c) 2005-2012 TransGaming Inc. +// +// All rights reserved. No part of this software may be copied, distributed, transmitted, +// transcribed, stored in a retrieval system, translated into any human or computer +// language by any means, or disclosed to third parties without the explicit written +// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express +// or implied, including but not limited to any patent rights, are granted to you. +// + +#ifndef COMPILER_TRANSLATORASM_H_ +#define COMPILER_TRANSLATORASM_H_ + +#include "ShHandle.h" +#include "OutputASM.h" +#include "Shader/PixelShader.hpp" +#include "Shader/VertexShader.hpp" + +namespace gl +{ + class Shader; +} + +class TranslatorASM : public TCompiler +{ +public: + TranslatorASM(gl::Shader *shaderObject, ShShaderType type, ShShaderSpec spec); + +protected: + virtual void translate(TIntermNode* root); + +private: + gl::Shader *const shaderObject; +}; + +#endif // COMPILER_TRANSLATORASM_H_
diff --git a/src/GLES2/compiler/Types.h b/src/GLES2/compiler/Types.h new file mode 100644 index 0000000..460a433 --- /dev/null +++ b/src/GLES2/compiler/Types.h
@@ -0,0 +1,368 @@ +// +// Copyright (c) 2002-2012 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. +// + +#ifndef _TYPES_INCLUDED +#define _TYPES_INCLUDED + +#include "compiler/BaseTypes.h" +#include "compiler/Common.h" +#include "compiler/debug.h" + +class TType; +struct TPublicType; + +// +// Need to have association of line numbers to types in a list for building structs. +// +struct TTypeLine { + TType* type; + int line; +}; +typedef TVector<TTypeLine> TTypeList; + +inline TTypeList* NewPoolTTypeList() +{ + void* memory = GlobalPoolAllocator.allocate(sizeof(TTypeList)); + return new(memory) TTypeList; +} + +typedef TMap<TTypeList*, TTypeList*> TStructureMap; +typedef TMap<TTypeList*, TTypeList*>::iterator TStructureMapIterator; + +// +// Base class for things that have a type. +// +class TType +{ +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + TType() {} + TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, int s = 1, bool m = false, bool a = false) : + type(t), precision(p), qualifier(q), size(s), matrix(m), array(a), arraySize(0), + maxArraySize(0), arrayInformationType(0), structure(0), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0), typeName(0) + { + } + explicit TType(const TPublicType &p); + TType(TTypeList* userDef, const TString& n, TPrecision p = EbpUndefined) : + type(EbtStruct), precision(p), qualifier(EvqTemporary), size(1), matrix(false), array(false), arraySize(0), + maxArraySize(0), arrayInformationType(0), structure(userDef), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0) + { + typeName = NewPoolTString(n.c_str()); + } + + void copyType(const TType& copyOf, TStructureMap& remapper) + { + type = copyOf.type; + precision = copyOf.precision; + qualifier = copyOf.qualifier; + size = copyOf.size; + matrix = copyOf.matrix; + array = copyOf.array; + arraySize = copyOf.arraySize; + + TStructureMapIterator iter; + if (copyOf.structure) { + if ((iter = remapper.find(structure)) == remapper.end()) { + // create the new structure here + structure = NewPoolTTypeList(); + for (unsigned int i = 0; i < copyOf.structure->size(); ++i) { + TTypeLine typeLine; + typeLine.line = (*copyOf.structure)[i].line; + typeLine.type = (*copyOf.structure)[i].type->clone(remapper); + structure->push_back(typeLine); + } + } else { + structure = iter->second; + } + } else + structure = 0; + + fieldName = 0; + if (copyOf.fieldName) + fieldName = NewPoolTString(copyOf.fieldName->c_str()); + typeName = 0; + if (copyOf.typeName) + typeName = NewPoolTString(copyOf.typeName->c_str()); + + mangled = 0; + if (copyOf.mangled) + mangled = NewPoolTString(copyOf.mangled->c_str()); + + structureSize = copyOf.structureSize; + maxArraySize = copyOf.maxArraySize; + deepestStructNesting = copyOf.deepestStructNesting; + assert(copyOf.arrayInformationType == 0); + arrayInformationType = 0; // arrayInformationType should not be set for builtIn symbol table level + } + + TType* clone(TStructureMap& remapper) + { + TType *newType = new TType(); + newType->copyType(*this, remapper); + + return newType; + } + + TBasicType getBasicType() const { return type; } + void setBasicType(TBasicType t) { type = t; } + + TPrecision getPrecision() const { return precision; } + void setPrecision(TPrecision p) { precision = p; } + + TQualifier getQualifier() const { return qualifier; } + void setQualifier(TQualifier q) { qualifier = q; } + + // One-dimensional size of single instance type + int getNominalSize() const { return size; } + void setNominalSize(int s) { size = s; } + // Full size of single instance of type + int getObjectSize() const + { + if(isArray()) + { + return getElementSize() * std::max(getArraySize(), getMaxArraySize()); + } + else + { + return getElementSize(); + } + } + + int getElementSize() const + { + if(getBasicType() == EbtStruct) + { + return getStructSize(); + } + else if(matrix) + { + return size * size; + } + else // Vector or scalar + { + return size; + } + } + + int elementRegisterCount() const + { + TTypeList *structure = getStruct(); + + if(structure) + { + int registerCount = 0; + + for(size_t i = 0; i < structure->size(); i++) + { + registerCount += (*structure)[i].type->totalRegisterCount(); + } + + return registerCount; + } + else if(isMatrix()) + { + return getNominalSize(); + } + else + { + return 1; + } + } + + int totalRegisterCount() const + { + if(array) + { + return arraySize * elementRegisterCount(); + } + else + { + return elementRegisterCount(); + } + } + + bool isMatrix() const { return matrix ? true : false; } + void setMatrix(bool m) { matrix = m; } + + bool isArray() const { return array ? true : false; } + int getArraySize() const { return arraySize; } + void setArraySize(int s) { array = true; arraySize = s; } + int getMaxArraySize () const { return maxArraySize; } + void setMaxArraySize (int s) { maxArraySize = s; } + void clearArrayness() { array = false; arraySize = 0; maxArraySize = 0; } + void setArrayInformationType(TType* t) { arrayInformationType = t; } + TType* getArrayInformationType() const { return arrayInformationType; } + + bool isVector() const { return size > 1 && !matrix; } + bool isScalar() const { return size == 1 && !matrix && !structure; } + bool isRegister() const { return !matrix && !structure && !array; } // Fits in a 4-element register + bool isStruct() const { return structure != 0; } + + TTypeList* getStruct() const { return structure; } + void setStruct(TTypeList* s) { structure = s; computeDeepestStructNesting(); } + + const TString& getTypeName() const + { + assert(typeName); + return *typeName; + } + void setTypeName(const TString& n) + { + typeName = NewPoolTString(n.c_str()); + } + + bool isField() const { return fieldName != 0; } + const TString& getFieldName() const + { + assert(fieldName); + return *fieldName; + } + void setFieldName(const TString& n) + { + fieldName = NewPoolTString(n.c_str()); + } + + TString& getMangledName() { + if (!mangled) { + mangled = NewPoolTString(""); + buildMangledName(*mangled); + *mangled += ';' ; + } + + return *mangled; + } + + bool sameElementType(const TType& right) const { + return type == right.type && + size == right.size && + matrix == right.matrix && + structure == right.structure; + } + bool operator==(const TType& right) const { + return type == right.type && + size == right.size && + matrix == right.matrix && + array == right.array && (!array || arraySize == right.arraySize) && + structure == right.structure; + // don't check the qualifier, it's not ever what's being sought after + } + bool operator!=(const TType& right) const { + return !operator==(right); + } + bool operator<(const TType& right) const { + if (type != right.type) return type < right.type; + if (size != right.size) return size < right.size; + if (matrix != right.matrix) return matrix < right.matrix; + if (array != right.array) return array < right.array; + if (arraySize != right.arraySize) return arraySize < right.arraySize; + if (structure != right.structure) return structure < right.structure; + + return false; + } + + const char* getBasicString() const { return ::getBasicString(type); } + const char* getPrecisionString() const { return ::getPrecisionString(precision); } + const char* getQualifierString() const { return ::getQualifierString(qualifier); } + TString getCompleteString() const; + + // If this type is a struct, returns the deepest struct nesting of + // any field in the struct. For example: + // struct nesting1 { + // vec4 position; + // }; + // struct nesting2 { + // nesting1 field1; + // vec4 field2; + // }; + // For type "nesting2", this method would return 2 -- the number + // of structures through which indirection must occur to reach the + // deepest field (nesting2.field1.position). + int getDeepestStructNesting() const { return deepestStructNesting; } + + bool isStructureContainingArrays() const; + +protected: + void buildMangledName(TString&); + int getStructSize() const; + void computeDeepestStructNesting(); + + TBasicType type : 6; + TPrecision precision; + TQualifier qualifier : 7; + int size : 8; // size of vector or matrix, not size of array + unsigned int matrix : 1; + unsigned int array : 1; + int arraySize; + int maxArraySize; + TType* arrayInformationType; + + TTypeList* structure; // 0 unless this is a struct + mutable int structureSize; + int deepestStructNesting; + + TString *fieldName; // for structure field names + TString *mangled; + TString *typeName; // for structure field type name +}; + +// +// This is a workaround for a problem with the yacc stack, It can't have +// types that it thinks have non-trivial constructors. It should +// just be used while recognizing the grammar, not anything else. Pointers +// could be used, but also trying to avoid lots of memory management overhead. +// +// Not as bad as it looks, there is no actual assumption that the fields +// match up or are name the same or anything like that. +// +struct TPublicType +{ + TBasicType type; + TQualifier qualifier; + TPrecision precision; + int size; // size of vector or matrix, not size of array + bool matrix; + bool array; + int arraySize; + TType* userDef; + int line; + + void setBasic(TBasicType bt, TQualifier q, int ln = 0) + { + type = bt; + qualifier = q; + precision = EbpUndefined; + size = 1; + matrix = false; + array = false; + arraySize = 0; + userDef = 0; + line = ln; + } + + void setAggregate(int s, bool m = false) + { + size = s; + matrix = m; + } + + void setArray(bool a, int s = 0) + { + array = a; + arraySize = s; + } + + bool isStructureContainingArrays() const + { + if (!userDef) + { + return false; + } + + return userDef->isStructureContainingArrays(); + } +}; + +#endif // _TYPES_INCLUDED_
diff --git a/src/GLES2/compiler/ValidateLimitations.cpp b/src/GLES2/compiler/ValidateLimitations.cpp new file mode 100644 index 0000000..5838d0f --- /dev/null +++ b/src/GLES2/compiler/ValidateLimitations.cpp
@@ -0,0 +1,512 @@ +// +// Copyright (c) 2002-2012 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/ValidateLimitations.h" +#include "compiler/InfoSink.h" +#include "compiler/InitializeParseContext.h" +#include "compiler/ParseHelper.h" + +namespace { +bool IsLoopIndex(const TIntermSymbol* symbol, const TLoopStack& stack) { + for (TLoopStack::const_iterator i = stack.begin(); i != stack.end(); ++i) { + if (i->index.id == symbol->getId()) + return true; + } + return false; +} + +void MarkLoopForUnroll(const TIntermSymbol* symbol, TLoopStack& stack) { + for (TLoopStack::iterator i = stack.begin(); i != stack.end(); ++i) { + if (i->index.id == symbol->getId()) { + ASSERT(i->loop != NULL); + i->loop->setUnrollFlag(true); + return; + } + } + UNREACHABLE(); +} + +// Traverses a node to check if it represents a constant index expression. +// Definition: +// constant-index-expressions are a superset of constant-expressions. +// Constant-index-expressions can include loop indices as defined in +// GLSL ES 1.0 spec, Appendix A, section 4. +// The following are constant-index-expressions: +// - Constant expressions +// - Loop indices as defined in section 4 +// - Expressions composed of both of the above +class ValidateConstIndexExpr : public TIntermTraverser { +public: + ValidateConstIndexExpr(const TLoopStack& stack) + : mValid(true), mLoopStack(stack) {} + + // Returns true if the parsed node represents a constant index expression. + bool isValid() const { return mValid; } + + virtual void visitSymbol(TIntermSymbol* symbol) { + // Only constants and loop indices are allowed in a + // constant index expression. + if (mValid) { + mValid = (symbol->getQualifier() == EvqConst) || + IsLoopIndex(symbol, mLoopStack); + } + } + +private: + bool mValid; + const TLoopStack& mLoopStack; +}; + +// Traverses a node to check if it uses a loop index. +// If an int loop index is used in its body as a sampler array index, +// mark the loop for unroll. +class ValidateLoopIndexExpr : public TIntermTraverser { +public: + ValidateLoopIndexExpr(TLoopStack& stack) + : mUsesFloatLoopIndex(false), + mUsesIntLoopIndex(false), + mLoopStack(stack) {} + + bool usesFloatLoopIndex() const { return mUsesFloatLoopIndex; } + bool usesIntLoopIndex() const { return mUsesIntLoopIndex; } + + virtual void visitSymbol(TIntermSymbol* symbol) { + if (IsLoopIndex(symbol, mLoopStack)) { + switch (symbol->getBasicType()) { + case EbtFloat: + mUsesFloatLoopIndex = true; + break; + case EbtInt: + mUsesIntLoopIndex = true; + MarkLoopForUnroll(symbol, mLoopStack); + break; + default: + UNREACHABLE(); + } + } + } + +private: + bool mUsesFloatLoopIndex; + bool mUsesIntLoopIndex; + TLoopStack& mLoopStack; +}; +} // namespace + +ValidateLimitations::ValidateLimitations(ShShaderType shaderType, + TInfoSinkBase& sink) + : mShaderType(shaderType), + mSink(sink), + mNumErrors(0) +{ +} + +bool ValidateLimitations::visitBinary(Visit, TIntermBinary* node) +{ + // Check if loop index is modified in the loop body. + validateOperation(node, node->getLeft()); + + // Check indexing. + switch (node->getOp()) { + case EOpIndexDirect: + validateIndexing(node); + break; + case EOpIndexIndirect: +#if defined(__APPLE__) + // Loop unrolling is a work-around for a Mac Cg compiler bug where it + // crashes when a sampler array's index is also the loop index. + // Once Apple fixes this bug, we should remove the code in this CL. + // See http://codereview.appspot.com/4331048/. + if ((node->getLeft() != NULL) && (node->getRight() != NULL) && + (node->getLeft()->getAsSymbolNode())) { + TIntermSymbol* symbol = node->getLeft()->getAsSymbolNode(); + if (IsSampler(symbol->getBasicType()) && symbol->isArray()) { + ValidateLoopIndexExpr validate(mLoopStack); + node->getRight()->traverse(&validate); + if (validate.usesFloatLoopIndex()) { + error(node->getLine(), + "sampler array index is float loop index", + "for"); + } + } + } +#endif + validateIndexing(node); + break; + default: break; + } + return true; +} + +bool ValidateLimitations::visitUnary(Visit, TIntermUnary* node) +{ + // Check if loop index is modified in the loop body. + validateOperation(node, node->getOperand()); + + return true; +} + +bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate* node) +{ + switch (node->getOp()) { + case EOpFunctionCall: + validateFunctionCall(node); + break; + default: + break; + } + return true; +} + +bool ValidateLimitations::visitLoop(Visit, TIntermLoop* node) +{ + if (!validateLoopType(node)) + return false; + + TLoopInfo info; + memset(&info, 0, sizeof(TLoopInfo)); + info.loop = node; + if (!validateForLoopHeader(node, &info)) + return false; + + TIntermNode* body = node->getBody(); + if (body != NULL) { + mLoopStack.push_back(info); + body->traverse(this); + mLoopStack.pop_back(); + } + + // The loop is fully processed - no need to visit children. + return false; +} + +void ValidateLimitations::error(TSourceLoc loc, + const char *reason, const char* token) +{ + mSink.prefix(EPrefixError); + mSink.location(loc); + mSink << "'" << token << "' : " << reason << "\n"; + ++mNumErrors; +} + +bool ValidateLimitations::withinLoopBody() const +{ + return !mLoopStack.empty(); +} + +bool ValidateLimitations::isLoopIndex(const TIntermSymbol* symbol) const +{ + return IsLoopIndex(symbol, mLoopStack); +} + +bool ValidateLimitations::validateLoopType(TIntermLoop* node) { + TLoopType type = node->getType(); + if (type == ELoopFor) + return true; + + // Reject while and do-while loops. + error(node->getLine(), + "This type of loop is not allowed", + type == ELoopWhile ? "while" : "do"); + return false; +} + +bool ValidateLimitations::validateForLoopHeader(TIntermLoop* node, + TLoopInfo* info) +{ + ASSERT(node->getType() == ELoopFor); + + // + // The for statement has the form: + // for ( init-declaration ; condition ; expression ) statement + // + if (!validateForLoopInit(node, info)) + return false; + if (!validateForLoopCond(node, info)) + return false; + if (!validateForLoopExpr(node, info)) + return false; + + return true; +} + +bool ValidateLimitations::validateForLoopInit(TIntermLoop* node, + TLoopInfo* info) +{ + TIntermNode* init = node->getInit(); + if (init == NULL) { + error(node->getLine(), "Missing init declaration", "for"); + return false; + } + + // + // init-declaration has the form: + // type-specifier identifier = constant-expression + // + TIntermAggregate* decl = init->getAsAggregate(); + if ((decl == NULL) || (decl->getOp() != EOpDeclaration)) { + error(init->getLine(), "Invalid init declaration", "for"); + return false; + } + // To keep things simple do not allow declaration list. + TIntermSequence& declSeq = decl->getSequence(); + if (declSeq.size() != 1) { + error(decl->getLine(), "Invalid init declaration", "for"); + return false; + } + TIntermBinary* declInit = declSeq[0]->getAsBinaryNode(); + if ((declInit == NULL) || (declInit->getOp() != EOpInitialize)) { + error(decl->getLine(), "Invalid init declaration", "for"); + return false; + } + TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode(); + if (symbol == NULL) { + error(declInit->getLine(), "Invalid init declaration", "for"); + return false; + } + // The loop index has type int or float. + TBasicType type = symbol->getBasicType(); + if ((type != EbtInt) && (type != EbtFloat)) { + error(symbol->getLine(), + "Invalid type for loop index", getBasicString(type)); + return false; + } + // The loop index is initialized with constant expression. + if (!isConstExpr(declInit->getRight())) { + error(declInit->getLine(), + "Loop index cannot be initialized with non-constant expression", + symbol->getSymbol().c_str()); + return false; + } + + info->index.id = symbol->getId(); + return true; +} + +bool ValidateLimitations::validateForLoopCond(TIntermLoop* node, + TLoopInfo* info) +{ + TIntermNode* cond = node->getCondition(); + if (cond == NULL) { + error(node->getLine(), "Missing condition", "for"); + return false; + } + // + // condition has the form: + // loop_index relational_operator constant_expression + // + TIntermBinary* binOp = cond->getAsBinaryNode(); + if (binOp == NULL) { + error(node->getLine(), "Invalid condition", "for"); + return false; + } + // Loop index should be to the left of relational operator. + TIntermSymbol* symbol = binOp->getLeft()->getAsSymbolNode(); + if (symbol == NULL) { + error(binOp->getLine(), "Invalid condition", "for"); + return false; + } + if (symbol->getId() != info->index.id) { + error(symbol->getLine(), + "Expected loop index", symbol->getSymbol().c_str()); + return false; + } + // Relational operator is one of: > >= < <= == or !=. + switch (binOp->getOp()) { + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + break; + default: + error(binOp->getLine(), + "Invalid relational operator", + getOperatorString(binOp->getOp())); + break; + } + // Loop index must be compared with a constant. + if (!isConstExpr(binOp->getRight())) { + error(binOp->getLine(), + "Loop index cannot be compared with non-constant expression", + symbol->getSymbol().c_str()); + return false; + } + + return true; +} + +bool ValidateLimitations::validateForLoopExpr(TIntermLoop* node, + TLoopInfo* info) +{ + TIntermNode* expr = node->getExpression(); + if (expr == NULL) { + error(node->getLine(), "Missing expression", "for"); + return false; + } + + // for expression has one of the following forms: + // loop_index++ + // loop_index-- + // loop_index += constant_expression + // loop_index -= constant_expression + // ++loop_index + // --loop_index + // The last two forms are not specified in the spec, but I am assuming + // its an oversight. + TIntermUnary* unOp = expr->getAsUnaryNode(); + TIntermBinary* binOp = unOp ? NULL : expr->getAsBinaryNode(); + + TOperator op = EOpNull; + TIntermSymbol* symbol = NULL; + if (unOp != NULL) { + op = unOp->getOp(); + symbol = unOp->getOperand()->getAsSymbolNode(); + } else if (binOp != NULL) { + op = binOp->getOp(); + symbol = binOp->getLeft()->getAsSymbolNode(); + } + + // The operand must be loop index. + if (symbol == NULL) { + error(expr->getLine(), "Invalid expression", "for"); + return false; + } + if (symbol->getId() != info->index.id) { + error(symbol->getLine(), + "Expected loop index", symbol->getSymbol().c_str()); + return false; + } + + // The operator is one of: ++ -- += -=. + switch (op) { + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + ASSERT((unOp != NULL) && (binOp == NULL)); + break; + case EOpAddAssign: + case EOpSubAssign: + ASSERT((unOp == NULL) && (binOp != NULL)); + break; + default: + error(expr->getLine(), "Invalid operator", getOperatorString(op)); + return false; + } + + // Loop index must be incremented/decremented with a constant. + if (binOp != NULL) { + if (!isConstExpr(binOp->getRight())) { + error(binOp->getLine(), + "Loop index cannot be modified by non-constant expression", + symbol->getSymbol().c_str()); + return false; + } + } + + return true; +} + +bool ValidateLimitations::validateFunctionCall(TIntermAggregate* node) +{ + ASSERT(node->getOp() == EOpFunctionCall); + + // If not within loop body, there is nothing to check. + if (!withinLoopBody()) + return true; + + // List of param indices for which loop indices are used as argument. + typedef std::vector<int> ParamIndex; + ParamIndex pIndex; + TIntermSequence& params = node->getSequence(); + for (TIntermSequence::size_type i = 0; i < params.size(); ++i) { + TIntermSymbol* symbol = params[i]->getAsSymbolNode(); + if (symbol && isLoopIndex(symbol)) + pIndex.push_back(i); + } + // If none of the loop indices are used as arguments, + // there is nothing to check. + if (pIndex.empty()) + return true; + + bool valid = true; + TSymbolTable& symbolTable = GlobalParseContext->symbolTable; + TSymbol* symbol = symbolTable.find(node->getName()); + ASSERT(symbol && symbol->isFunction()); + TFunction* function = static_cast<TFunction*>(symbol); + for (ParamIndex::const_iterator i = pIndex.begin(); + i != pIndex.end(); ++i) { + const TParameter& param = function->getParam(*i); + TQualifier qual = param.type->getQualifier(); + if ((qual == EvqOut) || (qual == EvqInOut)) { + error(params[*i]->getLine(), + "Loop index cannot be used as argument to a function out or inout parameter", + params[*i]->getAsSymbolNode()->getSymbol().c_str()); + valid = false; + } + } + + return valid; +} + +bool ValidateLimitations::validateOperation(TIntermOperator* node, + TIntermNode* operand) { + // Check if loop index is modified in the loop body. + if (!withinLoopBody() || !node->modifiesState()) + return true; + + const TIntermSymbol* symbol = operand->getAsSymbolNode(); + if (symbol && isLoopIndex(symbol)) { + error(node->getLine(), + "Loop index cannot be statically assigned to within the body of the loop", + symbol->getSymbol().c_str()); + } + return true; +} + +bool ValidateLimitations::isConstExpr(TIntermNode* node) +{ + ASSERT(node != NULL); + return node->getAsConstantUnion() != NULL; +} + +bool ValidateLimitations::isConstIndexExpr(TIntermNode* node) +{ + ASSERT(node != NULL); + + ValidateConstIndexExpr validate(mLoopStack); + node->traverse(&validate); + return validate.isValid(); +} + +bool ValidateLimitations::validateIndexing(TIntermBinary* node) +{ + ASSERT((node->getOp() == EOpIndexDirect) || + (node->getOp() == EOpIndexIndirect)); + + bool valid = true; + TIntermTyped* index = node->getRight(); + // The index expression must have integral type. + if (!index->isScalar() || (index->getBasicType() != EbtInt)) { + error(index->getLine(), + "Index expression must have integral type", + index->getCompleteString().c_str()); + valid = false; + } + // The index expession must be a constant-index-expression unless + // the operand is a uniform in a vertex shader. + TIntermTyped* operand = node->getLeft(); + bool skip = (mShaderType == SH_VERTEX_SHADER) && + (operand->getQualifier() == EvqUniform); + if (!skip && !isConstIndexExpr(index)) { + error(index->getLine(), "Index expression must be constant", "[]"); + valid = false; + } + return valid; +} +
diff --git a/src/GLES2/compiler/ValidateLimitations.h b/src/GLES2/compiler/ValidateLimitations.h new file mode 100644 index 0000000..a835cb3 --- /dev/null +++ b/src/GLES2/compiler/ValidateLimitations.h
@@ -0,0 +1,59 @@ +// +// Copyright (c) 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 "GLSLANG/ShaderLang.h" +#include "compiler/intermediate.h" + +class TInfoSinkBase; + +struct TLoopInfo { + struct TIndex { + int id; // symbol id. + } index; + TIntermLoop* loop; +}; +typedef TVector<TLoopInfo> TLoopStack; + +// Traverses intermediate tree to ensure that the shader does not exceed the +// minimum functionality mandated in GLSL 1.0 spec, Appendix A. +class ValidateLimitations : public TIntermTraverser { +public: + ValidateLimitations(ShShaderType shaderType, TInfoSinkBase& sink); + + int numErrors() const { return mNumErrors; } + + virtual bool visitBinary(Visit, TIntermBinary*); + virtual bool visitUnary(Visit, TIntermUnary*); + virtual bool visitAggregate(Visit, TIntermAggregate*); + virtual bool visitLoop(Visit, TIntermLoop*); + +private: + void error(TSourceLoc loc, const char *reason, const char* token); + + bool withinLoopBody() const; + bool isLoopIndex(const TIntermSymbol* symbol) const; + bool validateLoopType(TIntermLoop* node); + bool validateForLoopHeader(TIntermLoop* node, TLoopInfo* info); + bool validateForLoopInit(TIntermLoop* node, TLoopInfo* info); + bool validateForLoopCond(TIntermLoop* node, TLoopInfo* info); + bool validateForLoopExpr(TIntermLoop* node, TLoopInfo* info); + // Returns true if none of the loop indices is used as the argument to + // the given function out or inout parameter. + bool validateFunctionCall(TIntermAggregate* node); + bool validateOperation(TIntermOperator* node, TIntermNode* operand); + + // Returns true if indexing does not exceed the minimum functionality + // mandated in GLSL 1.0 spec, Appendix A, Section 5. + bool isConstExpr(TIntermNode* node); + bool isConstIndexExpr(TIntermNode* node); + bool validateIndexing(TIntermBinary* node); + + ShShaderType mShaderType; + TInfoSinkBase& mSink; + int mNumErrors; + TLoopStack mLoopStack; +}; +
diff --git a/src/GLES2/compiler/VariableInfo.cpp b/src/GLES2/compiler/VariableInfo.cpp new file mode 100644 index 0000000..071d05e --- /dev/null +++ b/src/GLES2/compiler/VariableInfo.cpp
@@ -0,0 +1,210 @@ +// +// Copyright (c) 2002-2012 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/VariableInfo.h" + +static TString arrayBrackets(int index) +{ + TStringStream stream; + stream << "[" << index << "]"; + return stream.str(); +} + +// Returns the data type for an attribute or uniform. +static ShDataType getVariableDataType(const TType& type) +{ + switch (type.getBasicType()) { + case EbtFloat: + if (type.isMatrix()) { + switch (type.getNominalSize()) { + case 2: return SH_FLOAT_MAT2; + case 3: return SH_FLOAT_MAT3; + case 4: return SH_FLOAT_MAT4; + default: UNREACHABLE(); + } + } else if (type.isVector()) { + switch (type.getNominalSize()) { + case 2: return SH_FLOAT_VEC2; + case 3: return SH_FLOAT_VEC3; + case 4: return SH_FLOAT_VEC4; + default: UNREACHABLE(); + } + } else { + return SH_FLOAT; + } + case EbtInt: + if (type.isMatrix()) { + UNREACHABLE(); + } else if (type.isVector()) { + switch (type.getNominalSize()) { + case 2: return SH_INT_VEC2; + case 3: return SH_INT_VEC3; + case 4: return SH_INT_VEC4; + default: UNREACHABLE(); + } + } else { + return SH_INT; + } + case EbtBool: + if (type.isMatrix()) { + UNREACHABLE(); + } else if (type.isVector()) { + switch (type.getNominalSize()) { + case 2: return SH_BOOL_VEC2; + case 3: return SH_BOOL_VEC3; + case 4: return SH_BOOL_VEC4; + default: UNREACHABLE(); + } + } else { + return SH_BOOL; + } + case EbtSampler2D: return SH_SAMPLER_2D; + case EbtSamplerCube: return SH_SAMPLER_CUBE; + default: UNREACHABLE(); + } + return SH_NONE; +} + +static void getBuiltInVariableInfo(const TType& type, + const TString& name, + TVariableInfoList& infoList); +static void getUserDefinedVariableInfo(const TType& type, + const TString& name, + TVariableInfoList& infoList); + +// Returns info for an attribute or uniform. +static void getVariableInfo(const TType& type, + const TString& name, + TVariableInfoList& infoList) +{ + if (type.getBasicType() == EbtStruct) { + if (type.isArray()) { + for (int i = 0; i < type.getArraySize(); ++i) { + TString lname = name + arrayBrackets(i); + getUserDefinedVariableInfo(type, lname, infoList); + } + } else { + getUserDefinedVariableInfo(type, name, infoList); + } + } else { + getBuiltInVariableInfo(type, name, infoList); + } +} + +void getBuiltInVariableInfo(const TType& type, + const TString& name, + TVariableInfoList& infoList) +{ + ASSERT(type.getBasicType() != EbtStruct); + + TVariableInfo varInfo; + if (type.isArray()) { + varInfo.name = (name + "[0]").c_str(); + varInfo.size = type.getArraySize(); + } else { + varInfo.name = name.c_str(); + varInfo.size = 1; + } + varInfo.type = getVariableDataType(type); + infoList.push_back(varInfo); +} + +void getUserDefinedVariableInfo(const TType& type, + const TString& name, + TVariableInfoList& infoList) +{ + ASSERT(type.getBasicType() == EbtStruct); + + const TTypeList* structure = type.getStruct(); + for (size_t i = 0; i < structure->size(); ++i) { + const TType* fieldType = (*structure)[i].type; + getVariableInfo(*fieldType, + name + "." + fieldType->getFieldName(), + infoList); + } +} + +CollectAttribsUniforms::CollectAttribsUniforms(TVariableInfoList& attribs, + TVariableInfoList& uniforms) + : mAttribs(attribs), + mUniforms(uniforms) +{ +} + +// We are only interested in attribute and uniform variable declaration. +void CollectAttribsUniforms::visitSymbol(TIntermSymbol*) +{ +} + +void CollectAttribsUniforms::visitConstantUnion(TIntermConstantUnion*) +{ +} + +bool CollectAttribsUniforms::visitBinary(Visit, TIntermBinary*) +{ + return false; +} + +bool CollectAttribsUniforms::visitUnary(Visit, TIntermUnary*) +{ + return false; +} + +bool CollectAttribsUniforms::visitSelection(Visit, TIntermSelection*) +{ + return false; +} + +bool CollectAttribsUniforms::visitAggregate(Visit, TIntermAggregate* node) +{ + bool visitChildren = false; + + switch (node->getOp()) + { + case EOpSequence: + // We need to visit sequence children to get to variable declarations. + visitChildren = true; + break; + case EOpDeclaration: { + const TIntermSequence& sequence = node->getSequence(); + TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier(); + if (qualifier == EvqAttribute || qualifier == EvqUniform) + { + TVariableInfoList& infoList = qualifier == EvqAttribute ? + mAttribs : mUniforms; + for (TIntermSequence::const_iterator i = sequence.begin(); + i != sequence.end(); ++i) + { + const TIntermSymbol* variable = (*i)->getAsSymbolNode(); + // The only case in which the sequence will not contain a + // TIntermSymbol node is initialization. It will contain a + // TInterBinary node in that case. Since attributes and unifroms + // cannot be initialized in a shader, we must have only + // TIntermSymbol nodes in the sequence. + ASSERT(variable != NULL); + getVariableInfo(variable->getType(), + variable->getSymbol(), + infoList); + } + } + break; + } + default: break; + } + + return visitChildren; +} + +bool CollectAttribsUniforms::visitLoop(Visit, TIntermLoop*) +{ + return false; +} + +bool CollectAttribsUniforms::visitBranch(Visit, TIntermBranch*) +{ + return false; +} +
diff --git a/src/GLES2/compiler/VariableInfo.h b/src/GLES2/compiler/VariableInfo.h new file mode 100644 index 0000000..77902d9 --- /dev/null +++ b/src/GLES2/compiler/VariableInfo.h
@@ -0,0 +1,42 @@ +// +// Copyright (c) 2002-2012 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. +// + +#ifndef COMPILER_VARIABLE_INFO_H_ +#define COMPILER_VARIABLE_INFO_H_ + +#include "GLSLANG/ShaderLang.h" +#include "compiler/intermediate.h" + +// Provides information about a variable. +// It is currently being used to store info about active attribs and uniforms. +struct TVariableInfo { + TPersistString name; + ShDataType type; + int size; +}; +typedef std::vector<TVariableInfo> TVariableInfoList; + +// Traverses intermediate tree to collect all attributes and uniforms. +class CollectAttribsUniforms : public TIntermTraverser { +public: + CollectAttribsUniforms(TVariableInfoList& attribs, + TVariableInfoList& uniforms); + + virtual void visitSymbol(TIntermSymbol*); + virtual void visitConstantUnion(TIntermConstantUnion*); + virtual bool visitBinary(Visit, TIntermBinary*); + virtual bool visitUnary(Visit, TIntermUnary*); + virtual bool visitSelection(Visit, TIntermSelection*); + virtual bool visitAggregate(Visit, TIntermAggregate*); + virtual bool visitLoop(Visit, TIntermLoop*); + virtual bool visitBranch(Visit, TIntermBranch*); + +private: + TVariableInfoList& mAttribs; + TVariableInfoList& mUniforms; +}; + +#endif // COMPILER_VARIABLE_INFO_H_
diff --git a/src/GLES2/compiler/debug.cpp b/src/GLES2/compiler/debug.cpp new file mode 100644 index 0000000..53778bd --- /dev/null +++ b/src/GLES2/compiler/debug.cpp
@@ -0,0 +1,37 @@ +// +// 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. +// + +// debug.cpp: Debugging utilities. + +#include "compiler/debug.h" + +#include <stdarg.h> +#include <stdio.h> + +#include "compiler/InitializeParseContext.h" +#include "compiler/ParseHelper.h" + +static const int kTraceBufferLen = 1024; + +#ifdef TRACE_ENABLED +extern "C" { +void Trace(const char *format, ...) { + if (!format) return; + + TParseContext* parseContext = GetGlobalParseContext(); + if (parseContext) { + char buf[kTraceBufferLen]; + va_list args; + va_start(args, format); + vsnprintf(buf, kTraceBufferLen, format, args); + va_end(args); + + parseContext->trace(buf); + } +} +} // extern "C" +#endif // TRACE_ENABLED +
diff --git a/src/GLES2/compiler/debug.h b/src/GLES2/compiler/debug.h new file mode 100644 index 0000000..7a37151 --- /dev/null +++ b/src/GLES2/compiler/debug.h
@@ -0,0 +1,53 @@ +// +// 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. +// + +// debug.h: Debugging utilities. + +#ifndef COMPILER_DEBUG_H_ +#define COMPILER_DEBUG_H_ + +#include <assert.h> + +#ifdef _DEBUG +#define TRACE_ENABLED // define to enable debug message tracing +#endif // _DEBUG + +// Outputs text to the debug log +#ifdef TRACE_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus +void Trace(const char* format, ...); +#ifdef __cplusplus +} +#endif // __cplusplus + +#else // TRACE_ENABLED + +#define Trace(...) ((void)0) + +#endif // TRACE_ENABLED + +// A macro asserting a condition and outputting failures to the debug log +#define ASSERT(expression) do { \ + if(!(expression)) \ + Trace("Assert failed: %s(%d): "#expression"\n", __FUNCTION__, __LINE__); \ + assert(expression); \ +} while(0) + +#define UNIMPLEMENTED() do { \ + Trace("Unimplemented invoked: %s(%d)\n", __FUNCTION__, __LINE__); \ + assert(false); \ +} while(0) + +#define UNREACHABLE() do { \ + Trace("Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__); \ + assert(false); \ +} while(0) + +#endif // COMPILER_DEBUG_H_ +
diff --git a/src/GLES2/compiler/generate_parser.sh b/src/GLES2/compiler/generate_parser.sh new file mode 100644 index 0000000..e472191 --- /dev/null +++ b/src/GLES2/compiler/generate_parser.sh
@@ -0,0 +1,27 @@ +#!/bin/bash +# Copyright (c) 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. + +# Generates GLSL ES parser - glslang_lex.cpp, glslang_tab.h, and glslang_tab.cpp + +run_flex() +{ +input_file=$script_dir/$1.l +output_source=$script_dir/$1_lex.cpp +flex --noline --nounistd --outfile=$output_source $input_file +} + +run_bison() +{ +input_file=$script_dir/$1.y +output_header=$script_dir/$1_tab.h +output_source=$script_dir/$1_tab.cpp +bison --no-lines --skeleton=yacc.c --defines=$output_header --output=$output_source $input_file +} + +script_dir=$(dirname $0) + +# Generate Parser +run_flex glslang +run_bison glslang
diff --git a/src/GLES2/compiler/glslang.h b/src/GLES2/compiler/glslang.h new file mode 100644 index 0000000..8e2d4d6 --- /dev/null +++ b/src/GLES2/compiler/glslang.h
@@ -0,0 +1,16 @@ +// +// Copyright (c) 2012 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. +// + +struct TParseContext; +extern int glslang_initialize(TParseContext* context); +extern int glslang_finalize(TParseContext* context); + +extern int glslang_scan(int count, + const char* const string[], + const int length[], + TParseContext* context); +extern int glslang_parse(TParseContext* context); +
diff --git a/src/GLES2/compiler/glslang.l b/src/GLES2/compiler/glslang.l new file mode 100644 index 0000000..ca29a62 --- /dev/null +++ b/src/GLES2/compiler/glslang.l
@@ -0,0 +1,365 @@ +/* +// +// Copyright (c) 2002-2012 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. +// + +This file contains the Lex specification for GLSL ES. +Based on ANSI C grammar, Lex specification: +http://www.lysator.liu.se/c/ANSI-C-grammar-l.html + +IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh, +WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp). +*/ + +%top{ +// +// Copyright (c) 2012 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. +// + +// This file is auto-generated by generate_parser.sh. DO NOT EDIT! + +// Ignore errors in auto-generated code. +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wswitch-enum" +#elif defined(_MSC_VER) +#pragma warning(disable: 4065) +#pragma warning(disable: 4189) +#pragma warning(disable: 4505) +#pragma warning(disable: 4701) +#endif +} + +%{ +#include "compiler/glslang.h" +#include "compiler/ParseHelper.h" +#include "compiler/preprocessor/Token.h" +#include "compiler/util.h" +#include "glslang_tab.h" + +/* windows only pragma */ +#ifdef _MSC_VER +#pragma warning(disable : 4102) +#endif + +#define YY_USER_ACTION yylval->lex.line = yylineno; +#define YY_INPUT(buf, result, max_size) \ + result = string_input(buf, max_size, yyscanner); + +static int string_input(char* buf, int max_size, yyscan_t yyscanner); +static int check_type(yyscan_t yyscanner); +static int reserved_word(yyscan_t yyscanner); +%} + +%option noyywrap nounput never-interactive +%option yylineno reentrant bison-bridge +%option stack +%option extra-type="TParseContext*" +%x COMMENT FIELDS + +D [0-9] +L [a-zA-Z_] +H [a-fA-F0-9] +E [Ee][+-]?{D}+ +O [0-7] + +%% + +%{ + TParseContext* context = yyextra; +%} + + /* Single-line comments */ +"//"[^\n]* ; + + /* Multi-line comments */ +"/*" { yy_push_state(COMMENT, yyscanner); } +<COMMENT>. | +<COMMENT>\n ; +<COMMENT>"*/" { yy_pop_state(yyscanner); } + +"invariant" { return(INVARIANT); } +"highp" { return(HIGH_PRECISION); } +"mediump" { return(MEDIUM_PRECISION); } +"lowp" { return(LOW_PRECISION); } +"precision" { return(PRECISION); } + +"attribute" { return(ATTRIBUTE); } +"const" { return(CONST_QUAL); } +"uniform" { return(UNIFORM); } +"varying" { return(VARYING); } + +"break" { return(BREAK); } +"continue" { return(CONTINUE); } +"do" { return(DO); } +"for" { return(FOR); } +"while" { return(WHILE); } + +"if" { return(IF); } +"else" { return(ELSE); } + +"in" { return(IN_QUAL); } +"out" { return(OUT_QUAL); } +"inout" { return(INOUT_QUAL); } + +"float" { context->lexAfterType = true; return(FLOAT_TYPE); } +"int" { context->lexAfterType = true; return(INT_TYPE); } +"void" { context->lexAfterType = true; return(VOID_TYPE); } +"bool" { context->lexAfterType = true; return(BOOL_TYPE); } +"true" { yylval->lex.b = true; return(BOOLCONSTANT); } +"false" { yylval->lex.b = false; return(BOOLCONSTANT); } + +"discard" { return(DISCARD); } +"return" { return(RETURN); } + +"mat2" { context->lexAfterType = true; return(MATRIX2); } +"mat3" { context->lexAfterType = true; return(MATRIX3); } +"mat4" { context->lexAfterType = true; return(MATRIX4); } + +"vec2" { context->lexAfterType = true; return (VEC2); } +"vec3" { context->lexAfterType = true; return (VEC3); } +"vec4" { context->lexAfterType = true; return (VEC4); } +"ivec2" { context->lexAfterType = true; return (IVEC2); } +"ivec3" { context->lexAfterType = true; return (IVEC3); } +"ivec4" { context->lexAfterType = true; return (IVEC4); } +"bvec2" { context->lexAfterType = true; return (BVEC2); } +"bvec3" { context->lexAfterType = true; return (BVEC3); } +"bvec4" { context->lexAfterType = true; return (BVEC4); } + +"sampler2D" { context->lexAfterType = true; return SAMPLER2D; } +"samplerCube" { context->lexAfterType = true; return SAMPLERCUBE; } + +"struct" { context->lexAfterType = true; return(STRUCT); } + +"asm" { return reserved_word(yyscanner); } + +"class" { return reserved_word(yyscanner); } +"union" { return reserved_word(yyscanner); } +"enum" { return reserved_word(yyscanner); } +"typedef" { return reserved_word(yyscanner); } +"template" { return reserved_word(yyscanner); } +"this" { return reserved_word(yyscanner); } +"packed" { return reserved_word(yyscanner); } + +"goto" { return reserved_word(yyscanner); } +"switch" { return reserved_word(yyscanner); } +"default" { return reserved_word(yyscanner); } + +"inline" { return reserved_word(yyscanner); } +"noinline" { return reserved_word(yyscanner); } +"volatile" { return reserved_word(yyscanner); } +"public" { return reserved_word(yyscanner); } +"static" { return reserved_word(yyscanner); } +"extern" { return reserved_word(yyscanner); } +"external" { return reserved_word(yyscanner); } +"interface" { return reserved_word(yyscanner); } +"flat" { return reserved_word(yyscanner); } + +"long" { return reserved_word(yyscanner); } +"short" { return reserved_word(yyscanner); } +"double" { return reserved_word(yyscanner); } +"half" { return reserved_word(yyscanner); } +"fixed" { return reserved_word(yyscanner); } +"unsigned" { return reserved_word(yyscanner); } +"superp" { return reserved_word(yyscanner); } + +"input" { return reserved_word(yyscanner); } +"output" { return reserved_word(yyscanner); } + +"hvec2" { return reserved_word(yyscanner); } +"hvec3" { return reserved_word(yyscanner); } +"hvec4" { return reserved_word(yyscanner); } +"dvec2" { return reserved_word(yyscanner); } +"dvec3" { return reserved_word(yyscanner); } +"dvec4" { return reserved_word(yyscanner); } +"fvec2" { return reserved_word(yyscanner); } +"fvec3" { return reserved_word(yyscanner); } +"fvec4" { return reserved_word(yyscanner); } + +"sampler1D" { return reserved_word(yyscanner); } +"sampler3D" { return reserved_word(yyscanner); } + +"sampler1DShadow" { return reserved_word(yyscanner); } +"sampler2DShadow" { return reserved_word(yyscanner); } + +"sampler2DRect" { return reserved_word(yyscanner); } +"sampler3DRect" { return reserved_word(yyscanner); } +"sampler2DRectShadow" { return reserved_word(yyscanner); } + +"sizeof" { return reserved_word(yyscanner); } +"cast" { return reserved_word(yyscanner); } + +"namespace" { return reserved_word(yyscanner); } +"using" { return reserved_word(yyscanner); } + +{L}({L}|{D})* { + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); +} + +0[xX]{H}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } +0{O}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } +0{D}+ { context->error(yylineno, "Invalid Octal number.", yytext); context->recover(); return 0;} +{D}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } + +{D}+{E} { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); } +{D}+"."{D}*({E})? { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); } +"."{D}+({E})? { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); } + +"+=" { return(ADD_ASSIGN); } +"-=" { return(SUB_ASSIGN); } +"*=" { return(MUL_ASSIGN); } +"/=" { return(DIV_ASSIGN); } +"%=" { return(MOD_ASSIGN); } +"<<=" { return(LEFT_ASSIGN); } +">>=" { return(RIGHT_ASSIGN); } +"&=" { return(AND_ASSIGN); } +"^=" { return(XOR_ASSIGN); } +"|=" { return(OR_ASSIGN); } + +"++" { return(INC_OP); } +"--" { return(DEC_OP); } +"&&" { return(AND_OP); } +"||" { return(OR_OP); } +"^^" { return(XOR_OP); } +"<=" { return(LE_OP); } +">=" { return(GE_OP); } +"==" { return(EQ_OP); } +"!=" { return(NE_OP); } +"<<" { return(LEFT_OP); } +">>" { return(RIGHT_OP); } +";" { context->lexAfterType = false; return(SEMICOLON); } +("{"|"<%") { context->lexAfterType = false; return(LEFT_BRACE); } +("}"|"%>") { return(RIGHT_BRACE); } +"," { if (context->inTypeParen) context->lexAfterType = false; return(COMMA); } +":" { return(COLON); } +"=" { context->lexAfterType = false; return(EQUAL); } +"(" { context->lexAfterType = false; context->inTypeParen = true; return(LEFT_PAREN); } +")" { context->inTypeParen = false; return(RIGHT_PAREN); } +("["|"<:") { return(LEFT_BRACKET); } +("]"|":>") { return(RIGHT_BRACKET); } +"." { BEGIN(FIELDS); return(DOT); } +"!" { return(BANG); } +"-" { return(DASH); } +"~" { return(TILDE); } +"+" { return(PLUS); } +"*" { return(STAR); } +"/" { return(SLASH); } +"%" { return(PERCENT); } +"<" { return(LEFT_ANGLE); } +">" { return(RIGHT_ANGLE); } +"|" { return(VERTICAL_BAR); } +"^" { return(CARET); } +"&" { return(AMPERSAND); } +"?" { return(QUESTION); } + +<FIELDS>{L}({L}|{D})* { + BEGIN(INITIAL); + yylval->lex.string = NewPoolTString(yytext); + return FIELD_SELECTION; +} +<FIELDS>[ \t\v\f\r] {} + +[ \t\v\n\f\r] { } +<*><<EOF>> { context->AfterEOF = true; yyterminate(); } +<*>. { context->warning(yylineno, "Unknown char", yytext, ""); return 0; } + +%% + +int string_input(char* buf, int max_size, yyscan_t yyscanner) +{ + int len = 0; + + pp::Token token; + yyget_extra(yyscanner)->preprocessor.lex(&token); + len = token.type == pp::Token::LAST ? 0 : token.text.size(); + if ((len > 0) && (len < max_size)) + memcpy(buf, token.text.c_str(), len); + yyset_lineno(EncodeSourceLoc(token.location.file, token.location.line), yyscanner); + + if (len >= max_size) + YY_FATAL_ERROR("Input buffer overflow"); + else if (len > 0) + buf[len++] = ' '; + return len; +} + +int check_type(yyscan_t yyscanner) { + struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; + + int token = IDENTIFIER; + TSymbol* symbol = yyextra->symbolTable.find(yytext); + if (yyextra->lexAfterType == false && symbol && symbol->isVariable()) { + TVariable* variable = static_cast<TVariable*>(symbol); + if (variable->isUserType()) { + yyextra->lexAfterType = true; + token = TYPE_NAME; + } + } + yylval->lex.symbol = symbol; + return token; +} + +int reserved_word(yyscan_t yyscanner) { + struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; + + yyextra->error(yylineno, "Illegal use of reserved word", yytext, ""); + yyextra->recover(); + return 0; +} + +void yyerror(TParseContext* context, const char* reason) { + struct yyguts_t* yyg = (struct yyguts_t*) context->scanner; + + if (context->AfterEOF) { + context->error(yylineno, reason, "unexpected EOF"); + } else { + context->error(yylineno, reason, yytext); + } + context->recover(); +} + +int glslang_initialize(TParseContext* context) { + yyscan_t scanner = NULL; + if (yylex_init_extra(context, &scanner)) + return 1; + + context->scanner = scanner; + return 0; +} + +int glslang_finalize(TParseContext* context) { + yyscan_t scanner = context->scanner; + if (scanner == NULL) return 0; + + context->scanner = NULL; + yylex_destroy(scanner); + + return 0; +} + +int glslang_scan(int count, const char* const string[], const int length[], + TParseContext* context) { + yyrestart(NULL, context->scanner); + yyset_lineno(EncodeSourceLoc(0, 1), context->scanner); + context->AfterEOF = false; + + // Initialize preprocessor. + if (!context->preprocessor.init(count, string, length)) + return 1; + + // Define extension macros. + const TExtensionBehavior& extBehavior = context->extensionBehavior(); + for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); + iter != extBehavior.end(); ++iter) + { + context->preprocessor.predefineMacro(iter->first.c_str(), 1); + } + return 0; +} +
diff --git a/src/GLES2/compiler/glslang.y b/src/GLES2/compiler/glslang.y new file mode 100644 index 0000000..ba8a0b8 --- /dev/null +++ b/src/GLES2/compiler/glslang.y
@@ -0,0 +1,2124 @@ +/* +// +// Copyright (c) 2002-2012 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. +// + +This file contains the Yacc grammar for GLSL ES. +Based on ANSI C Yacc grammar: +http://www.lysator.liu.se/c/ANSI-C-grammar-y.html + +IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh, +WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). +*/ + +%{ +// +// Copyright (c) 2002-2012 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. +// + +// This file is auto-generated by generate_parser.sh. DO NOT EDIT! + +// Ignore errors in auto-generated code. +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wswitch-enum" +#elif defined(_MSC_VER) +#pragma warning(disable: 4065) +#pragma warning(disable: 4189) +#pragma warning(disable: 4505) +#pragma warning(disable: 4701) +#endif + +#include "compiler/SymbolTable.h" +#include "compiler/ParseHelper.h" +#include "GLSLANG/ShaderLang.h" + +#define YYLEX_PARAM context->scanner +%} + +%expect 1 /* One shift reduce conflict because of if | else */ +%pure-parser +%parse-param {TParseContext* context} + +%union { + struct { + TSourceLoc line; + union { + TString *string; + float f; + int i; + bool b; + }; + TSymbol* symbol; + } lex; + struct { + TSourceLoc line; + TOperator op; + union { + TIntermNode* intermNode; + TIntermNodePair nodePair; + TIntermTyped* intermTypedNode; + TIntermAggregate* intermAggregate; + }; + union { + TPublicType type; + TPrecision precision; + TQualifier qualifier; + TFunction* function; + TParameter param; + TTypeLine typeLine; + TTypeList* typeList; + }; + } interm; +} + +%{ +extern int yylex(YYSTYPE* yylval_param, void* yyscanner); +extern void yyerror(TParseContext* context, const char* reason); + +#define FRAG_VERT_ONLY(S, L) { \ + if (context->shaderType != SH_FRAGMENT_SHADER && \ + context->shaderType != SH_VERTEX_SHADER) { \ + context->error(L, " supported in vertex/fragment shaders only ", S); \ + context->recover(); \ + } \ +} + +#define VERTEX_ONLY(S, L) { \ + if (context->shaderType != SH_VERTEX_SHADER) { \ + context->error(L, " supported in vertex shaders only ", S); \ + context->recover(); \ + } \ +} + +#define FRAG_ONLY(S, L) { \ + if (context->shaderType != SH_FRAGMENT_SHADER) { \ + context->error(L, " supported in fragment shaders only ", S); \ + context->recover(); \ + } \ +} +%} + +%token <lex> INVARIANT HIGH_PRECISION MEDIUM_PRECISION LOW_PRECISION PRECISION +%token <lex> ATTRIBUTE CONST_QUAL BOOL_TYPE FLOAT_TYPE INT_TYPE +%token <lex> BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN +%token <lex> BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 VEC2 VEC3 VEC4 +%token <lex> MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING +%token <lex> STRUCT VOID_TYPE WHILE +%token <lex> SAMPLER2D SAMPLERCUBE + +%token <lex> IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT BOOLCONSTANT +%token <lex> FIELD_SELECTION +%token <lex> LEFT_OP RIGHT_OP +%token <lex> INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP +%token <lex> AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN +%token <lex> MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN +%token <lex> SUB_ASSIGN + +%token <lex> LEFT_PAREN RIGHT_PAREN LEFT_BRACKET RIGHT_BRACKET LEFT_BRACE RIGHT_BRACE DOT +%token <lex> COMMA COLON EQUAL SEMICOLON BANG DASH TILDE PLUS STAR SLASH PERCENT +%token <lex> LEFT_ANGLE RIGHT_ANGLE VERTICAL_BAR CARET AMPERSAND QUESTION + +%type <interm> assignment_operator unary_operator +%type <interm.intermTypedNode> variable_identifier primary_expression postfix_expression +%type <interm.intermTypedNode> expression integer_expression assignment_expression +%type <interm.intermTypedNode> unary_expression multiplicative_expression additive_expression +%type <interm.intermTypedNode> relational_expression equality_expression +%type <interm.intermTypedNode> conditional_expression constant_expression +%type <interm.intermTypedNode> logical_or_expression logical_xor_expression logical_and_expression +%type <interm.intermTypedNode> shift_expression and_expression exclusive_or_expression inclusive_or_expression +%type <interm.intermTypedNode> function_call initializer condition conditionopt + +%type <interm.intermNode> translation_unit function_definition +%type <interm.intermNode> statement simple_statement +%type <interm.intermAggregate> statement_list compound_statement +%type <interm.intermNode> declaration_statement selection_statement expression_statement +%type <interm.intermNode> declaration external_declaration +%type <interm.intermNode> for_init_statement compound_statement_no_new_scope +%type <interm.nodePair> selection_rest_statement for_rest_statement +%type <interm.intermNode> iteration_statement jump_statement statement_no_new_scope statement_with_scope +%type <interm> single_declaration init_declarator_list + +%type <interm> parameter_declaration parameter_declarator parameter_type_specifier +%type <interm.qualifier> parameter_qualifier + +%type <interm.precision> precision_qualifier +%type <interm.type> type_qualifier fully_specified_type type_specifier +%type <interm.type> type_specifier_no_prec type_specifier_nonarray +%type <interm.type> struct_specifier +%type <interm.typeLine> struct_declarator +%type <interm.typeList> struct_declarator_list struct_declaration struct_declaration_list +%type <interm.function> function_header function_declarator function_identifier +%type <interm.function> function_header_with_parameters function_call_header +%type <interm> function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype +%type <interm> function_call_or_method + +%start translation_unit +%% + +variable_identifier + : IDENTIFIER { + // The symbol table search was done in the lexical phase + const TSymbol* symbol = $1.symbol; + const TVariable* variable; + if (symbol == 0) { + context->error($1.line, "undeclared identifier", $1.string->c_str()); + context->recover(); + TType type(EbtFloat, EbpUndefined); + TVariable* fakeVariable = new TVariable($1.string, type); + context->symbolTable.insert(*fakeVariable); + variable = fakeVariable; + } else { + // This identifier can only be a variable type symbol + if (! symbol->isVariable()) { + context->error($1.line, "variable expected", $1.string->c_str()); + context->recover(); + } + variable = static_cast<const TVariable*>(symbol); + } + + // don't delete $1.string, it's used by error recovery, and the pool + // pop will reclaim the memory + + if (variable->getType().getQualifier() == EvqConst ) { + ConstantUnion* constArray = variable->getConstPointer(); + TType t(variable->getType()); + $$ = context->intermediate.addConstantUnion(constArray, t, $1.line); + } else + $$ = context->intermediate.addSymbol(variable->getUniqueId(), + variable->getName(), + variable->getType(), $1.line); + } + ; + +primary_expression + : variable_identifier { + $$ = $1; + } + | INTCONSTANT { + // + // INT_TYPE is only 16-bit plus sign bit for vertex/fragment shaders, + // check for overflow for constants + // + if (abs($1.i) >= (1 << 16)) { + context->error($1.line, " integer constant overflow", ""); + context->recover(); + } + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst($1.i); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), $1.line); + } + | FLOATCONSTANT { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setFConst($1.f); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), $1.line); + } + | BOOLCONSTANT { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst($1.b); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $1.line); + } + | LEFT_PAREN expression RIGHT_PAREN { + $$ = $2; + } + ; + +postfix_expression + : primary_expression { + $$ = $1; + } + | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET { + if (!$1->isArray() && !$1->isMatrix() && !$1->isVector()) { + if ($1->getAsSymbolNode()) + context->error($2.line, " left of '[' is not of type array, matrix, or vector ", $1->getAsSymbolNode()->getSymbol().c_str()); + else + context->error($2.line, " left of '[' is not of type array, matrix, or vector ", "expression"); + context->recover(); + } + if ($1->getType().getQualifier() == EvqConst && $3->getQualifier() == EvqConst) { + if ($1->isArray()) { // constant folding for arrays + $$ = context->addConstArrayNode($3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), $1, $2.line); + } else if ($1->isVector()) { // constant folding for vectors + TVectorFields fields; + fields.num = 1; + fields.offsets[0] = $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); // need to do it this way because v.xy sends fields integer array + $$ = context->addConstVectorNode(fields, $1, $2.line); + } else if ($1->isMatrix()) { // constant folding for matrices + $$ = context->addConstMatrixNode($3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), $1, $2.line); + } + } else { + if ($3->getQualifier() == EvqConst) { + if (($1->isVector() || $1->isMatrix()) && $1->getType().getNominalSize() <= $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() && !$1->isArray() ) { + std::stringstream extraInfoStream; + extraInfoStream << "field selection out of range '" << $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() << "'"; + std::string extraInfo = extraInfoStream.str(); + context->error($2.line, "", "[", extraInfo.c_str()); + context->recover(); + } else { + if ($1->isArray()) { + if ($1->getType().getArraySize() == 0) { + if ($1->getType().getMaxArraySize() <= $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst()) { + if (context->arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), true, $2.line)) + context->recover(); + } else { + if (context->arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), 0, false, $2.line)) + context->recover(); + } + } else if ( $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() >= $1->getType().getArraySize()) { + std::stringstream extraInfoStream; + extraInfoStream << "array index out of range '" << $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() << "'"; + std::string extraInfo = extraInfoStream.str(); + context->error($2.line, "", "[", extraInfo.c_str()); + context->recover(); + } + } + $$ = context->intermediate.addIndex(EOpIndexDirect, $1, $3, $2.line); + } + } else { + if ($1->isArray() && $1->getType().getArraySize() == 0) { + context->error($2.line, "", "[", "array must be redeclared with a size before being indexed with a variable"); + context->recover(); + } + + $$ = context->intermediate.addIndex(EOpIndexIndirect, $1, $3, $2.line); + } + } + if ($$ == 0) { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setFConst(0.0f); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), $2.line); + } else if ($1->isArray()) { + if ($1->getType().getStruct()) + $$->setType(TType($1->getType().getStruct(), $1->getType().getTypeName())); + else + $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary, $1->getNominalSize(), $1->isMatrix())); + + if ($1->getType().getQualifier() == EvqConst) + $$->getTypePointer()->setQualifier(EvqConst); + } else if ($1->isMatrix() && $1->getType().getQualifier() == EvqConst) + $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqConst, $1->getNominalSize())); + else if ($1->isMatrix()) + $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary, $1->getNominalSize())); + else if ($1->isVector() && $1->getType().getQualifier() == EvqConst) + $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqConst)); + else if ($1->isVector()) + $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary)); + else + $$->setType($1->getType()); + } + | function_call { + $$ = $1; + } + | postfix_expression DOT FIELD_SELECTION { + if ($1->isArray()) { + context->error($3.line, "cannot apply dot operator to an array", "."); + context->recover(); + } + + if ($1->isVector()) { + TVectorFields fields; + if (! context->parseVectorFields(*$3.string, $1->getNominalSize(), fields, $3.line)) { + fields.num = 1; + fields.offsets[0] = 0; + context->recover(); + } + + if ($1->getType().getQualifier() == EvqConst) { // constant folding for vector fields + $$ = context->addConstVectorNode(fields, $1, $3.line); + if ($$ == 0) { + context->recover(); + $$ = $1; + } + else + $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqConst, (int) (*$3.string).size())); + } else { + TString vectorString = *$3.string; + TIntermTyped* index = context->intermediate.addSwizzle(fields, $3.line); + $$ = context->intermediate.addIndex(EOpVectorSwizzle, $1, index, $2.line); + $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary, (int) vectorString.size())); + } + } else if ($1->isMatrix()) { + TMatrixFields fields; + if (! context->parseMatrixFields(*$3.string, $1->getNominalSize(), fields, $3.line)) { + fields.wholeRow = false; + fields.wholeCol = false; + fields.row = 0; + fields.col = 0; + context->recover(); + } + + if (fields.wholeRow || fields.wholeCol) { + context->error($2.line, " non-scalar fields not implemented yet", "."); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst(0); + TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), $3.line); + $$ = context->intermediate.addIndex(EOpIndexDirect, $1, index, $2.line); + $$->setType(TType($1->getBasicType(), $1->getPrecision(),EvqTemporary, $1->getNominalSize())); + } else { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst(fields.col * $1->getNominalSize() + fields.row); + TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), $3.line); + $$ = context->intermediate.addIndex(EOpIndexDirect, $1, index, $2.line); + $$->setType(TType($1->getBasicType(), $1->getPrecision())); + } + } else if ($1->getBasicType() == EbtStruct) { + bool fieldFound = false; + const TTypeList* fields = $1->getType().getStruct(); + if (fields == 0) { + context->error($2.line, "structure has no fields", "Internal Error"); + context->recover(); + $$ = $1; + } else { + unsigned int i; + for (i = 0; i < fields->size(); ++i) { + if ((*fields)[i].type->getFieldName() == *$3.string) { + fieldFound = true; + break; + } + } + if (fieldFound) { + if ($1->getType().getQualifier() == EvqConst) { + $$ = context->addConstStruct(*$3.string, $1, $2.line); + if ($$ == 0) { + context->recover(); + $$ = $1; + } + else { + $$->setType(*(*fields)[i].type); + // change the qualifier of the return type, not of the structure field + // as the structure definition is shared between various structures. + $$->getTypePointer()->setQualifier(EvqConst); + } + } else { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst(i); + TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, *(*fields)[i].type, $3.line); + $$ = context->intermediate.addIndex(EOpIndexDirectStruct, $1, index, $2.line); + $$->setType(*(*fields)[i].type); + } + } else { + context->error($2.line, " no such field in structure", $3.string->c_str()); + context->recover(); + $$ = $1; + } + } + } else { + context->error($2.line, " field selection requires structure, vector, or matrix on left hand side", $3.string->c_str()); + context->recover(); + $$ = $1; + } + // don't delete $3.string, it's from the pool + } + | postfix_expression INC_OP { + if (context->lValueErrorCheck($2.line, "++", $1)) + context->recover(); + $$ = context->intermediate.addUnaryMath(EOpPostIncrement, $1, $2.line, context->symbolTable); + if ($$ == 0) { + context->unaryOpError($2.line, "++", $1->getCompleteString()); + context->recover(); + $$ = $1; + } + } + | postfix_expression DEC_OP { + if (context->lValueErrorCheck($2.line, "--", $1)) + context->recover(); + $$ = context->intermediate.addUnaryMath(EOpPostDecrement, $1, $2.line, context->symbolTable); + if ($$ == 0) { + context->unaryOpError($2.line, "--", $1->getCompleteString()); + context->recover(); + $$ = $1; + } + } + ; + +integer_expression + : expression { + if (context->integerErrorCheck($1, "[]")) + context->recover(); + $$ = $1; + } + ; + +function_call + : function_call_or_method { + TFunction* fnCall = $1.function; + TOperator op = fnCall->getBuiltInOp(); + + if (op != EOpNull) + { + // + // Then this should be a constructor. + // Don't go through the symbol table for constructors. + // Their parameters will be verified algorithmically. + // + TType type(EbtVoid, EbpUndefined); // use this to get the type back + if (context->constructorErrorCheck($1.line, $1.intermNode, *fnCall, op, &type)) { + $$ = 0; + } else { + // + // It's a constructor, of type 'type'. + // + $$ = context->addConstructor($1.intermNode, &type, op, fnCall, $1.line); + } + + if ($$ == 0) { + context->recover(); + $$ = context->intermediate.setAggregateOperator(0, op, $1.line); + } + $$->setType(type); + } else { + // + // Not a constructor. Find it in the symbol table. + // + const TFunction* fnCandidate; + bool builtIn; + fnCandidate = context->findFunction($1.line, fnCall, &builtIn); + if (fnCandidate) { + // + // A declared function. + // + if (builtIn && !fnCandidate->getExtension().empty() && + context->extensionErrorCheck($1.line, fnCandidate->getExtension())) { + context->recover(); + } + op = fnCandidate->getBuiltInOp(); + if (builtIn && op != EOpNull) { + // + // A function call mapped to a built-in operation. + // + if (fnCandidate->getParamCount() == 1) { + // + // Treat it like a built-in unary operator. + // + $$ = context->intermediate.addUnaryMath(op, $1.intermNode, 0, context->symbolTable); + if ($$ == 0) { + std::stringstream extraInfoStream; + extraInfoStream << "built in unary operator function. Type: " << static_cast<TIntermTyped*>($1.intermNode)->getCompleteString(); + std::string extraInfo = extraInfoStream.str(); + context->error($1.intermNode->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str()); + YYERROR; + } + } else { + $$ = context->intermediate.setAggregateOperator($1.intermAggregate, op, $1.line); + } + } else { + // This is a real function call + + $$ = context->intermediate.setAggregateOperator($1.intermAggregate, EOpFunctionCall, $1.line); + $$->setType(fnCandidate->getReturnType()); + + // this is how we know whether the given function is a builtIn function or a user defined function + // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also + // if builtIn == true, it's definitely a builtIn function with EOpNull + if (!builtIn) + $$->getAsAggregate()->setUserDefined(); + $$->getAsAggregate()->setName(fnCandidate->getMangledName()); + + TQualifier qual; + for (int i = 0; i < fnCandidate->getParamCount(); ++i) { + qual = fnCandidate->getParam(i).type->getQualifier(); + if (qual == EvqOut || qual == EvqInOut) { + if (context->lValueErrorCheck($$->getLine(), "assign", $$->getAsAggregate()->getSequence()[i]->getAsTyped())) { + context->error($1.intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error"); + context->recover(); + } + } + } + } + $$->setType(fnCandidate->getReturnType()); + } else { + // error message was put out by PaFindFunction() + // Put on a dummy node for error recovery + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setFConst(0.0f); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), $1.line); + context->recover(); + } + } + delete fnCall; + } + ; + +function_call_or_method + : function_call_generic { + $$ = $1; + } + | postfix_expression DOT function_call_generic { + context->error($3.line, "methods are not supported", ""); + context->recover(); + $$ = $3; + } + ; + +function_call_generic + : function_call_header_with_parameters RIGHT_PAREN { + $$ = $1; + $$.line = $2.line; + } + | function_call_header_no_parameters RIGHT_PAREN { + $$ = $1; + $$.line = $2.line; + } + ; + +function_call_header_no_parameters + : function_call_header VOID_TYPE { + $$.function = $1; + $$.intermNode = 0; + } + | function_call_header { + $$.function = $1; + $$.intermNode = 0; + } + ; + +function_call_header_with_parameters + : function_call_header assignment_expression { + TParameter param = { 0, new TType($2->getType()) }; + $1->addParameter(param); + $$.function = $1; + $$.intermNode = $2; + } + | function_call_header_with_parameters COMMA assignment_expression { + TParameter param = { 0, new TType($3->getType()) }; + $1.function->addParameter(param); + $$.function = $1.function; + $$.intermNode = context->intermediate.growAggregate($1.intermNode, $3, $2.line); + } + ; + +function_call_header + : function_identifier LEFT_PAREN { + $$ = $1; + } + ; + +// Grammar Note: Constructors look like functions, but are recognized as types. + +function_identifier + : type_specifier_nonarray { + // + // Constructor + // + TOperator op = EOpNull; + if ($1.userDef) { + op = EOpConstructStruct; + } else { + switch ($1.type) { + case EbtFloat: + if ($1.matrix) { + switch($1.size) { + case 2: op = EOpConstructMat2; break; + case 3: op = EOpConstructMat3; break; + case 4: op = EOpConstructMat4; break; + } + } else { + switch($1.size) { + case 1: op = EOpConstructFloat; break; + case 2: op = EOpConstructVec2; break; + case 3: op = EOpConstructVec3; break; + case 4: op = EOpConstructVec4; break; + } + } + break; + case EbtInt: + switch($1.size) { + case 1: op = EOpConstructInt; break; + case 2: FRAG_VERT_ONLY("ivec2", $1.line); op = EOpConstructIVec2; break; + case 3: FRAG_VERT_ONLY("ivec3", $1.line); op = EOpConstructIVec3; break; + case 4: FRAG_VERT_ONLY("ivec4", $1.line); op = EOpConstructIVec4; break; + } + break; + case EbtBool: + switch($1.size) { + case 1: op = EOpConstructBool; break; + case 2: FRAG_VERT_ONLY("bvec2", $1.line); op = EOpConstructBVec2; break; + case 3: FRAG_VERT_ONLY("bvec3", $1.line); op = EOpConstructBVec3; break; + case 4: FRAG_VERT_ONLY("bvec4", $1.line); op = EOpConstructBVec4; break; + } + break; + default: break; + } + if (op == EOpNull) { + context->error($1.line, "cannot construct this type", getBasicString($1.type)); + context->recover(); + $1.type = EbtFloat; + op = EOpConstructFloat; + } + } + TString tempString; + TType type($1); + TFunction *function = new TFunction(&tempString, type, op); + $$ = function; + } + | IDENTIFIER { + if (context->reservedErrorCheck($1.line, *$1.string)) + context->recover(); + TType type(EbtVoid, EbpUndefined); + TFunction *function = new TFunction($1.string, type); + $$ = function; + } + | FIELD_SELECTION { + if (context->reservedErrorCheck($1.line, *$1.string)) + context->recover(); + TType type(EbtVoid, EbpUndefined); + TFunction *function = new TFunction($1.string, type); + $$ = function; + } + ; + +unary_expression + : postfix_expression { + $$ = $1; + } + | INC_OP unary_expression { + if (context->lValueErrorCheck($1.line, "++", $2)) + context->recover(); + $$ = context->intermediate.addUnaryMath(EOpPreIncrement, $2, $1.line, context->symbolTable); + if ($$ == 0) { + context->unaryOpError($1.line, "++", $2->getCompleteString()); + context->recover(); + $$ = $2; + } + } + | DEC_OP unary_expression { + if (context->lValueErrorCheck($1.line, "--", $2)) + context->recover(); + $$ = context->intermediate.addUnaryMath(EOpPreDecrement, $2, $1.line, context->symbolTable); + if ($$ == 0) { + context->unaryOpError($1.line, "--", $2->getCompleteString()); + context->recover(); + $$ = $2; + } + } + | unary_operator unary_expression { + if ($1.op != EOpNull) { + $$ = context->intermediate.addUnaryMath($1.op, $2, $1.line, context->symbolTable); + if ($$ == 0) { + const char* errorOp = ""; + switch($1.op) { + case EOpNegative: errorOp = "-"; break; + case EOpLogicalNot: errorOp = "!"; break; + default: break; + } + context->unaryOpError($1.line, errorOp, $2->getCompleteString()); + context->recover(); + $$ = $2; + } + } else + $$ = $2; + } + ; +// Grammar Note: No traditional style type casts. + +unary_operator + : PLUS { $$.line = $1.line; $$.op = EOpNull; } + | DASH { $$.line = $1.line; $$.op = EOpNegative; } + | BANG { $$.line = $1.line; $$.op = EOpLogicalNot; } + ; +// Grammar Note: No '*' or '&' unary ops. Pointers are not supported. + +multiplicative_expression + : unary_expression { $$ = $1; } + | multiplicative_expression STAR unary_expression { + FRAG_VERT_ONLY("*", $2.line); + $$ = context->intermediate.addBinaryMath(EOpMul, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "*", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + $$ = $1; + } + } + | multiplicative_expression SLASH unary_expression { + FRAG_VERT_ONLY("/", $2.line); + $$ = context->intermediate.addBinaryMath(EOpDiv, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "/", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + $$ = $1; + } + } + ; + +additive_expression + : multiplicative_expression { $$ = $1; } + | additive_expression PLUS multiplicative_expression { + $$ = context->intermediate.addBinaryMath(EOpAdd, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "+", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + $$ = $1; + } + } + | additive_expression DASH multiplicative_expression { + $$ = context->intermediate.addBinaryMath(EOpSub, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "-", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + $$ = $1; + } + } + ; + +shift_expression + : additive_expression { $$ = $1; } + ; + +relational_expression + : shift_expression { $$ = $1; } + | relational_expression LEFT_ANGLE shift_expression { + $$ = context->intermediate.addBinaryMath(EOpLessThan, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "<", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line); + } + } + | relational_expression RIGHT_ANGLE shift_expression { + $$ = context->intermediate.addBinaryMath(EOpGreaterThan, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, ">", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line); + } + } + | relational_expression LE_OP shift_expression { + $$ = context->intermediate.addBinaryMath(EOpLessThanEqual, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "<=", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line); + } + } + | relational_expression GE_OP shift_expression { + $$ = context->intermediate.addBinaryMath(EOpGreaterThanEqual, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, ">=", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line); + } + } + ; + +equality_expression + : relational_expression { $$ = $1; } + | equality_expression EQ_OP relational_expression { + $$ = context->intermediate.addBinaryMath(EOpEqual, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "==", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line); + } + } + | equality_expression NE_OP relational_expression { + $$ = context->intermediate.addBinaryMath(EOpNotEqual, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "!=", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line); + } + } + ; + +and_expression + : equality_expression { $$ = $1; } + ; + +exclusive_or_expression + : and_expression { $$ = $1; } + ; + +inclusive_or_expression + : exclusive_or_expression { $$ = $1; } + ; + +logical_and_expression + : inclusive_or_expression { $$ = $1; } + | logical_and_expression AND_OP inclusive_or_expression { + $$ = context->intermediate.addBinaryMath(EOpLogicalAnd, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "&&", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line); + } + } + ; + +logical_xor_expression + : logical_and_expression { $$ = $1; } + | logical_xor_expression XOR_OP logical_and_expression { + $$ = context->intermediate.addBinaryMath(EOpLogicalXor, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "^^", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line); + } + } + ; + +logical_or_expression + : logical_xor_expression { $$ = $1; } + | logical_or_expression OR_OP logical_xor_expression { + $$ = context->intermediate.addBinaryMath(EOpLogicalOr, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "||", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line); + } + } + ; + +conditional_expression + : logical_or_expression { $$ = $1; } + | logical_or_expression QUESTION expression COLON assignment_expression { + if (context->boolErrorCheck($2.line, $1)) + context->recover(); + + $$ = context->intermediate.addSelection($1, $3, $5, $2.line); + if ($3->getType() != $5->getType()) + $$ = 0; + + if ($$ == 0) { + context->binaryOpError($2.line, ":", $3->getCompleteString(), $5->getCompleteString()); + context->recover(); + $$ = $5; + } + } + ; + +assignment_expression + : conditional_expression { $$ = $1; } + | unary_expression assignment_operator assignment_expression { + if (context->lValueErrorCheck($2.line, "assign", $1)) + context->recover(); + $$ = context->intermediate.addAssign($2.op, $1, $3, $2.line); + if ($$ == 0) { + context->assignError($2.line, "assign", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + $$ = $1; + } + } + ; + +assignment_operator + : EQUAL { $$.line = $1.line; $$.op = EOpAssign; } + | MUL_ASSIGN { FRAG_VERT_ONLY("*=", $1.line); $$.line = $1.line; $$.op = EOpMulAssign; } + | DIV_ASSIGN { FRAG_VERT_ONLY("/=", $1.line); $$.line = $1.line; $$.op = EOpDivAssign; } + | ADD_ASSIGN { $$.line = $1.line; $$.op = EOpAddAssign; } + | SUB_ASSIGN { $$.line = $1.line; $$.op = EOpSubAssign; } + ; + +expression + : assignment_expression { + $$ = $1; + } + | expression COMMA assignment_expression { + $$ = context->intermediate.addComma($1, $3, $2.line); + if ($$ == 0) { + context->binaryOpError($2.line, ",", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + $$ = $3; + } + } + ; + +constant_expression + : conditional_expression { + if (context->constErrorCheck($1)) + context->recover(); + $$ = $1; + } + ; + +declaration + : function_prototype SEMICOLON { + TFunction &function = *($1.function); + + TIntermAggregate *prototype = new TIntermAggregate; + prototype->setType(function.getReturnType()); + prototype->setName(function.getName()); + + for (int i = 0; i < function.getParamCount(); i++) + { + const TParameter ¶m = function.getParam(i); + if (param.name != 0) + { + TVariable *variable = new TVariable(param.name, *param.type); + + prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), $1.line), $1.line); + } + else + { + prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(0, "", *param.type, $1.line), $1.line); + } + } + + prototype->setOp(EOpPrototype); + $$ = prototype; + + context->symbolTable.pop(); + } + | init_declarator_list SEMICOLON { + if ($1.intermAggregate) + $1.intermAggregate->setOp(EOpDeclaration); + $$ = $1.intermAggregate; + } + | PRECISION precision_qualifier type_specifier_no_prec SEMICOLON { + context->symbolTable.setDefaultPrecision( $3.type, $2 ); + $$ = 0; + } + ; + +function_prototype + : function_declarator RIGHT_PAREN { + // + // Multiple declarations of the same function are allowed. + // + // If this is a definition, the definition production code will check for redefinitions + // (we don't know at this point if it's a definition or not). + // + // Redeclarations are allowed. But, return types and parameter qualifiers must match. + // + TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find($1->getMangledName())); + if (prevDec) { + if (prevDec->getReturnType() != $1->getReturnType()) { + context->error($2.line, "overloaded functions must have the same return type", $1->getReturnType().getBasicString()); + context->recover(); + } + for (int i = 0; i < prevDec->getParamCount(); ++i) { + if (prevDec->getParam(i).type->getQualifier() != $1->getParam(i).type->getQualifier()) { + context->error($2.line, "overloaded functions must have the same parameter qualifiers", $1->getParam(i).type->getQualifierString()); + context->recover(); + } + } + } + + // + // If this is a redeclaration, it could also be a definition, + // in which case, we want to use the variable names from this one, and not the one that's + // being redeclared. So, pass back up this declaration, not the one in the symbol table. + // + $$.function = $1; + $$.line = $2.line; + + // We're at the inner scope level of the function's arguments and body statement. + // Add the function prototype to the surrounding scope instead. + context->symbolTable.getOuterLevel()->insert(*$$.function); + } + ; + +function_declarator + : function_header { + $$ = $1; + } + | function_header_with_parameters { + $$ = $1; + } + ; + + +function_header_with_parameters + : function_header parameter_declaration { + // Add the parameter + $$ = $1; + if ($2.param.type->getBasicType() != EbtVoid) + $1->addParameter($2.param); + else + delete $2.param.type; + } + | function_header_with_parameters COMMA parameter_declaration { + // + // Only first parameter of one-parameter functions can be void + // The check for named parameters not being void is done in parameter_declarator + // + if ($3.param.type->getBasicType() == EbtVoid) { + // + // This parameter > first is void + // + context->error($2.line, "cannot be an argument type except for '(void)'", "void"); + context->recover(); + delete $3.param.type; + } else { + // Add the parameter + $$ = $1; + $1->addParameter($3.param); + } + } + ; + +function_header + : fully_specified_type IDENTIFIER LEFT_PAREN { + if ($1.qualifier != EvqGlobal && $1.qualifier != EvqTemporary) { + context->error($2.line, "no qualifiers allowed for function return", getQualifierString($1.qualifier)); + context->recover(); + } + // make sure a sampler is not involved as well... + if (context->structQualifierErrorCheck($2.line, $1)) + context->recover(); + + // Add the function as a prototype after parsing it (we do not support recursion) + TFunction *function; + TType type($1); + function = new TFunction($2.string, type); + $$ = function; + + context->symbolTable.push(); + } + ; + +parameter_declarator + // Type + name + : type_specifier IDENTIFIER { + if ($1.type == EbtVoid) { + context->error($2.line, "illegal use of type 'void'", $2.string->c_str()); + context->recover(); + } + if (context->reservedErrorCheck($2.line, *$2.string)) + context->recover(); + TParameter param = {$2.string, new TType($1)}; + $$.line = $2.line; + $$.param = param; + } + | type_specifier IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { + // Check that we can make an array out of this type + if (context->arrayTypeErrorCheck($3.line, $1)) + context->recover(); + + if (context->reservedErrorCheck($2.line, *$2.string)) + context->recover(); + + int size; + if (context->arraySizeErrorCheck($3.line, $4, size)) + context->recover(); + $1.setArray(true, size); + + TType* type = new TType($1); + TParameter param = { $2.string, type }; + $$.line = $2.line; + $$.param = param; + } + ; + +parameter_declaration + // + // The only parameter qualifier a parameter can have are + // IN_QUAL, OUT_QUAL, INOUT_QUAL, or CONST. + // + + // + // Type + name + // + : type_qualifier parameter_qualifier parameter_declarator { + $$ = $3; + if (context->paramErrorCheck($3.line, $1.qualifier, $2, $$.param.type)) + context->recover(); + } + | parameter_qualifier parameter_declarator { + $$ = $2; + if (context->parameterSamplerErrorCheck($2.line, $1, *$2.param.type)) + context->recover(); + if (context->paramErrorCheck($2.line, EvqTemporary, $1, $$.param.type)) + context->recover(); + } + // + // Only type + // + | type_qualifier parameter_qualifier parameter_type_specifier { + $$ = $3; + if (context->paramErrorCheck($3.line, $1.qualifier, $2, $$.param.type)) + context->recover(); + } + | parameter_qualifier parameter_type_specifier { + $$ = $2; + if (context->parameterSamplerErrorCheck($2.line, $1, *$2.param.type)) + context->recover(); + if (context->paramErrorCheck($2.line, EvqTemporary, $1, $$.param.type)) + context->recover(); + } + ; + +parameter_qualifier + : /* empty */ { + $$ = EvqIn; + } + | IN_QUAL { + $$ = EvqIn; + } + | OUT_QUAL { + $$ = EvqOut; + } + | INOUT_QUAL { + $$ = EvqInOut; + } + ; + +parameter_type_specifier + : type_specifier { + TParameter param = { 0, new TType($1) }; + $$.param = param; + } + ; + +init_declarator_list + : single_declaration { + $$ = $1; + } + | init_declarator_list COMMA IDENTIFIER { + if ($1.type.type == EbtInvariant && !$3.symbol) + { + context->error($3.line, "undeclared identifier declared as invariant", $3.string->c_str()); + context->recover(); + } + + TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$3.string, TType($1.type), $3.line); + $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, symbol, $3.line); + + if (context->structQualifierErrorCheck($3.line, $$.type)) + context->recover(); + + if (context->nonInitConstErrorCheck($3.line, *$3.string, $$.type, false)) + context->recover(); + + TVariable* variable = 0; + if (context->nonInitErrorCheck($3.line, *$3.string, $$.type, variable)) + context->recover(); + if (symbol && variable) + symbol->setId(variable->getUniqueId()); + } + | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET RIGHT_BRACKET { + if (context->structQualifierErrorCheck($3.line, $1.type)) + context->recover(); + + if (context->nonInitConstErrorCheck($3.line, *$3.string, $1.type, true)) + context->recover(); + + $$ = $1; + + if (context->arrayTypeErrorCheck($4.line, $1.type) || context->arrayQualifierErrorCheck($4.line, $1.type)) + context->recover(); + else { + $1.type.setArray(true); + TVariable* variable; + if (context->arrayErrorCheck($4.line, *$3.string, $1.type, variable)) + context->recover(); + } + } + | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { + if (context->structQualifierErrorCheck($3.line, $1.type)) + context->recover(); + + if (context->nonInitConstErrorCheck($3.line, *$3.string, $1.type, true)) + context->recover(); + + $$ = $1; + + if (context->arrayTypeErrorCheck($4.line, $1.type) || context->arrayQualifierErrorCheck($4.line, $1.type)) + context->recover(); + else { + int size; + if (context->arraySizeErrorCheck($4.line, $5, size)) + context->recover(); + $1.type.setArray(true, size); + TVariable* variable = 0; + if (context->arrayErrorCheck($4.line, *$3.string, $1.type, variable)) + context->recover(); + TType type = TType($1.type); + type.setArraySize(size); + $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, context->intermediate.addSymbol(variable ? variable->getUniqueId() : 0, *$3.string, type, $3.line), $3.line); + } + } + | init_declarator_list COMMA IDENTIFIER EQUAL initializer { + if (context->structQualifierErrorCheck($3.line, $1.type)) + context->recover(); + + $$ = $1; + + TIntermNode* intermNode; + if (!context->executeInitializer($3.line, *$3.string, $1.type, $5, intermNode)) { + // + // build the intermediate representation + // + if (intermNode) + $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, intermNode, $4.line); + else + $$.intermAggregate = $1.intermAggregate; + } else { + context->recover(); + $$.intermAggregate = 0; + } + } + ; + +single_declaration + : fully_specified_type { + $$.type = $1; + $$.intermAggregate = context->intermediate.makeAggregate(context->intermediate.addSymbol(0, "", TType($1), $1.line), $1.line); + } + | fully_specified_type IDENTIFIER { + TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, TType($1), $2.line); + $$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line); + + if (context->structQualifierErrorCheck($2.line, $$.type)) + context->recover(); + + if (context->nonInitConstErrorCheck($2.line, *$2.string, $$.type, false)) + context->recover(); + + $$.type = $1; + + TVariable* variable = 0; + if (context->nonInitErrorCheck($2.line, *$2.string, $$.type, variable)) + context->recover(); + if (variable && symbol) + symbol->setId(variable->getUniqueId()); + } + | fully_specified_type IDENTIFIER LEFT_BRACKET RIGHT_BRACKET { + context->error($2.line, "unsized array declarations not supported", $2.string->c_str()); + context->recover(); + + TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, TType($1), $2.line); + $$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line); + $$.type = $1; + } + | fully_specified_type IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { + TType type = TType($1); + int size; + if (context->arraySizeErrorCheck($2.line, $4, size)) + context->recover(); + type.setArraySize(size); + TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, type, $2.line); + $$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line); + + if (context->structQualifierErrorCheck($2.line, $1)) + context->recover(); + + if (context->nonInitConstErrorCheck($2.line, *$2.string, $1, true)) + context->recover(); + + $$.type = $1; + + if (context->arrayTypeErrorCheck($3.line, $1) || context->arrayQualifierErrorCheck($3.line, $1)) + context->recover(); + else { + int size; + if (context->arraySizeErrorCheck($3.line, $4, size)) + context->recover(); + + $1.setArray(true, size); + TVariable* variable = 0; + if (context->arrayErrorCheck($3.line, *$2.string, $1, variable)) + context->recover(); + if (variable && symbol) + symbol->setId(variable->getUniqueId()); + } + } + | fully_specified_type IDENTIFIER EQUAL initializer { + if (context->structQualifierErrorCheck($2.line, $1)) + context->recover(); + + $$.type = $1; + + TIntermNode* intermNode; + if (!context->executeInitializer($2.line, *$2.string, $1, $4, intermNode)) { + // + // Build intermediate representation + // + if(intermNode) + $$.intermAggregate = context->intermediate.makeAggregate(intermNode, $3.line); + else + $$.intermAggregate = 0; + } else { + context->recover(); + $$.intermAggregate = 0; + } + } + | INVARIANT IDENTIFIER { + VERTEX_ONLY("invariant declaration", $1.line); + if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "invariant varying")) + context->recover(); + $$.type.setBasic(EbtInvariant, EvqInvariantVaryingOut, $2.line); + if (!$2.symbol) + { + context->error($2.line, "undeclared identifier declared as invariant", $2.string->c_str()); + context->recover(); + + $$.intermAggregate = 0; + } + else + { + TIntermSymbol *symbol = context->intermediate.addSymbol(0, *$2.string, TType($$.type), $2.line); + $$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line); + } + } + +// +// Place holder for the pack/unpack languages. +// +// | buffer_specifier { +// $$.intermAggregate = 0; +// } + ; + +// Grammar Note: No 'enum', or 'typedef'. + +// +// Place holder for the pack/unpack languages. +// +//%type <interm> buffer_declaration +//%type <interm.type> buffer_specifier input_or_output buffer_declaration_list +//buffer_specifier +// : input_or_output LEFT_BRACE buffer_declaration_list RIGHT_BRACE { +// } +// ; +// +//input_or_output +// : INPUT { +// if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "input")) +// context->recover(); +// UNPACK_ONLY("input", $1.line); +// $$.qualifier = EvqInput; +// } +// | OUTPUT { +// if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "output")) +// context->recover(); +// PACK_ONLY("output", $1.line); +// $$.qualifier = EvqOutput; +// } +// ; + +// +// Place holder for the pack/unpack languages. +// +//buffer_declaration_list +// : buffer_declaration { +// } +// | buffer_declaration_list buffer_declaration { +// } +// ; + +// +// Input/output semantics: +// float must be 16 or 32 bits +// float alignment restrictions? +// check for only one input and only one output +// sum of bitfields has to be multiple of 32 +// + +// +// Place holder for the pack/unpack languages. +// +//buffer_declaration +// : type_specifier IDENTIFIER COLON constant_expression SEMICOLON { +// if (context->reservedErrorCheck($2.line, *$2.string, context)) +// context->recover(); +// $$.variable = new TVariable($2.string, $1); +// if (! context->symbolTable.insert(*$$.variable)) { +// context->error($2.line, "redefinition", $$.variable->getName().c_str()); +// context->recover(); +// // don't have to delete $$.variable, the pool pop will take care of it +// } +// } +// ; + +fully_specified_type + : type_specifier { + $$ = $1; + + if ($1.array) { + context->error($1.line, "not supported", "first-class array"); + context->recover(); + $1.setArray(false); + } + } + | type_qualifier type_specifier { + if ($2.array) { + context->error($2.line, "not supported", "first-class array"); + context->recover(); + $2.setArray(false); + } + + if ($1.qualifier == EvqAttribute && + ($2.type == EbtBool || $2.type == EbtInt)) { + context->error($2.line, "cannot be bool or int", getQualifierString($1.qualifier)); + context->recover(); + } + if (($1.qualifier == EvqVaryingIn || $1.qualifier == EvqVaryingOut) && + ($2.type == EbtBool || $2.type == EbtInt)) { + context->error($2.line, "cannot be bool or int", getQualifierString($1.qualifier)); + context->recover(); + } + $$ = $2; + $$.qualifier = $1.qualifier; + } + ; + +type_qualifier + : CONST_QUAL { + $$.setBasic(EbtVoid, EvqConst, $1.line); + } + | ATTRIBUTE { + VERTEX_ONLY("attribute", $1.line); + if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "attribute")) + context->recover(); + $$.setBasic(EbtVoid, EvqAttribute, $1.line); + } + | VARYING { + if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "varying")) + context->recover(); + if (context->shaderType == SH_VERTEX_SHADER) + $$.setBasic(EbtVoid, EvqVaryingOut, $1.line); + else + $$.setBasic(EbtVoid, EvqVaryingIn, $1.line); + } + | INVARIANT VARYING { + if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "invariant varying")) + context->recover(); + if (context->shaderType == SH_VERTEX_SHADER) + $$.setBasic(EbtVoid, EvqInvariantVaryingOut, $1.line); + else + $$.setBasic(EbtVoid, EvqInvariantVaryingIn, $1.line); + } + | UNIFORM { + if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "uniform")) + context->recover(); + $$.setBasic(EbtVoid, EvqUniform, $1.line); + } + ; + +type_specifier + : type_specifier_no_prec { + $$ = $1; + + if ($$.precision == EbpUndefined) { + $$.precision = context->symbolTable.getDefaultPrecision($1.type); + if (context->precisionErrorCheck($1.line, $$.precision, $1.type)) { + context->recover(); + } + } + } + | precision_qualifier type_specifier_no_prec { + $$ = $2; + $$.precision = $1; + } + ; + +precision_qualifier + : HIGH_PRECISION { + $$ = EbpHigh; + } + | MEDIUM_PRECISION { + $$ = EbpMedium; + } + | LOW_PRECISION { + $$ = EbpLow; + } + ; + +type_specifier_no_prec + : type_specifier_nonarray { + $$ = $1; + } + | type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET { + $$ = $1; + + if (context->arrayTypeErrorCheck($2.line, $1)) + context->recover(); + else { + int size; + if (context->arraySizeErrorCheck($2.line, $3, size)) + context->recover(); + $$.setArray(true, size); + } + } + ; + +type_specifier_nonarray + : VOID_TYPE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtVoid, qual, $1.line); + } + | FLOAT_TYPE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + } + | INT_TYPE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, $1.line); + } + | BOOL_TYPE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, $1.line); + } +// | UNSIGNED INT_TYPE { +// PACK_UNPACK_ONLY("unsigned", $1.line); +// TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; +// $$.setBasic(EbtInt, qual, $1.line); +// } + | VEC2 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(2); + } + | VEC3 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(3); + } + | VEC4 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(4); + } + | BVEC2 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, $1.line); + $$.setAggregate(2); + } + | BVEC3 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, $1.line); + $$.setAggregate(3); + } + | BVEC4 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, $1.line); + $$.setAggregate(4); + } + | IVEC2 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, $1.line); + $$.setAggregate(2); + } + | IVEC3 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, $1.line); + $$.setAggregate(3); + } + | IVEC4 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, $1.line); + $$.setAggregate(4); + } + | MATRIX2 { + FRAG_VERT_ONLY("mat2", $1.line); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(2, true); + } + | MATRIX3 { + FRAG_VERT_ONLY("mat3", $1.line); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(3, true); + } + | MATRIX4 { + FRAG_VERT_ONLY("mat4", $1.line); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(4, true); + } + | SAMPLER2D { + FRAG_VERT_ONLY("sampler2D", $1.line); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler2D, qual, $1.line); + } + | SAMPLERCUBE { + FRAG_VERT_ONLY("samplerCube", $1.line); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSamplerCube, qual, $1.line); + } + | struct_specifier { + FRAG_VERT_ONLY("struct", $1.line); + $$ = $1; + $$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + } + | TYPE_NAME { + // + // This is for user defined type names. The lexical phase looked up the + // type. + // + TType& structure = static_cast<TVariable*>($1.symbol)->getType(); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtStruct, qual, $1.line); + $$.userDef = &structure; + } + ; + +struct_specifier + : STRUCT IDENTIFIER LEFT_BRACE { if (context->enterStructDeclaration($2.line, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE { + if (context->reservedErrorCheck($2.line, *$2.string)) + context->recover(); + + TType* structure = new TType($5, *$2.string); + TVariable* userTypeDef = new TVariable($2.string, *structure, true); + if (! context->symbolTable.insert(*userTypeDef)) { + context->error($2.line, "redefinition", $2.string->c_str(), "struct"); + context->recover(); + } + $$.setBasic(EbtStruct, EvqTemporary, $1.line); + $$.userDef = structure; + context->exitStructDeclaration(); + } + | STRUCT LEFT_BRACE { if (context->enterStructDeclaration($2.line, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE { + TType* structure = new TType($4, TString("")); + $$.setBasic(EbtStruct, EvqTemporary, $1.line); + $$.userDef = structure; + context->exitStructDeclaration(); + } + ; + +struct_declaration_list + : struct_declaration { + $$ = $1; + } + | struct_declaration_list struct_declaration { + $$ = $1; + for (unsigned int i = 0; i < $2->size(); ++i) { + for (unsigned int j = 0; j < $$->size(); ++j) { + if ((*$$)[j].type->getFieldName() == (*$2)[i].type->getFieldName()) { + context->error((*$2)[i].line, "duplicate field name in structure:", "struct", (*$2)[i].type->getFieldName().c_str()); + context->recover(); + } + } + $$->push_back((*$2)[i]); + } + } + ; + +struct_declaration + : type_specifier struct_declarator_list SEMICOLON { + $$ = $2; + + if (context->voidErrorCheck($1.line, (*$2)[0].type->getFieldName(), $1)) { + context->recover(); + } + for (unsigned int i = 0; i < $$->size(); ++i) { + // + // Careful not to replace already known aspects of type, like array-ness + // + TType* type = (*$$)[i].type; + type->setBasicType($1.type); + type->setNominalSize($1.size); + type->setMatrix($1.matrix); + type->setPrecision($1.precision); + + // don't allow arrays of arrays + if (type->isArray()) { + if (context->arrayTypeErrorCheck($1.line, $1)) + context->recover(); + } + if ($1.array) + type->setArraySize($1.arraySize); + if ($1.userDef) { + type->setStruct($1.userDef->getStruct()); + type->setTypeName($1.userDef->getTypeName()); + } + + if (context->structNestingErrorCheck($1.line, *type)) { + context->recover(); + } + } + } + ; + +struct_declarator_list + : struct_declarator { + $$ = NewPoolTTypeList(); + $$->push_back($1); + } + | struct_declarator_list COMMA struct_declarator { + $$->push_back($3); + } + ; + +struct_declarator + : IDENTIFIER { + if (context->reservedErrorCheck($1.line, *$1.string)) + context->recover(); + + $$.type = new TType(EbtVoid, EbpUndefined); + $$.line = $1.line; + $$.type->setFieldName(*$1.string); + } + | IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { + if (context->reservedErrorCheck($1.line, *$1.string)) + context->recover(); + + $$.type = new TType(EbtVoid, EbpUndefined); + $$.line = $1.line; + $$.type->setFieldName(*$1.string); + + int size; + if (context->arraySizeErrorCheck($2.line, $3, size)) + context->recover(); + $$.type->setArraySize(size); + } + ; + +initializer + : assignment_expression { $$ = $1; } + ; + +declaration_statement + : declaration { $$ = $1; } + ; + +statement + : compound_statement { $$ = $1; } + | simple_statement { $$ = $1; } + ; + +// Grammar Note: No labeled statements; 'goto' is not supported. + +simple_statement + : declaration_statement { $$ = $1; } + | expression_statement { $$ = $1; } + | selection_statement { $$ = $1; } + | iteration_statement { $$ = $1; } + | jump_statement { $$ = $1; } + ; + +compound_statement + : LEFT_BRACE RIGHT_BRACE { $$ = 0; } + | LEFT_BRACE { context->symbolTable.push(); } statement_list { context->symbolTable.pop(); } RIGHT_BRACE { + if ($3 != 0) { + $3->setOp(EOpSequence); + $3->setEndLine($5.line); + } + $$ = $3; + } + ; + +statement_no_new_scope + : compound_statement_no_new_scope { $$ = $1; } + | simple_statement { $$ = $1; } + ; + +statement_with_scope + : { context->symbolTable.push(); } compound_statement_no_new_scope { context->symbolTable.pop(); $$ = $2; } + | { context->symbolTable.push(); } simple_statement { context->symbolTable.pop(); $$ = $2; } + ; + +compound_statement_no_new_scope + // Statement that doesn't create a new scope, for selection_statement, iteration_statement + : LEFT_BRACE RIGHT_BRACE { + $$ = 0; + } + | LEFT_BRACE statement_list RIGHT_BRACE { + if ($2) { + $2->setOp(EOpSequence); + $2->setEndLine($3.line); + } + $$ = $2; + } + ; + +statement_list + : statement { + $$ = context->intermediate.makeAggregate($1, 0); + } + | statement_list statement { + $$ = context->intermediate.growAggregate($1, $2, 0); + } + ; + +expression_statement + : SEMICOLON { $$ = 0; } + | expression SEMICOLON { $$ = static_cast<TIntermNode*>($1); } + ; + +selection_statement + : IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement { + if (context->boolErrorCheck($1.line, $3)) + context->recover(); + $$ = context->intermediate.addSelection($3, $5, $1.line); + } + ; + +selection_rest_statement + : statement_with_scope ELSE statement_with_scope { + $$.node1 = $1; + $$.node2 = $3; + } + | statement_with_scope { + $$.node1 = $1; + $$.node2 = 0; + } + ; + +// Grammar Note: No 'switch'. Switch statements not supported. + +condition + // In 1996 c++ draft, conditions can include single declarations + : expression { + $$ = $1; + if (context->boolErrorCheck($1->getLine(), $1)) + context->recover(); + } + | fully_specified_type IDENTIFIER EQUAL initializer { + TIntermNode* intermNode; + if (context->structQualifierErrorCheck($2.line, $1)) + context->recover(); + if (context->boolErrorCheck($2.line, $1)) + context->recover(); + + if (!context->executeInitializer($2.line, *$2.string, $1, $4, intermNode)) + $$ = $4; + else { + context->recover(); + $$ = 0; + } + } + ; + +iteration_statement + : WHILE LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope { + context->symbolTable.pop(); + $$ = context->intermediate.addLoop(ELoopWhile, 0, $4, 0, $6, $1.line); + --context->loopNestingLevel; + } + | DO { ++context->loopNestingLevel; } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON { + if (context->boolErrorCheck($8.line, $6)) + context->recover(); + + $$ = context->intermediate.addLoop(ELoopDoWhile, 0, $6, 0, $3, $4.line); + --context->loopNestingLevel; + } + | FOR LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope { + context->symbolTable.pop(); + $$ = context->intermediate.addLoop(ELoopFor, $4, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), $7, $1.line); + --context->loopNestingLevel; + } + ; + +for_init_statement + : expression_statement { + $$ = $1; + } + | declaration_statement { + $$ = $1; + } + ; + +conditionopt + : condition { + $$ = $1; + } + | /* May be null */ { + $$ = 0; + } + ; + +for_rest_statement + : conditionopt SEMICOLON { + $$.node1 = $1; + $$.node2 = 0; + } + | conditionopt SEMICOLON expression { + $$.node1 = $1; + $$.node2 = $3; + } + ; + +jump_statement + : CONTINUE SEMICOLON { + if (context->loopNestingLevel <= 0) { + context->error($1.line, "continue statement only allowed in loops", ""); + context->recover(); + } + $$ = context->intermediate.addBranch(EOpContinue, $1.line); + } + | BREAK SEMICOLON { + if (context->loopNestingLevel <= 0) { + context->error($1.line, "break statement only allowed in loops", ""); + context->recover(); + } + $$ = context->intermediate.addBranch(EOpBreak, $1.line); + } + | RETURN SEMICOLON { + $$ = context->intermediate.addBranch(EOpReturn, $1.line); + if (context->currentFunctionType->getBasicType() != EbtVoid) { + context->error($1.line, "non-void function must return a value", "return"); + context->recover(); + } + } + | RETURN expression SEMICOLON { + $$ = context->intermediate.addBranch(EOpReturn, $2, $1.line); + context->functionReturnsValue = true; + if (context->currentFunctionType->getBasicType() == EbtVoid) { + context->error($1.line, "void function cannot return a value", "return"); + context->recover(); + } else if (*(context->currentFunctionType) != $2->getType()) { + context->error($1.line, "function return is not matching type:", "return"); + context->recover(); + } + } + | DISCARD SEMICOLON { + FRAG_ONLY("discard", $1.line); + $$ = context->intermediate.addBranch(EOpKill, $1.line); + } + ; + +// Grammar Note: No 'goto'. Gotos are not supported. + +translation_unit + : external_declaration { + $$ = $1; + context->treeRoot = $$; + } + | translation_unit external_declaration { + $$ = context->intermediate.growAggregate($1, $2, 0); + context->treeRoot = $$; + } + ; + +external_declaration + : function_definition { + $$ = $1; + } + | declaration { + $$ = $1; + } + ; + +function_definition + : function_prototype { + TFunction* function = $1.function; + + const TSymbol *builtIn = context->symbolTable.findBuiltIn(function->getMangledName()); + + if (builtIn) + { + context->error($1.line, "built-in functions cannot be redefined", function->getName().c_str()); + context->recover(); + } + + TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find(function->getMangledName())); + // + // Note: 'prevDec' could be 'function' if this is the first time we've seen function + // as it would have just been put in the symbol table. Otherwise, we're looking up + // an earlier occurance. + // + if (prevDec->isDefined()) { + // + // Then this function already has a body. + // + context->error($1.line, "function already has a body", function->getName().c_str()); + context->recover(); + } + prevDec->setDefined(); + + // + // Raise error message if main function takes any parameters or return anything other than void + // + if (function->getName() == "main") { + if (function->getParamCount() > 0) { + context->error($1.line, "function cannot take any parameter(s)", function->getName().c_str()); + context->recover(); + } + if (function->getReturnType().getBasicType() != EbtVoid) { + context->error($1.line, "", function->getReturnType().getBasicString(), "main function cannot return a value"); + context->recover(); + } + } + + // + // Remember the return type for later checking for RETURN statements. + // + context->currentFunctionType = &(prevDec->getReturnType()); + context->functionReturnsValue = false; + + // + // Insert parameters into the symbol table. + // If the parameter has no name, it's not an error, just don't insert it + // (could be used for unused args). + // + // Also, accumulate the list of parameters into the HIL, so lower level code + // knows where to find parameters. + // + TIntermAggregate* paramNodes = new TIntermAggregate; + for (int i = 0; i < function->getParamCount(); i++) { + const TParameter& param = function->getParam(i); + if (param.name != 0) { + TVariable *variable = new TVariable(param.name, *param.type); + // + // Insert the parameters with name in the symbol table. + // + if (! context->symbolTable.insert(*variable)) { + context->error($1.line, "redefinition", variable->getName().c_str()); + context->recover(); + delete variable; + } + + // + // Add the parameter to the HIL + // + paramNodes = context->intermediate.growAggregate( + paramNodes, + context->intermediate.addSymbol(variable->getUniqueId(), + variable->getName(), + variable->getType(), $1.line), + $1.line); + } else { + paramNodes = context->intermediate.growAggregate(paramNodes, context->intermediate.addSymbol(0, "", *param.type, $1.line), $1.line); + } + } + context->intermediate.setAggregateOperator(paramNodes, EOpParameters, $1.line); + $1.intermAggregate = paramNodes; + context->loopNestingLevel = 0; + } + compound_statement_no_new_scope { + //?? Check that all paths return a value if return type != void ? + // May be best done as post process phase on intermediate code + if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) { + context->error($1.line, "function does not return a value:", "", $1.function->getName().c_str()); + context->recover(); + } + + $$ = context->intermediate.growAggregate($1.intermAggregate, $3, 0); + context->intermediate.setAggregateOperator($$, EOpFunction, $1.line); + $$->getAsAggregate()->setName($1.function->getMangledName().c_str()); + $$->getAsAggregate()->setType($1.function->getReturnType()); + + // store the pragma information for debug and optimize and other vendor specific + // information. This information can be queried from the parse tree + $$->getAsAggregate()->setOptimize(context->pragma().optimize); + $$->getAsAggregate()->setDebug(context->pragma().debug); + + if ($3 && $3->getAsAggregate()) + $$->getAsAggregate()->setEndLine($3->getAsAggregate()->getEndLine()); + + context->symbolTable.pop(); + } + ; + +%% + +int glslang_parse(TParseContext* context) { + return yyparse(context); +} +
diff --git a/src/GLES2/compiler/glslang_lex.cpp b/src/GLES2/compiler/glslang_lex.cpp new file mode 100644 index 0000000..e2c8a9e --- /dev/null +++ b/src/GLES2/compiler/glslang_lex.cpp
@@ -0,0 +1,3029 @@ +#line 17 "./glslang.l" +// +// Copyright (c) 2012 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. +// + +// This file is auto-generated by generate_parser.sh. DO NOT EDIT! + +// Ignore errors in auto-generated code. +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wswitch-enum" +#elif defined(_MSC_VER) +#pragma warning(disable: 4065) +#pragma warning(disable: 4189) +#pragma warning(disable: 4505) +#pragma warning(disable: 4701) +#endif + + + +#line 25 "./glslang_lex.cpp" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart(yyin ,yyscanner ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires + * access to the local variable yy_act. Since yyless() is a macro, it would break + * existing scanners that call yyless() from OUTSIDE yylex. + * One obvious solution it to make yy_act a global. I tried that, and saw + * a 5% performance hit in a non-yylineno scanner, because yy_act is + * normally declared as a register variable-- so it is not worth it. + */ + #define YY_LESS_LINENO(n) \ + do { \ + int yyl;\ + for ( yyl = n; yyl < yyleng; ++yyl )\ + if ( yytext[yyl] == '\n' )\ + --yylineno;\ + }while(0) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void yyrestart (FILE *input_file ,yyscan_t yyscanner ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void yypop_buffer_state (yyscan_t yyscanner ); + +static void yyensure_buffer_stack (yyscan_t yyscanner ); +static void yy_load_buffer_state (yyscan_t yyscanner ); +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); + +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) + +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); + +void *yyalloc (yy_size_t ,yyscan_t yyscanner ); +void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); +void yyfree (void * ,yyscan_t yyscanner ); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define yywrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); +static int yy_get_next_buffer (yyscan_t yyscanner ); +static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 154 +#define YY_END_OF_BUFFER 155 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[448] = + { 0, + 0, 0, 0, 0, 0, 0, 155, 153, 152, 152, + 137, 143, 148, 132, 133, 141, 140, 129, 138, 136, + 142, 101, 101, 130, 126, 144, 131, 145, 149, 97, + 134, 135, 147, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 127, 146, 128, 139, 3, 4, 3, + 151, 154, 150, 123, 109, 128, 117, 112, 107, 115, + 105, 116, 106, 104, 2, 1, 108, 103, 99, 100, + 0, 0, 101, 135, 127, 134, 124, 120, 122, 121, + 125, 97, 113, 119, 97, 97, 97, 97, 97, 97, + + 97, 97, 97, 97, 17, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 20, 22, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 114, 118, 5, + 150, 0, 1, 103, 0, 0, 102, 98, 110, 111, + 48, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 18, + 97, 97, 97, 97, 97, 97, 97, 97, 26, 97, + 97, 97, 97, 97, 97, 97, 97, 23, 97, 97, + + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 0, 104, 0, 103, 97, 28, 97, 97, 94, + 97, 97, 97, 97, 97, 97, 97, 21, 51, 97, + 97, 97, 67, 97, 97, 56, 71, 97, 97, 97, + 97, 97, 97, 97, 97, 68, 9, 33, 34, 35, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 54, 29, 97, 97, + 97, 97, 97, 97, 36, 37, 38, 27, 97, 97, + 97, 15, 42, 43, 44, 49, 12, 97, 97, 97, + + 97, 80, 81, 82, 97, 30, 72, 25, 83, 84, + 85, 7, 77, 78, 79, 97, 24, 75, 97, 97, + 39, 40, 41, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 69, 97, 97, 97, 97, 97, 97, 97, + 97, 50, 97, 96, 97, 97, 19, 97, 97, 97, + 97, 70, 64, 59, 97, 97, 97, 97, 97, 76, + 55, 97, 62, 32, 97, 93, 63, 47, 74, 57, + 97, 97, 97, 97, 97, 97, 97, 97, 58, 31, + 97, 97, 97, 8, 97, 97, 97, 97, 97, 52, + 13, 97, 14, 97, 97, 16, 65, 97, 97, 97, + + 60, 97, 97, 97, 97, 97, 53, 73, 61, 11, + 66, 6, 95, 10, 86, 45, 87, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 46, 97, 97, + 97, 97, 97, 90, 97, 91, 97, 97, 97, 88, + 97, 89, 97, 97, 97, 92, 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 1, 1, 1, 5, 6, 1, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 20, 20, 21, 21, 22, 23, 24, + 25, 26, 27, 1, 28, 28, 29, 30, 31, 28, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 33, 34, 32, 32, 32, 32, 35, 32, 32, + 36, 1, 37, 38, 32, 1, 39, 40, 41, 42, + + 43, 44, 45, 46, 47, 32, 48, 49, 50, 51, + 52, 53, 32, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[67] = + { 0, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3, 1, 4, 4, 4, 4, 4, 4, + 4, 1, 1, 1, 1, 1, 1, 5, 5, 5, + 4, 6, 6, 6, 6, 1, 1, 1, 5, 5, + 5, 5, 4, 5, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 1, 1, 1, 1 + } ; + +static yyconst flex_int16_t yy_base[455] = + { 0, + 0, 0, 64, 65, 74, 0, 649, 650, 650, 650, + 623, 44, 135, 650, 650, 622, 132, 650, 131, 129, + 144, 157, 148, 620, 650, 158, 620, 46, 650, 0, + 650, 650, 126, 99, 113, 145, 138, 138, 154, 592, + 160, 108, 591, 165, 163, 585, 156, 598, 175, 181, + 154, 177, 594, 650, 161, 650, 650, 650, 650, 625, + 650, 650, 0, 650, 650, 650, 650, 650, 650, 650, + 650, 650, 650, 228, 650, 0, 650, 235, 176, 226, + 264, 0, 227, 650, 650, 650, 613, 650, 650, 650, + 612, 0, 650, 650, 586, 579, 582, 590, 589, 576, + + 591, 578, 584, 572, 569, 582, 569, 566, 566, 572, + 560, 189, 565, 575, 561, 567, 570, 571, 0, 237, + 570, 179, 556, 569, 560, 562, 552, 566, 563, 565, + 548, 553, 550, 539, 221, 547, 552, 548, 550, 539, + 542, 217, 547, 539, 551, 214, 544, 650, 650, 650, + 0, 282, 0, 289, 306, 318, 325, 0, 650, 650, + 0, 536, 540, 549, 546, 530, 530, 212, 545, 542, + 542, 540, 537, 529, 535, 522, 533, 519, 535, 0, + 532, 520, 527, 524, 528, 521, 510, 509, 522, 525, + 522, 517, 508, 294, 513, 516, 507, 504, 508, 514, + + 505, 496, 499, 497, 507, 493, 491, 504, 490, 492, + 489, 500, 499, 221, 494, 489, 478, 311, 496, 498, + 487, 332, 339, 346, 353, 488, 0, 486, 358, 0, + 478, 476, 484, 473, 490, 479, 361, 0, 0, 473, + 483, 483, 0, 468, 364, 0, 0, 470, 367, 471, + 465, 464, 465, 464, 370, 0, 0, 0, 0, 0, + 460, 461, 466, 457, 470, 465, 464, 456, 460, 452, + 455, 459, 464, 450, 462, 453, 0, 0, 459, 448, + 448, 453, 452, 449, 0, 0, 0, 0, 439, 451, + 453, 0, 0, 0, 0, 0, 0, 441, 442, 436, + + 446, 0, 0, 0, 437, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 444, 0, 0, 442, 438, + 0, 0, 0, 434, 430, 435, 425, 438, 424, 437, + 426, 433, 0, 431, 433, 417, 419, 425, 431, 426, + 414, 0, 416, 0, 415, 418, 0, 407, 406, 406, + 419, 0, 421, 0, 420, 419, 404, 417, 404, 0, + 0, 407, 0, 0, 399, 0, 0, 0, 0, 0, + 396, 407, 400, 406, 403, 398, 390, 402, 0, 0, + 395, 402, 391, 0, 400, 397, 387, 374, 395, 0, + 0, 395, 0, 393, 392, 0, 0, 391, 377, 389, + + 0, 380, 400, 399, 398, 362, 0, 0, 0, 0, + 0, 0, 0, 0, 368, 254, 368, 360, 353, 355, + 351, 353, 352, 355, 352, 292, 278, 0, 275, 259, + 272, 240, 239, 243, 210, 0, 178, 187, 167, 0, + 184, 0, 177, 116, 103, 0, 650, 403, 407, 408, + 411, 417, 421, 422 + } ; + +static yyconst flex_int16_t yy_def[455] = + { 0, + 447, 1, 448, 448, 447, 5, 447, 447, 447, 447, + 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, + 447, 447, 449, 447, 447, 447, 447, 447, 447, 450, + 447, 447, 447, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 447, 447, 447, 447, 447, 447, 447, + 447, 447, 451, 447, 447, 447, 447, 447, 447, 447, + 447, 447, 447, 447, 447, 452, 447, 447, 22, 453, + 447, 454, 449, 447, 447, 447, 447, 447, 447, 447, + 447, 450, 447, 447, 450, 450, 450, 450, 450, 450, + + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 447, 447, 447, + 451, 447, 452, 447, 447, 447, 447, 454, 447, 447, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 447, 447, 447, 447, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 0, 447, 447, 447, + 447, 447, 447, 447 + } ; + +static yyconst flex_int16_t yy_nxt[717] = + { 0, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 23, 23, 23, 23, + 23, 24, 25, 26, 27, 28, 29, 30, 30, 30, + 30, 30, 30, 30, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 30, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 30, + 30, 30, 54, 55, 56, 57, 59, 59, 65, 66, + 90, 91, 60, 60, 8, 61, 62, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + + 8, 63, 63, 63, 63, 63, 63, 63, 63, 8, + 8, 8, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 8, 8, 8, 8, + 67, 70, 72, 74, 74, 74, 74, 74, 74, 74, + 93, 119, 75, 95, 96, 73, 71, 76, 120, 68, + 78, 446, 85, 94, 97, 121, 98, 445, 77, 78, + 99, 79, 79, 79, 79, 79, 79, 80, 81, 86, + 103, 87, 88, 100, 104, 148, 107, 81, 108, 105, + 81, 82, 110, 101, 128, 106, 102, 109, 116, 81, + + 111, 125, 112, 123, 142, 113, 117, 124, 143, 129, + 447, 114, 130, 132, 126, 144, 82, 118, 444, 145, + 133, 134, 443, 138, 149, 442, 139, 178, 146, 192, + 135, 136, 441, 137, 140, 447, 440, 193, 78, 78, + 179, 141, 74, 74, 74, 74, 74, 74, 74, 154, + 154, 154, 154, 154, 154, 154, 81, 81, 152, 206, + 219, 439, 220, 214, 280, 155, 232, 233, 81, 81, + 152, 215, 281, 156, 207, 156, 438, 155, 157, 157, + 157, 157, 157, 157, 157, 186, 420, 421, 187, 188, + 437, 222, 189, 222, 190, 436, 223, 223, 223, 223, + + 223, 223, 223, 154, 154, 154, 154, 154, 154, 154, + 258, 259, 260, 435, 434, 224, 433, 224, 432, 155, + 225, 225, 225, 225, 225, 225, 225, 285, 286, 287, + 431, 155, 157, 157, 157, 157, 157, 157, 157, 157, + 157, 157, 157, 157, 157, 157, 223, 223, 223, 223, + 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 293, 294, 295, 302, 303, 304, + 309, 310, 311, 313, 314, 315, 321, 322, 323, 403, + 404, 405, 430, 429, 428, 427, 426, 425, 424, 423, + + 422, 419, 406, 58, 58, 58, 58, 58, 58, 83, + 83, 92, 92, 92, 151, 151, 151, 153, 418, 153, + 153, 153, 153, 80, 80, 158, 158, 417, 416, 415, + 414, 413, 412, 411, 410, 409, 408, 407, 402, 401, + 400, 399, 398, 397, 396, 395, 394, 393, 392, 391, + 390, 389, 388, 387, 386, 385, 384, 383, 382, 381, + 380, 379, 378, 377, 376, 375, 374, 373, 372, 371, + 370, 369, 368, 367, 366, 365, 364, 363, 362, 361, + 360, 359, 358, 357, 356, 355, 354, 353, 352, 351, + 350, 349, 348, 347, 346, 345, 344, 343, 342, 341, + + 340, 339, 338, 337, 336, 335, 334, 333, 332, 331, + 330, 329, 328, 327, 326, 325, 324, 320, 319, 318, + 317, 316, 312, 308, 307, 306, 305, 301, 300, 299, + 298, 297, 296, 292, 291, 290, 289, 288, 284, 283, + 282, 279, 278, 277, 276, 275, 274, 273, 272, 271, + 270, 269, 268, 267, 266, 265, 264, 263, 262, 261, + 257, 256, 255, 254, 253, 252, 251, 250, 249, 248, + 247, 246, 245, 244, 243, 242, 241, 240, 239, 238, + 237, 236, 235, 234, 231, 230, 229, 228, 227, 226, + 221, 218, 217, 216, 213, 212, 211, 210, 209, 208, + + 205, 204, 203, 202, 201, 200, 199, 198, 197, 196, + 195, 194, 191, 185, 184, 183, 182, 181, 180, 177, + 176, 175, 174, 173, 172, 171, 170, 169, 168, 167, + 166, 165, 164, 163, 162, 161, 160, 159, 150, 147, + 131, 127, 122, 115, 89, 84, 69, 64, 447, 7, + 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, + 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, + 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, + 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, + 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, + + 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, + 447, 447, 447, 447, 447, 447 + } ; + +static yyconst flex_int16_t yy_chk[717] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 4, 12, 12, + 28, 28, 3, 4, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 13, 17, 19, 20, 20, 20, 20, 20, 20, 20, + 33, 42, 21, 34, 34, 19, 17, 21, 42, 13, + 23, 445, 26, 33, 35, 42, 35, 444, 21, 22, + 35, 22, 22, 22, 22, 22, 22, 22, 23, 26, + 37, 26, 26, 36, 37, 55, 38, 22, 38, 37, + 23, 22, 39, 36, 47, 37, 36, 38, 41, 22, + + 39, 45, 39, 44, 51, 39, 41, 44, 51, 47, + 79, 39, 47, 49, 45, 52, 22, 41, 443, 52, + 49, 49, 441, 50, 55, 439, 50, 112, 52, 122, + 49, 49, 438, 49, 50, 79, 437, 122, 80, 83, + 112, 50, 74, 74, 74, 74, 74, 74, 74, 78, + 78, 78, 78, 78, 78, 78, 80, 83, 74, 135, + 146, 435, 146, 142, 214, 78, 168, 168, 80, 83, + 74, 142, 214, 81, 135, 81, 434, 78, 81, 81, + 81, 81, 81, 81, 81, 120, 416, 416, 120, 120, + 433, 152, 120, 152, 120, 432, 152, 152, 152, 152, + + 152, 152, 152, 154, 154, 154, 154, 154, 154, 154, + 194, 194, 194, 431, 430, 155, 429, 155, 427, 154, + 155, 155, 155, 155, 155, 155, 155, 218, 218, 218, + 426, 154, 156, 156, 156, 156, 156, 156, 156, 157, + 157, 157, 157, 157, 157, 157, 222, 222, 222, 222, + 222, 222, 222, 223, 223, 223, 223, 223, 223, 223, + 224, 224, 224, 224, 224, 224, 224, 225, 225, 225, + 225, 225, 225, 225, 229, 229, 229, 237, 237, 237, + 245, 245, 245, 249, 249, 249, 255, 255, 255, 388, + 388, 388, 425, 424, 423, 422, 421, 420, 419, 418, + + 417, 415, 388, 448, 448, 448, 448, 448, 448, 449, + 449, 450, 450, 450, 451, 451, 451, 452, 406, 452, + 452, 452, 452, 453, 453, 454, 454, 405, 404, 403, + 402, 400, 399, 398, 395, 394, 392, 389, 387, 386, + 385, 383, 382, 381, 378, 377, 376, 375, 374, 373, + 372, 371, 365, 362, 359, 358, 357, 356, 355, 353, + 351, 350, 349, 348, 346, 345, 343, 341, 340, 339, + 338, 337, 336, 335, 334, 332, 331, 330, 329, 328, + 327, 326, 325, 324, 320, 319, 316, 305, 301, 300, + 299, 298, 291, 290, 289, 284, 283, 282, 281, 280, + + 279, 276, 275, 274, 273, 272, 271, 270, 269, 268, + 267, 266, 265, 264, 263, 262, 261, 254, 253, 252, + 251, 250, 248, 244, 242, 241, 240, 236, 235, 234, + 233, 232, 231, 228, 226, 221, 220, 219, 217, 216, + 215, 213, 212, 211, 210, 209, 208, 207, 206, 205, + 204, 203, 202, 201, 200, 199, 198, 197, 196, 195, + 193, 192, 191, 190, 189, 188, 187, 186, 185, 184, + 183, 182, 181, 179, 178, 177, 176, 175, 174, 173, + 172, 171, 170, 169, 167, 166, 165, 164, 163, 162, + 147, 145, 144, 143, 141, 140, 139, 138, 137, 136, + + 134, 133, 132, 131, 130, 129, 128, 127, 126, 125, + 124, 123, 121, 118, 117, 116, 115, 114, 113, 111, + 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, + 100, 99, 98, 97, 96, 95, 91, 87, 60, 53, + 48, 46, 43, 40, 27, 24, 16, 11, 7, 447, + 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, + 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, + 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, + 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, + 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, + + 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, + 447, 447, 447, 447, 447, 447 + } ; + +/* Table of booleans, true if rule could match eol. */ +static yyconst flex_int32_t yy_rule_can_match_eol[155] = + { 0, +0, 0, 0, 1, 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, 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, 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, + 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, }; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +/* +// +// Copyright (c) 2002-2012 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. +// + +This file contains the Lex specification for GLSL ES. +Based on ANSI C grammar, Lex specification: +http://www.lysator.liu.se/c/ANSI-C-grammar-l.html + +IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh, +WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp). +*/ + +#include "compiler/glslang.h" +#include "compiler/ParseHelper.h" +#include "compiler/preprocessor/Token.h" +#include "compiler/util.h" +#include "glslang_tab.h" + +/* windows only pragma */ +#ifdef _MSC_VER +#pragma warning(disable : 4102) +#endif + +#define YY_USER_ACTION yylval->lex.line = yylineno; +#define YY_INPUT(buf, result, max_size) \ + result = string_input(buf, max_size, yyscanner); + +static int string_input(char* buf, int max_size, yyscan_t yyscanner); +static int check_type(yyscan_t yyscanner); +static int reserved_word(yyscan_t yyscanner); + +#define INITIAL 0 +#define COMMENT 1 +#define FIELDS 2 + +#define YY_EXTRA_TYPE TParseContext* + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals (yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy (yyscan_t yyscanner ); + +int yyget_debug (yyscan_t yyscanner ); + +void yyset_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner ); + +void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *yyget_in (yyscan_t yyscanner ); + +void yyset_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *yyget_out (yyscan_t yyscanner ); + +void yyset_out (FILE * out_str ,yyscan_t yyscanner ); + +int yyget_leng (yyscan_t yyscanner ); + +char *yyget_text (yyscan_t yyscanner ); + +int yyget_lineno (yyscan_t yyscanner ); + +void yyset_lineno (int line_number ,yyscan_t yyscanner ); + +YYSTYPE * yyget_lval (yyscan_t yyscanner ); + +void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap (yyscan_t yyscanner ); +#else +extern int yywrap (yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (yyscan_t yyscanner ); +#else +static int input (yyscan_t yyscanner ); +#endif + +#endif + + static void yy_push_state (int new_state ,yyscan_t yyscanner); + + static void yy_pop_state (yyscan_t yyscanner ); + + static int yy_top_state (yyscan_t yyscanner ); + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex \ + (YYSTYPE * yylval_param ,yyscan_t yyscanner); + +#define YY_DECL int yylex \ + (YYSTYPE * yylval_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + TParseContext* context = yyextra; + + /* Single-line comments */ + + yylval = yylval_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + yy_load_buffer_state(yyscanner ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 448 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_current_state != 447 ); + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + + if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) + { + int yyl; + for ( yyl = 0; yyl < yyleng; ++yyl ) + if ( yytext[yyl] == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + } + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +; + YY_BREAK +/* Multi-line comments */ +case 2: +YY_RULE_SETUP +{ yy_push_state(COMMENT, yyscanner); } + YY_BREAK +case 3: +case 4: +/* rule 4 can match eol */ +YY_RULE_SETUP +; + YY_BREAK +case 5: +YY_RULE_SETUP +{ yy_pop_state(yyscanner); } + YY_BREAK +case 6: +YY_RULE_SETUP +{ return(INVARIANT); } + YY_BREAK +case 7: +YY_RULE_SETUP +{ return(HIGH_PRECISION); } + YY_BREAK +case 8: +YY_RULE_SETUP +{ return(MEDIUM_PRECISION); } + YY_BREAK +case 9: +YY_RULE_SETUP +{ return(LOW_PRECISION); } + YY_BREAK +case 10: +YY_RULE_SETUP +{ return(PRECISION); } + YY_BREAK +case 11: +YY_RULE_SETUP +{ return(ATTRIBUTE); } + YY_BREAK +case 12: +YY_RULE_SETUP +{ return(CONST_QUAL); } + YY_BREAK +case 13: +YY_RULE_SETUP +{ return(UNIFORM); } + YY_BREAK +case 14: +YY_RULE_SETUP +{ return(VARYING); } + YY_BREAK +case 15: +YY_RULE_SETUP +{ return(BREAK); } + YY_BREAK +case 16: +YY_RULE_SETUP +{ return(CONTINUE); } + YY_BREAK +case 17: +YY_RULE_SETUP +{ return(DO); } + YY_BREAK +case 18: +YY_RULE_SETUP +{ return(FOR); } + YY_BREAK +case 19: +YY_RULE_SETUP +{ return(WHILE); } + YY_BREAK +case 20: +YY_RULE_SETUP +{ return(IF); } + YY_BREAK +case 21: +YY_RULE_SETUP +{ return(ELSE); } + YY_BREAK +case 22: +YY_RULE_SETUP +{ return(IN_QUAL); } + YY_BREAK +case 23: +YY_RULE_SETUP +{ return(OUT_QUAL); } + YY_BREAK +case 24: +YY_RULE_SETUP +{ return(INOUT_QUAL); } + YY_BREAK +case 25: +YY_RULE_SETUP +{ context->lexAfterType = true; return(FLOAT_TYPE); } + YY_BREAK +case 26: +YY_RULE_SETUP +{ context->lexAfterType = true; return(INT_TYPE); } + YY_BREAK +case 27: +YY_RULE_SETUP +{ context->lexAfterType = true; return(VOID_TYPE); } + YY_BREAK +case 28: +YY_RULE_SETUP +{ context->lexAfterType = true; return(BOOL_TYPE); } + YY_BREAK +case 29: +YY_RULE_SETUP +{ yylval->lex.b = true; return(BOOLCONSTANT); } + YY_BREAK +case 30: +YY_RULE_SETUP +{ yylval->lex.b = false; return(BOOLCONSTANT); } + YY_BREAK +case 31: +YY_RULE_SETUP +{ return(DISCARD); } + YY_BREAK +case 32: +YY_RULE_SETUP +{ return(RETURN); } + YY_BREAK +case 33: +YY_RULE_SETUP +{ context->lexAfterType = true; return(MATRIX2); } + YY_BREAK +case 34: +YY_RULE_SETUP +{ context->lexAfterType = true; return(MATRIX3); } + YY_BREAK +case 35: +YY_RULE_SETUP +{ context->lexAfterType = true; return(MATRIX4); } + YY_BREAK +case 36: +YY_RULE_SETUP +{ context->lexAfterType = true; return (VEC2); } + YY_BREAK +case 37: +YY_RULE_SETUP +{ context->lexAfterType = true; return (VEC3); } + YY_BREAK +case 38: +YY_RULE_SETUP +{ context->lexAfterType = true; return (VEC4); } + YY_BREAK +case 39: +YY_RULE_SETUP +{ context->lexAfterType = true; return (IVEC2); } + YY_BREAK +case 40: +YY_RULE_SETUP +{ context->lexAfterType = true; return (IVEC3); } + YY_BREAK +case 41: +YY_RULE_SETUP +{ context->lexAfterType = true; return (IVEC4); } + YY_BREAK +case 42: +YY_RULE_SETUP +{ context->lexAfterType = true; return (BVEC2); } + YY_BREAK +case 43: +YY_RULE_SETUP +{ context->lexAfterType = true; return (BVEC3); } + YY_BREAK +case 44: +YY_RULE_SETUP +{ context->lexAfterType = true; return (BVEC4); } + YY_BREAK +case 45: +YY_RULE_SETUP +{ context->lexAfterType = true; return SAMPLER2D; } + YY_BREAK +case 46: +YY_RULE_SETUP +{ context->lexAfterType = true; return SAMPLERCUBE; } + YY_BREAK +case 47: +YY_RULE_SETUP +{ context->lexAfterType = true; return(STRUCT); } + YY_BREAK +case 48: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 49: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 50: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 51: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 52: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 53: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 54: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 55: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 56: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 57: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 58: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 59: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 60: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 61: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 62: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 63: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 64: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 65: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 66: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 67: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 68: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 69: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 70: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 71: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 72: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 73: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 74: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 75: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 76: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 77: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 78: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 79: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 80: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 81: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 82: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 83: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 84: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 85: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 86: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 87: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 88: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 89: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 90: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 91: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 92: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 93: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 94: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 95: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 96: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 97: +YY_RULE_SETUP +{ + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); +} + YY_BREAK +case 98: +YY_RULE_SETUP +{ yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } + YY_BREAK +case 99: +YY_RULE_SETUP +{ yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } + YY_BREAK +case 100: +YY_RULE_SETUP +{ context->error(yylineno, "Invalid Octal number.", yytext); context->recover(); return 0;} + YY_BREAK +case 101: +YY_RULE_SETUP +{ yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } + YY_BREAK +case 102: +YY_RULE_SETUP +{ yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); } + YY_BREAK +case 103: +YY_RULE_SETUP +{ yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); } + YY_BREAK +case 104: +YY_RULE_SETUP +{ yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); } + YY_BREAK +case 105: +YY_RULE_SETUP +{ return(ADD_ASSIGN); } + YY_BREAK +case 106: +YY_RULE_SETUP +{ return(SUB_ASSIGN); } + YY_BREAK +case 107: +YY_RULE_SETUP +{ return(MUL_ASSIGN); } + YY_BREAK +case 108: +YY_RULE_SETUP +{ return(DIV_ASSIGN); } + YY_BREAK +case 109: +YY_RULE_SETUP +{ return(MOD_ASSIGN); } + YY_BREAK +case 110: +YY_RULE_SETUP +{ return(LEFT_ASSIGN); } + YY_BREAK +case 111: +YY_RULE_SETUP +{ return(RIGHT_ASSIGN); } + YY_BREAK +case 112: +YY_RULE_SETUP +{ return(AND_ASSIGN); } + YY_BREAK +case 113: +YY_RULE_SETUP +{ return(XOR_ASSIGN); } + YY_BREAK +case 114: +YY_RULE_SETUP +{ return(OR_ASSIGN); } + YY_BREAK +case 115: +YY_RULE_SETUP +{ return(INC_OP); } + YY_BREAK +case 116: +YY_RULE_SETUP +{ return(DEC_OP); } + YY_BREAK +case 117: +YY_RULE_SETUP +{ return(AND_OP); } + YY_BREAK +case 118: +YY_RULE_SETUP +{ return(OR_OP); } + YY_BREAK +case 119: +YY_RULE_SETUP +{ return(XOR_OP); } + YY_BREAK +case 120: +YY_RULE_SETUP +{ return(LE_OP); } + YY_BREAK +case 121: +YY_RULE_SETUP +{ return(GE_OP); } + YY_BREAK +case 122: +YY_RULE_SETUP +{ return(EQ_OP); } + YY_BREAK +case 123: +YY_RULE_SETUP +{ return(NE_OP); } + YY_BREAK +case 124: +YY_RULE_SETUP +{ return(LEFT_OP); } + YY_BREAK +case 125: +YY_RULE_SETUP +{ return(RIGHT_OP); } + YY_BREAK +case 126: +YY_RULE_SETUP +{ context->lexAfterType = false; return(SEMICOLON); } + YY_BREAK +case 127: +YY_RULE_SETUP +{ context->lexAfterType = false; return(LEFT_BRACE); } + YY_BREAK +case 128: +YY_RULE_SETUP +{ return(RIGHT_BRACE); } + YY_BREAK +case 129: +YY_RULE_SETUP +{ if (context->inTypeParen) context->lexAfterType = false; return(COMMA); } + YY_BREAK +case 130: +YY_RULE_SETUP +{ return(COLON); } + YY_BREAK +case 131: +YY_RULE_SETUP +{ context->lexAfterType = false; return(EQUAL); } + YY_BREAK +case 132: +YY_RULE_SETUP +{ context->lexAfterType = false; context->inTypeParen = true; return(LEFT_PAREN); } + YY_BREAK +case 133: +YY_RULE_SETUP +{ context->inTypeParen = false; return(RIGHT_PAREN); } + YY_BREAK +case 134: +YY_RULE_SETUP +{ return(LEFT_BRACKET); } + YY_BREAK +case 135: +YY_RULE_SETUP +{ return(RIGHT_BRACKET); } + YY_BREAK +case 136: +YY_RULE_SETUP +{ BEGIN(FIELDS); return(DOT); } + YY_BREAK +case 137: +YY_RULE_SETUP +{ return(BANG); } + YY_BREAK +case 138: +YY_RULE_SETUP +{ return(DASH); } + YY_BREAK +case 139: +YY_RULE_SETUP +{ return(TILDE); } + YY_BREAK +case 140: +YY_RULE_SETUP +{ return(PLUS); } + YY_BREAK +case 141: +YY_RULE_SETUP +{ return(STAR); } + YY_BREAK +case 142: +YY_RULE_SETUP +{ return(SLASH); } + YY_BREAK +case 143: +YY_RULE_SETUP +{ return(PERCENT); } + YY_BREAK +case 144: +YY_RULE_SETUP +{ return(LEFT_ANGLE); } + YY_BREAK +case 145: +YY_RULE_SETUP +{ return(RIGHT_ANGLE); } + YY_BREAK +case 146: +YY_RULE_SETUP +{ return(VERTICAL_BAR); } + YY_BREAK +case 147: +YY_RULE_SETUP +{ return(CARET); } + YY_BREAK +case 148: +YY_RULE_SETUP +{ return(AMPERSAND); } + YY_BREAK +case 149: +YY_RULE_SETUP +{ return(QUESTION); } + YY_BREAK +case 150: +YY_RULE_SETUP +{ + BEGIN(INITIAL); + yylval->lex.string = NewPoolTString(yytext); + return FIELD_SELECTION; +} + YY_BREAK +case 151: +YY_RULE_SETUP +{} + YY_BREAK +case 152: +/* rule 152 can match eol */ +YY_RULE_SETUP +{ } + YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(COMMENT): +case YY_STATE_EOF(FIELDS): +{ context->AfterEOF = true; yyterminate(); } + YY_BREAK +case 153: +YY_RULE_SETUP +{ context->warning(yylineno, "Unknown char", yytext, ""); return 0; } + YY_BREAK +case 154: +YY_RULE_SETUP +ECHO; + YY_BREAK + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( yywrap(yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = yyg->yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart(yyin ,yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 448 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + register int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + register char *yy_cp = yyg->yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 448 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 447); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart(yyin ,yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap(yyscanner ) ) + return EOF; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + if ( c == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); + yy_load_buffer_state(yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state(yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ,yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer(b,file ,yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree((void *) b->yy_ch_buf ,yyscanner ); + + yyfree((void *) b ,yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer(b ,yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state(yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (yyscan_t yyscanner) +{ + int num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer(b ,yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) +{ + + return yy_scan_bytes(yystr,strlen(yystr) ,yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) yyalloc(n ,yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer(buf,n ,yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + + static void yy_push_state (int new_state , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( yyg->yy_start_stack_ptr >= yyg->yy_start_stack_depth ) + { + yy_size_t new_size; + + yyg->yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yyg->yy_start_stack_depth * sizeof( int ); + + if ( ! yyg->yy_start_stack ) + yyg->yy_start_stack = (int *) yyalloc(new_size ,yyscanner ); + + else + yyg->yy_start_stack = (int *) yyrealloc((void *) yyg->yy_start_stack,new_size ,yyscanner ); + + if ( ! yyg->yy_start_stack ) + YY_FATAL_ERROR( "out of memory expanding start-condition stack" ); + } + + yyg->yy_start_stack[yyg->yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); +} + + static void yy_pop_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( --yyg->yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yyg->yy_start_stack[yyg->yy_start_stack_ptr]); +} + + static int yy_top_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyg->yy_start_stack[yyg->yy_start_stack_ptr - 1]; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param line_number + * @param yyscanner The scanner object. + */ +void yyset_lineno (int line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "yyset_lineno called with no buffer" , yyscanner); + + yylineno = line_number; +} + +/** Set the current column. + * @param line_number + * @param yyscanner The scanner object. + */ +void yyset_column (int column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "yyset_column called with no buffer" , yyscanner); + + yycolumn = column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = in_str ; +} + +void yyset_out (FILE * out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = out_str ; +} + +int yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void yyset_debug (int bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * yyget_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ + +int yylex_init(yyscan_t* ptr_yy_globals) + +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ + +int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) + +{ + struct yyguts_t dummy_yyguts; + + yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = 0; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = (char *) 0; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack ,yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + yyfree(yyg->yy_start_stack ,yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + return (void *) malloc( size ); +} + +void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void yyfree (void * ptr , yyscan_t yyscanner) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +int string_input(char* buf, int max_size, yyscan_t yyscanner) +{ + int len = 0; + + pp::Token token; + yyget_extra(yyscanner)->preprocessor.lex(&token); + len = token.type == pp::Token::LAST ? 0 : token.text.size(); + if ((len > 0) && (len < max_size)) + memcpy(buf, token.text.c_str(), len); + yyset_lineno(EncodeSourceLoc(token.location.file, token.location.line),yyscanner); + + if (len >= max_size) + YY_FATAL_ERROR("Input buffer overflow"); + else if (len > 0) + buf[len++] = ' '; + return len; +} + +int check_type(yyscan_t yyscanner) { + struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; + + int token = IDENTIFIER; + TSymbol* symbol = yyextra->symbolTable.find(yytext); + if (yyextra->lexAfterType == false && symbol && symbol->isVariable()) { + TVariable* variable = static_cast<TVariable*>(symbol); + if (variable->isUserType()) { + yyextra->lexAfterType = true; + token = TYPE_NAME; + } + } + yylval->lex.symbol = symbol; + return token; +} + +int reserved_word(yyscan_t yyscanner) { + struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; + + yyextra->error(yylineno, "Illegal use of reserved word", yytext, ""); + yyextra->recover(); + return 0; +} + +void yyerror(TParseContext* context, const char* reason) { + struct yyguts_t* yyg = (struct yyguts_t*) context->scanner; + + if (context->AfterEOF) { + context->error(yylineno, reason, "unexpected EOF"); + } else { + context->error(yylineno, reason, yytext); + } + context->recover(); +} + +int glslang_initialize(TParseContext* context) { + yyscan_t scanner = NULL; + if (yylex_init_extra(context,&scanner)) + return 1; + + context->scanner = scanner; + return 0; +} + +int glslang_finalize(TParseContext* context) { + yyscan_t scanner = context->scanner; + if (scanner == NULL) return 0; + + context->scanner = NULL; + yylex_destroy(scanner); + + return 0; +} + +int glslang_scan(int count, const char* const string[], const int length[], + TParseContext* context) { + yyrestart(NULL,context->scanner); + yyset_lineno(EncodeSourceLoc(0, 1),context->scanner); + context->AfterEOF = false; + + // Initialize preprocessor. + if (!context->preprocessor.init(count, string, length)) + return 1; + + // Define extension macros. + const TExtensionBehavior& extBehavior = context->extensionBehavior(); + for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); + iter != extBehavior.end(); ++iter) + { + context->preprocessor.predefineMacro(iter->first.c_str(), 1); + } + return 0; +} +
diff --git a/src/GLES2/compiler/glslang_tab.cpp b/src/GLES2/compiler/glslang_tab.cpp new file mode 100644 index 0000000..3784c5e --- /dev/null +++ b/src/GLES2/compiler/glslang_tab.cpp
@@ -0,0 +1,4714 @@ +/* A Bison parser, made by GNU Bison 2.4.2. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2006, 2009-2010 Free Software + Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.4.2" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Copy the first part of user declarations. */ + + +// +// Copyright (c) 2002-2012 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. +// + +// This file is auto-generated by generate_parser.sh. DO NOT EDIT! + +// Ignore errors in auto-generated code. +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wswitch-enum" +#elif defined(_MSC_VER) +#pragma warning(disable: 4065) +#pragma warning(disable: 4189) +#pragma warning(disable: 4505) +#pragma warning(disable: 4701) +#endif + +#include "compiler/SymbolTable.h" +#include "compiler/ParseHelper.h" +#include "GLSLANG/ShaderLang.h" + +#define YYLEX_PARAM context->scanner + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + INVARIANT = 258, + HIGH_PRECISION = 259, + MEDIUM_PRECISION = 260, + LOW_PRECISION = 261, + PRECISION = 262, + ATTRIBUTE = 263, + CONST_QUAL = 264, + BOOL_TYPE = 265, + FLOAT_TYPE = 266, + INT_TYPE = 267, + BREAK = 268, + CONTINUE = 269, + DO = 270, + ELSE = 271, + FOR = 272, + IF = 273, + DISCARD = 274, + RETURN = 275, + BVEC2 = 276, + BVEC3 = 277, + BVEC4 = 278, + IVEC2 = 279, + IVEC3 = 280, + IVEC4 = 281, + VEC2 = 282, + VEC3 = 283, + VEC4 = 284, + MATRIX2 = 285, + MATRIX3 = 286, + MATRIX4 = 287, + IN_QUAL = 288, + OUT_QUAL = 289, + INOUT_QUAL = 290, + UNIFORM = 291, + VARYING = 292, + STRUCT = 293, + VOID_TYPE = 294, + WHILE = 295, + SAMPLER2D = 296, + SAMPLERCUBE = 297, + IDENTIFIER = 298, + TYPE_NAME = 299, + FLOATCONSTANT = 300, + INTCONSTANT = 301, + BOOLCONSTANT = 302, + FIELD_SELECTION = 303, + LEFT_OP = 304, + RIGHT_OP = 305, + INC_OP = 306, + DEC_OP = 307, + LE_OP = 308, + GE_OP = 309, + EQ_OP = 310, + NE_OP = 311, + AND_OP = 312, + OR_OP = 313, + XOR_OP = 314, + MUL_ASSIGN = 315, + DIV_ASSIGN = 316, + ADD_ASSIGN = 317, + MOD_ASSIGN = 318, + LEFT_ASSIGN = 319, + RIGHT_ASSIGN = 320, + AND_ASSIGN = 321, + XOR_ASSIGN = 322, + OR_ASSIGN = 323, + SUB_ASSIGN = 324, + LEFT_PAREN = 325, + RIGHT_PAREN = 326, + LEFT_BRACKET = 327, + RIGHT_BRACKET = 328, + LEFT_BRACE = 329, + RIGHT_BRACE = 330, + DOT = 331, + COMMA = 332, + COLON = 333, + EQUAL = 334, + SEMICOLON = 335, + BANG = 336, + DASH = 337, + TILDE = 338, + PLUS = 339, + STAR = 340, + SLASH = 341, + PERCENT = 342, + LEFT_ANGLE = 343, + RIGHT_ANGLE = 344, + VERTICAL_BAR = 345, + CARET = 346, + AMPERSAND = 347, + QUESTION = 348 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + + + struct { + TSourceLoc line; + union { + TString *string; + float f; + int i; + bool b; + }; + TSymbol* symbol; + } lex; + struct { + TSourceLoc line; + TOperator op; + union { + TIntermNode* intermNode; + TIntermNodePair nodePair; + TIntermTyped* intermTypedNode; + TIntermAggregate* intermAggregate; + }; + union { + TPublicType type; + TPrecision precision; + TQualifier qualifier; + TFunction* function; + TParameter param; + TTypeLine typeLine; + TTypeList* typeList; + }; + } interm; + + + +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + +/* Copy the second part of user declarations. */ + + +extern int yylex(YYSTYPE* yylval_param, void* yyscanner); +extern void yyerror(TParseContext* context, const char* reason); + +#define FRAG_VERT_ONLY(S, L) { \ + if (context->shaderType != SH_FRAGMENT_SHADER && \ + context->shaderType != SH_VERTEX_SHADER) { \ + context->error(L, " supported in vertex/fragment shaders only ", S); \ + context->recover(); \ + } \ +} + +#define VERTEX_ONLY(S, L) { \ + if (context->shaderType != SH_VERTEX_SHADER) { \ + context->error(L, " supported in vertex shaders only ", S); \ + context->recover(); \ + } \ +} + +#define FRAG_ONLY(S, L) { \ + if (context->shaderType != SH_FRAGMENT_SHADER) { \ + context->error(L, " supported in fragment shaders only ", S); \ + context->recover(); \ + } \ +} + + + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 69 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 1385 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 94 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 83 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 199 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 302 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 348 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 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, 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, 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, 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, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 5, 7, 9, 11, 13, 17, 19, + 24, 26, 30, 33, 36, 38, 40, 42, 46, 49, + 52, 55, 57, 60, 64, 67, 69, 71, 73, 75, + 78, 81, 84, 86, 88, 90, 92, 96, 100, 102, + 106, 110, 112, 114, 118, 122, 126, 130, 132, 136, + 140, 142, 144, 146, 148, 152, 154, 158, 160, 164, + 166, 172, 174, 178, 180, 182, 184, 186, 188, 190, + 194, 196, 199, 202, 207, 210, 212, 214, 217, 221, + 225, 228, 234, 238, 241, 245, 248, 249, 251, 253, + 255, 257, 259, 263, 269, 276, 282, 284, 287, 292, + 298, 303, 306, 308, 311, 313, 315, 317, 320, 322, + 324, 327, 329, 331, 333, 335, 340, 342, 344, 346, + 348, 350, 352, 354, 356, 358, 360, 362, 364, 366, + 368, 370, 372, 374, 376, 378, 380, 381, 388, 389, + 395, 397, 400, 404, 406, 410, 412, 417, 419, 421, + 423, 425, 427, 429, 431, 433, 435, 438, 439, 440, + 446, 448, 450, 451, 454, 455, 458, 461, 465, 467, + 470, 472, 475, 481, 485, 487, 489, 494, 495, 502, + 503, 512, 513, 521, 523, 525, 527, 528, 531, 535, + 538, 541, 544, 548, 551, 553, 556, 558, 560, 561 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int16 yyrhs[] = +{ + 173, 0, -1, 43, -1, 95, -1, 46, -1, 45, + -1, 47, -1, 70, 122, 71, -1, 96, -1, 97, + 72, 98, 73, -1, 99, -1, 97, 76, 48, -1, + 97, 51, -1, 97, 52, -1, 122, -1, 100, -1, + 101, -1, 97, 76, 101, -1, 103, 71, -1, 102, + 71, -1, 104, 39, -1, 104, -1, 104, 120, -1, + 103, 77, 120, -1, 105, 70, -1, 140, -1, 43, + -1, 48, -1, 97, -1, 51, 106, -1, 52, 106, + -1, 107, 106, -1, 84, -1, 82, -1, 81, -1, + 106, -1, 108, 85, 106, -1, 108, 86, 106, -1, + 108, -1, 109, 84, 108, -1, 109, 82, 108, -1, + 109, -1, 110, -1, 111, 88, 110, -1, 111, 89, + 110, -1, 111, 53, 110, -1, 111, 54, 110, -1, + 111, -1, 112, 55, 111, -1, 112, 56, 111, -1, + 112, -1, 113, -1, 114, -1, 115, -1, 116, 57, + 115, -1, 116, -1, 117, 59, 116, -1, 117, -1, + 118, 58, 117, -1, 118, -1, 118, 93, 122, 78, + 120, -1, 119, -1, 106, 121, 120, -1, 79, -1, + 60, -1, 61, -1, 62, -1, 69, -1, 120, -1, + 122, 77, 120, -1, 119, -1, 125, 80, -1, 133, + 80, -1, 7, 138, 139, 80, -1, 126, 71, -1, + 128, -1, 127, -1, 128, 130, -1, 127, 77, 130, + -1, 135, 43, 70, -1, 137, 43, -1, 137, 43, + 72, 123, 73, -1, 136, 131, 129, -1, 131, 129, + -1, 136, 131, 132, -1, 131, 132, -1, -1, 33, + -1, 34, -1, 35, -1, 137, -1, 134, -1, 133, + 77, 43, -1, 133, 77, 43, 72, 73, -1, 133, + 77, 43, 72, 123, 73, -1, 133, 77, 43, 79, + 148, -1, 135, -1, 135, 43, -1, 135, 43, 72, + 73, -1, 135, 43, 72, 123, 73, -1, 135, 43, + 79, 148, -1, 3, 43, -1, 137, -1, 136, 137, + -1, 9, -1, 8, -1, 37, -1, 3, 37, -1, + 36, -1, 139, -1, 138, 139, -1, 4, -1, 5, + -1, 6, -1, 140, -1, 140, 72, 123, 73, -1, + 39, -1, 11, -1, 12, -1, 10, -1, 27, -1, + 28, -1, 29, -1, 21, -1, 22, -1, 23, -1, + 24, -1, 25, -1, 26, -1, 30, -1, 31, -1, + 32, -1, 41, -1, 42, -1, 141, -1, 44, -1, + -1, 38, 43, 74, 142, 144, 75, -1, -1, 38, + 74, 143, 144, 75, -1, 145, -1, 144, 145, -1, + 137, 146, 80, -1, 147, -1, 146, 77, 147, -1, + 43, -1, 43, 72, 123, 73, -1, 120, -1, 124, + -1, 152, -1, 151, -1, 149, -1, 161, -1, 162, + -1, 165, -1, 172, -1, 74, 75, -1, -1, -1, + 74, 153, 160, 154, 75, -1, 159, -1, 151, -1, + -1, 157, 159, -1, -1, 158, 151, -1, 74, 75, + -1, 74, 160, 75, -1, 150, -1, 160, 150, -1, + 80, -1, 122, 80, -1, 18, 70, 122, 71, 163, + -1, 156, 16, 156, -1, 156, -1, 122, -1, 135, + 43, 79, 148, -1, -1, 40, 70, 166, 164, 71, + 155, -1, -1, 15, 167, 156, 40, 70, 122, 71, + 80, -1, -1, 17, 70, 168, 169, 171, 71, 155, + -1, 161, -1, 149, -1, 164, -1, -1, 170, 80, + -1, 170, 80, 122, -1, 14, 80, -1, 13, 80, + -1, 20, 80, -1, 20, 122, 80, -1, 19, 80, + -1, 174, -1, 173, 174, -1, 175, -1, 124, -1, + -1, 125, 176, 159, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 165, 165, 200, 203, 216, 221, 226, 232, 235, + 314, 317, 418, 428, 441, 449, 549, 552, 560, 564, + 571, 575, 582, 588, 597, 605, 660, 667, 677, 680, + 690, 700, 721, 722, 723, 728, 729, 738, 750, 751, + 759, 770, 774, 775, 785, 795, 805, 818, 819, 829, + 842, 846, 850, 854, 855, 868, 869, 882, 883, 896, + 897, 914, 915, 928, 929, 930, 931, 932, 936, 939, + 950, 958, 985, 990, 997, 1035, 1038, 1045, 1053, 1074, + 1095, 1106, 1135, 1140, 1150, 1155, 1165, 1168, 1171, 1174, + 1180, 1187, 1190, 1212, 1230, 1254, 1277, 1281, 1299, 1307, + 1339, 1359, 1448, 1457, 1480, 1483, 1489, 1497, 1505, 1513, + 1523, 1530, 1533, 1536, 1542, 1545, 1560, 1564, 1568, 1572, + 1581, 1586, 1591, 1596, 1601, 1606, 1611, 1616, 1621, 1626, + 1632, 1638, 1644, 1649, 1654, 1659, 1672, 1672, 1686, 1686, + 1695, 1698, 1713, 1749, 1753, 1759, 1767, 1783, 1787, 1791, + 1792, 1798, 1799, 1800, 1801, 1802, 1806, 1807, 1807, 1807, + 1817, 1818, 1822, 1822, 1823, 1823, 1828, 1831, 1841, 1844, + 1850, 1851, 1855, 1863, 1867, 1877, 1882, 1899, 1899, 1904, + 1904, 1911, 1911, 1919, 1922, 1928, 1931, 1937, 1941, 1948, + 1955, 1962, 1969, 1980, 1989, 1993, 2000, 2003, 2009, 2009 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "INVARIANT", "HIGH_PRECISION", + "MEDIUM_PRECISION", "LOW_PRECISION", "PRECISION", "ATTRIBUTE", + "CONST_QUAL", "BOOL_TYPE", "FLOAT_TYPE", "INT_TYPE", "BREAK", "CONTINUE", + "DO", "ELSE", "FOR", "IF", "DISCARD", "RETURN", "BVEC2", "BVEC3", + "BVEC4", "IVEC2", "IVEC3", "IVEC4", "VEC2", "VEC3", "VEC4", "MATRIX2", + "MATRIX3", "MATRIX4", "IN_QUAL", "OUT_QUAL", "INOUT_QUAL", "UNIFORM", + "VARYING", "STRUCT", "VOID_TYPE", "WHILE", "SAMPLER2D", "SAMPLERCUBE", + "IDENTIFIER", "TYPE_NAME", "FLOATCONSTANT", "INTCONSTANT", + "BOOLCONSTANT", "FIELD_SELECTION", "LEFT_OP", "RIGHT_OP", "INC_OP", + "DEC_OP", "LE_OP", "GE_OP", "EQ_OP", "NE_OP", "AND_OP", "OR_OP", + "XOR_OP", "MUL_ASSIGN", "DIV_ASSIGN", "ADD_ASSIGN", "MOD_ASSIGN", + "LEFT_ASSIGN", "RIGHT_ASSIGN", "AND_ASSIGN", "XOR_ASSIGN", "OR_ASSIGN", + "SUB_ASSIGN", "LEFT_PAREN", "RIGHT_PAREN", "LEFT_BRACKET", + "RIGHT_BRACKET", "LEFT_BRACE", "RIGHT_BRACE", "DOT", "COMMA", "COLON", + "EQUAL", "SEMICOLON", "BANG", "DASH", "TILDE", "PLUS", "STAR", "SLASH", + "PERCENT", "LEFT_ANGLE", "RIGHT_ANGLE", "VERTICAL_BAR", "CARET", + "AMPERSAND", "QUESTION", "$accept", "variable_identifier", + "primary_expression", "postfix_expression", "integer_expression", + "function_call", "function_call_or_method", "function_call_generic", + "function_call_header_no_parameters", + "function_call_header_with_parameters", "function_call_header", + "function_identifier", "unary_expression", "unary_operator", + "multiplicative_expression", "additive_expression", "shift_expression", + "relational_expression", "equality_expression", "and_expression", + "exclusive_or_expression", "inclusive_or_expression", + "logical_and_expression", "logical_xor_expression", + "logical_or_expression", "conditional_expression", + "assignment_expression", "assignment_operator", "expression", + "constant_expression", "declaration", "function_prototype", + "function_declarator", "function_header_with_parameters", + "function_header", "parameter_declarator", "parameter_declaration", + "parameter_qualifier", "parameter_type_specifier", + "init_declarator_list", "single_declaration", "fully_specified_type", + "type_qualifier", "type_specifier", "precision_qualifier", + "type_specifier_no_prec", "type_specifier_nonarray", "struct_specifier", + "$@1", "$@2", "struct_declaration_list", "struct_declaration", + "struct_declarator_list", "struct_declarator", "initializer", + "declaration_statement", "statement", "simple_statement", + "compound_statement", "$@3", "$@4", "statement_no_new_scope", + "statement_with_scope", "$@5", "$@6", "compound_statement_no_new_scope", + "statement_list", "expression_statement", "selection_statement", + "selection_rest_statement", "condition", "iteration_statement", "$@7", + "$@8", "$@9", "for_init_statement", "conditionopt", "for_rest_statement", + "jump_statement", "translation_unit", "external_declaration", + "function_definition", "$@10", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, 347, 348 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 94, 95, 96, 96, 96, 96, 96, 97, 97, + 97, 97, 97, 97, 98, 99, 100, 100, 101, 101, + 102, 102, 103, 103, 104, 105, 105, 105, 106, 106, + 106, 106, 107, 107, 107, 108, 108, 108, 109, 109, + 109, 110, 111, 111, 111, 111, 111, 112, 112, 112, + 113, 114, 115, 116, 116, 117, 117, 118, 118, 119, + 119, 120, 120, 121, 121, 121, 121, 121, 122, 122, + 123, 124, 124, 124, 125, 126, 126, 127, 127, 128, + 129, 129, 130, 130, 130, 130, 131, 131, 131, 131, + 132, 133, 133, 133, 133, 133, 134, 134, 134, 134, + 134, 134, 135, 135, 136, 136, 136, 136, 136, 137, + 137, 138, 138, 138, 139, 139, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 142, 141, 143, 141, + 144, 144, 145, 146, 146, 147, 147, 148, 149, 150, + 150, 151, 151, 151, 151, 151, 152, 153, 154, 152, + 155, 155, 157, 156, 158, 156, 159, 159, 160, 160, + 161, 161, 162, 163, 163, 164, 164, 166, 165, 167, + 165, 168, 165, 169, 169, 170, 170, 171, 171, 172, + 172, 172, 172, 172, 173, 173, 174, 174, 176, 175 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 1, 1, 1, 1, 3, 1, 4, + 1, 3, 2, 2, 1, 1, 1, 3, 2, 2, + 2, 1, 2, 3, 2, 1, 1, 1, 1, 2, + 2, 2, 1, 1, 1, 1, 3, 3, 1, 3, + 3, 1, 1, 3, 3, 3, 3, 1, 3, 3, + 1, 1, 1, 1, 3, 1, 3, 1, 3, 1, + 5, 1, 3, 1, 1, 1, 1, 1, 1, 3, + 1, 2, 2, 4, 2, 1, 1, 2, 3, 3, + 2, 5, 3, 2, 3, 2, 0, 1, 1, 1, + 1, 1, 3, 5, 6, 5, 1, 2, 4, 5, + 4, 2, 1, 2, 1, 1, 1, 2, 1, 1, + 2, 1, 1, 1, 1, 4, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 6, 0, 5, + 1, 2, 3, 1, 3, 1, 4, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2, 0, 0, 5, + 1, 1, 0, 2, 0, 2, 2, 3, 1, 2, + 1, 2, 5, 3, 1, 1, 4, 0, 6, 0, + 8, 0, 7, 1, 1, 1, 0, 2, 3, 2, + 2, 2, 3, 2, 1, 2, 1, 1, 0, 3 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 0, 0, 111, 112, 113, 0, 105, 104, 119, 117, + 118, 123, 124, 125, 126, 127, 128, 120, 121, 122, + 129, 130, 131, 108, 106, 0, 116, 132, 133, 135, + 197, 198, 0, 76, 86, 0, 91, 96, 0, 102, + 0, 109, 114, 134, 0, 194, 196, 107, 101, 0, + 0, 138, 71, 0, 74, 86, 0, 87, 88, 89, + 77, 0, 86, 0, 72, 97, 103, 110, 0, 1, + 195, 0, 136, 0, 0, 199, 78, 83, 85, 90, + 0, 92, 79, 0, 0, 2, 5, 4, 6, 27, + 0, 0, 0, 34, 33, 32, 3, 8, 28, 10, + 15, 16, 0, 0, 21, 0, 35, 0, 38, 41, + 42, 47, 50, 51, 52, 53, 55, 57, 59, 70, + 0, 25, 73, 0, 0, 0, 140, 0, 0, 179, + 0, 0, 0, 0, 0, 157, 166, 170, 35, 61, + 68, 0, 148, 0, 114, 151, 168, 150, 149, 0, + 152, 153, 154, 155, 80, 82, 84, 0, 0, 98, + 0, 147, 100, 29, 30, 0, 12, 13, 0, 0, + 19, 18, 0, 20, 22, 24, 31, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 115, 0, 145, 0, 143, 139, 141, 190, 189, + 164, 181, 0, 193, 191, 0, 177, 156, 0, 64, + 65, 66, 67, 63, 0, 0, 171, 167, 169, 0, + 93, 0, 95, 99, 7, 0, 14, 26, 11, 17, + 23, 36, 37, 40, 39, 45, 46, 43, 44, 48, + 49, 54, 56, 58, 0, 137, 0, 0, 142, 0, + 0, 0, 0, 0, 192, 0, 158, 62, 69, 0, + 94, 9, 0, 0, 144, 0, 163, 165, 184, 183, + 186, 164, 175, 0, 0, 0, 81, 60, 146, 0, + 185, 0, 0, 174, 172, 0, 0, 159, 0, 187, + 0, 164, 0, 161, 178, 160, 0, 188, 182, 173, + 176, 180 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 96, 97, 98, 225, 99, 100, 101, 102, 103, + 104, 105, 138, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 139, 140, 214, 141, 120, + 142, 143, 32, 33, 34, 77, 60, 61, 78, 35, + 36, 37, 38, 39, 40, 41, 121, 43, 123, 73, + 125, 126, 194, 195, 162, 145, 146, 147, 148, 208, + 275, 294, 249, 250, 251, 295, 149, 150, 151, 284, + 274, 152, 255, 200, 252, 270, 281, 282, 153, 44, + 45, 46, 53 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -260 +static const yytype_int16 yypact[] = +{ + 1241, -23, -260, -260, -260, 152, -260, -260, -260, -260, + -260, -260, -260, -260, -260, -260, -260, -260, -260, -260, + -260, -260, -260, -260, -260, -32, -260, -260, -260, -260, + -260, -18, -35, 17, 82, 29, -260, 26, 1282, -260, + 1341, -260, 11, -260, 1199, -260, -260, -260, -260, 1341, + 28, -260, -260, 36, -260, 62, 67, -260, -260, -260, + -260, 1282, 126, 79, -260, 7, -260, -260, 972, -260, + -260, 40, -260, 1282, 288, -260, -260, -260, -260, 87, + 1282, -13, -260, 193, 972, 80, -260, -260, -260, -260, + 972, 972, 972, -260, -260, -260, -260, -260, 16, -260, + -260, -260, 81, -40, 1036, 84, -260, 972, 77, -67, + -260, -31, 111, -260, -260, -260, 107, 115, -29, -260, + 103, -260, -260, 1282, 138, 1103, -260, 104, 105, -260, + 113, 116, 108, 844, 117, 118, -260, -260, -34, -260, + -260, 31, -260, -18, -16, -260, -260, -260, -260, 370, + -260, -260, -260, -260, 119, -260, -260, 908, 972, -260, + 121, -260, -260, -260, -260, 5, -260, -260, 972, 1306, + -260, -260, 972, 120, -260, -260, -260, 972, 972, 972, + 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, + 972, -260, 1144, 123, 44, -260, -260, -260, -260, -260, + 122, -260, 972, -260, -260, 71, -260, -260, 452, -260, + -260, -260, -260, -260, 972, 972, -260, -260, -260, 972, + -260, 124, -260, -260, -260, 125, 129, -260, 131, -260, + -260, -260, -260, 77, 77, -260, -260, -260, -260, -31, + -31, -260, 107, 115, 91, -260, 972, 138, -260, 167, + 36, 616, 698, 10, -260, 780, 452, -260, -260, 137, + -260, -260, 972, 139, -260, 141, -260, -260, -260, -260, + 780, 122, 129, 170, 155, 153, -260, -260, -260, 972, + -260, 147, 158, 214, -260, 154, 534, -260, 30, 972, + 534, 122, 972, -260, -260, -260, 162, 129, -260, -260, + -260, -260 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -260, -260, -260, -260, -260, -260, -260, 74, -260, -260, + -260, -260, -44, -260, -9, -260, -55, -8, -260, -260, + -260, 59, 60, 58, -260, -64, -83, -260, -90, -73, + 6, 8, -260, -260, -260, 169, 195, 191, 174, -260, + -260, -222, -25, -20, 252, -15, 0, -260, -260, -260, + 135, -120, -260, 12, -145, 9, -142, -235, -260, -260, + -260, -30, -259, -260, -260, -50, 54, 13, -260, -260, + -6, -260, -260, -260, -260, -260, -260, -260, -260, -260, + 223, -260, -260 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -163 +static const yytype_int16 yytable[] = +{ + 42, 161, 165, 75, 119, 197, 30, 218, 31, 62, + 160, 50, 283, 222, 47, 179, 267, 180, 66, 119, + 48, 174, 181, 182, 106, 67, 209, 210, 211, 189, + 62, 171, 299, 273, 71, 212, 54, 172, 42, 106, + 42, 79, 51, 205, 42, 213, 163, 164, 273, 42, + 30, 293, 31, 124, -25, 293, 68, 183, 184, 157, + 79, 42, 52, 176, 190, 56, 158, 166, 167, 65, + 6, 7, 197, 42, 144, 161, 224, 82, 226, 83, + 42, 271, 215, 68, 221, 56, 84, 215, 168, 230, + 6, 7, 169, 119, 55, 57, 58, 59, 23, 24, + 244, 296, 72, 124, 47, 124, 63, 215, 215, 64, + 74, 216, 253, 106, 218, 57, 58, 59, 23, 24, + 122, 247, 81, 42, 248, 42, 235, 236, 237, 238, + 154, 257, 258, 231, 232, 106, 106, 106, 106, 106, + 106, 106, 106, 106, 106, 106, 259, 300, 215, 144, + -26, 254, 170, -75, 175, 119, 2, 3, 4, 57, + 58, 59, 177, 178, 187, 272, 185, 186, 215, 262, + 233, 234, 124, 263, 188, 106, 191, 239, 240, 277, + 272, 193, 119, 201, 198, 199, 202, 206, 203, 288, + -116, 219, 42, 207, 223, 246, -162, 260, 261, 297, + 266, -27, 106, 8, 9, 10, 215, 265, 144, 161, + 276, 279, 278, 285, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 286, 289, 287, 290, + 291, 25, 26, 292, 27, 28, 85, 29, 86, 87, + 88, 89, 301, 229, 90, 91, 241, 243, 242, 155, + 76, 144, 144, 80, 156, 144, 144, 49, 192, 264, + 298, 268, 256, 92, 280, 269, 159, 70, 0, 0, + 144, 0, 0, 0, 93, 94, 0, 95, 0, 0, + 0, 0, 0, 0, 0, 0, 144, 0, 0, 0, + 144, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 127, 128, 129, 0, 130, 131, 132, 133, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 0, 0, 0, 23, 24, 25, 26, 134, 27, + 28, 85, 29, 86, 87, 88, 89, 0, 0, 90, + 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, + 0, 0, 135, 136, 0, 0, 0, 0, 137, 93, + 94, 0, 95, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 127, 128, 129, 0, 130, 131, 132, + 133, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 0, 0, 0, 23, 24, 25, 26, + 134, 27, 28, 85, 29, 86, 87, 88, 89, 0, + 0, 90, 91, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 92, 0, 0, 0, 135, 217, 0, 0, 0, 0, + 137, 93, 94, 0, 95, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 127, 128, 129, 0, 130, + 131, 132, 133, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 0, 0, 0, 23, 24, + 25, 26, 134, 27, 28, 85, 29, 86, 87, 88, + 89, 0, 0, 90, 91, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 92, 0, 0, 0, 135, 0, 0, 0, + 0, 0, 137, 93, 94, 0, 95, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 127, 128, 129, + 0, 130, 131, 132, 133, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 0, 0, 0, + 23, 24, 25, 26, 134, 27, 28, 85, 29, 86, + 87, 88, 89, 0, 0, 90, 91, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 92, 0, 0, 0, 74, 0, + 0, 0, 0, 0, 137, 93, 94, 0, 95, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 127, + 128, 129, 0, 130, 131, 132, 133, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, + 0, 0, 23, 24, 25, 26, 134, 27, 28, 85, + 29, 86, 87, 88, 89, 0, 0, 90, 91, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 137, 93, 94, 0, + 95, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 0, 0, 0, 0, 0, 0, 0, 0, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 0, 0, 0, 23, 24, 25, 26, 0, 27, + 28, 85, 29, 86, 87, 88, 89, 0, 0, 90, + 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 137, 93, + 94, 0, 95, 56, 2, 3, 4, 0, 6, 7, + 8, 9, 10, 0, 0, 0, 0, 0, 0, 0, + 0, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 0, 0, 0, 23, 24, 25, 26, + 0, 27, 28, 85, 29, 86, 87, 88, 89, 0, + 0, 90, 91, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 92, 0, 0, 0, 8, 9, 10, 0, 0, 0, + 0, 93, 94, 0, 95, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 0, 0, 0, + 0, 0, 25, 26, 0, 27, 28, 85, 29, 86, + 87, 88, 89, 0, 0, 90, 91, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 92, 0, 0, 0, 8, 9, + 10, 0, 0, 0, 204, 93, 94, 0, 95, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 0, 0, 0, 0, 0, 25, 26, 0, 27, + 28, 85, 29, 86, 87, 88, 89, 0, 0, 90, + 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, + 0, 220, 8, 9, 10, 0, 0, 0, 0, 93, + 94, 0, 95, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 0, 0, 0, 0, 0, + 25, 26, 0, 27, 28, 85, 29, 86, 87, 88, + 89, 0, 0, 90, 91, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 92, 0, 0, 0, 8, 9, 10, 0, + 0, 0, 0, 93, 94, 0, 95, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, + 0, 0, 0, 0, 25, 173, 0, 27, 28, 85, + 29, 86, 87, 88, 89, 0, 0, 90, 91, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 92, 2, 3, 4, + 0, 0, 0, 8, 9, 10, 0, 93, 94, 0, + 95, 0, 0, 0, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 0, 0, 0, 0, + 0, 25, 26, 0, 27, 28, 0, 29, 2, 3, + 4, 0, 0, 0, 8, 9, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 0, 196, 0, + 0, 0, 25, 26, 0, 27, 28, 0, 29, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 0, 0, 0, 0, 0, 0, 0, 245, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 0, 0, 0, 23, 24, 25, 26, 0, + 27, 28, 0, 29, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 0, 0, 0, 0, 0, 0, + 0, 0, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 0, 0, 0, 23, 24, 25, + 26, 0, 27, 28, 0, 29, 2, 3, 4, 0, + 0, 0, 8, 9, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 0, 8, 9, 10, 0, + 25, 26, 0, 27, 28, 0, 29, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, + 0, 0, 0, 0, 25, 26, 0, 27, 28, 227, + 29, 8, 9, 10, 228, 0, 0, 0, 0, 0, + 0, 0, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 0, 0, 0, 0, 0, 25, + 26, 0, 27, 28, 0, 29 +}; + +static const yytype_int16 yycheck[] = +{ + 0, 84, 92, 53, 68, 125, 0, 149, 0, 34, + 83, 43, 271, 158, 37, 82, 251, 84, 38, 83, + 43, 104, 53, 54, 68, 40, 60, 61, 62, 58, + 55, 71, 291, 255, 49, 69, 71, 77, 38, 83, + 40, 61, 74, 133, 44, 79, 90, 91, 270, 49, + 44, 286, 44, 73, 70, 290, 72, 88, 89, 72, + 80, 61, 80, 107, 93, 3, 79, 51, 52, 43, + 8, 9, 192, 73, 74, 158, 71, 70, 168, 72, + 80, 71, 77, 72, 157, 3, 79, 77, 72, 172, + 8, 9, 76, 157, 77, 33, 34, 35, 36, 37, + 190, 71, 74, 123, 37, 125, 77, 77, 77, 80, + 74, 80, 202, 157, 256, 33, 34, 35, 36, 37, + 80, 77, 43, 123, 80, 125, 181, 182, 183, 184, + 43, 214, 215, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 219, 292, 77, 149, + 70, 80, 71, 71, 70, 219, 4, 5, 6, 33, + 34, 35, 85, 86, 57, 255, 55, 56, 77, 78, + 179, 180, 192, 246, 59, 219, 73, 185, 186, 262, + 270, 43, 246, 70, 80, 80, 70, 70, 80, 279, + 70, 72, 192, 75, 73, 72, 74, 73, 73, 289, + 250, 70, 246, 10, 11, 12, 77, 40, 208, 292, + 73, 70, 73, 43, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 71, 80, 75, 71, + 16, 38, 39, 79, 41, 42, 43, 44, 45, 46, + 47, 48, 80, 169, 51, 52, 187, 189, 188, 80, + 55, 251, 252, 62, 80, 255, 256, 5, 123, 247, + 290, 252, 208, 70, 270, 252, 73, 44, -1, -1, + 270, -1, -1, -1, 81, 82, -1, 84, -1, -1, + -1, -1, -1, -1, -1, -1, 286, -1, -1, -1, + 290, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, -1, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, -1, -1, -1, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, -1, -1, 51, + 52, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 70, -1, + -1, -1, 74, 75, -1, -1, -1, -1, 80, 81, + 82, -1, 84, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, -1, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, -1, -1, -1, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, -1, + -1, 51, 52, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 70, -1, -1, -1, 74, 75, -1, -1, -1, -1, + 80, 81, 82, -1, 84, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, -1, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, -1, -1, -1, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, -1, -1, 51, 52, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 70, -1, -1, -1, 74, -1, -1, -1, + -1, -1, 80, 81, 82, -1, 84, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + -1, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, -1, -1, 51, 52, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 70, -1, -1, -1, 74, -1, + -1, -1, -1, -1, 80, 81, 82, -1, 84, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, -1, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, + -1, -1, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, -1, -1, 51, 52, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 70, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 80, 81, 82, -1, + 84, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, -1, -1, -1, -1, -1, -1, -1, -1, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, -1, -1, -1, 36, 37, 38, 39, -1, 41, + 42, 43, 44, 45, 46, 47, 48, -1, -1, 51, + 52, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 70, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 80, 81, + 82, -1, 84, 3, 4, 5, 6, -1, 8, 9, + 10, 11, 12, -1, -1, -1, -1, -1, -1, -1, + -1, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, -1, -1, -1, 36, 37, 38, 39, + -1, 41, 42, 43, 44, 45, 46, 47, 48, -1, + -1, 51, 52, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 70, -1, -1, -1, 10, 11, 12, -1, -1, -1, + -1, 81, 82, -1, 84, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, + -1, -1, 38, 39, -1, 41, 42, 43, 44, 45, + 46, 47, 48, -1, -1, 51, 52, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 70, -1, -1, -1, 10, 11, + 12, -1, -1, -1, 80, 81, 82, -1, 84, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, -1, -1, -1, -1, -1, 38, 39, -1, 41, + 42, 43, 44, 45, 46, 47, 48, -1, -1, 51, + 52, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 70, -1, + -1, 73, 10, 11, 12, -1, -1, -1, -1, 81, + 82, -1, 84, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, -1, -1, -1, -1, -1, + 38, 39, -1, 41, 42, 43, 44, 45, 46, 47, + 48, -1, -1, 51, 52, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 70, -1, -1, -1, 10, 11, 12, -1, + -1, -1, -1, 81, 82, -1, 84, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, + -1, -1, -1, -1, 38, 39, -1, 41, 42, 43, + 44, 45, 46, 47, 48, -1, -1, 51, 52, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 70, 4, 5, 6, + -1, -1, -1, 10, 11, 12, -1, 81, 82, -1, + 84, -1, -1, -1, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, + -1, 38, 39, -1, 41, 42, -1, 44, 4, 5, + 6, -1, -1, -1, 10, 11, 12, -1, -1, -1, + -1, -1, -1, -1, -1, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, -1, 75, -1, + -1, -1, 38, 39, -1, 41, 42, -1, 44, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, + -1, -1, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, -1, -1, -1, -1, -1, -1, -1, 75, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, -1, -1, -1, 36, 37, 38, 39, -1, + 41, 42, -1, 44, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, -1, -1, -1, -1, -1, -1, + -1, -1, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, -1, -1, -1, 36, 37, 38, + 39, -1, 41, 42, -1, 44, 4, 5, 6, -1, + -1, -1, 10, 11, 12, -1, -1, -1, -1, -1, + -1, -1, -1, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, -1, 10, 11, 12, -1, + 38, 39, -1, 41, 42, -1, 44, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, + -1, -1, -1, -1, 38, 39, -1, 41, 42, 43, + 44, 10, 11, 12, 48, -1, -1, -1, -1, -1, + -1, -1, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, -1, -1, -1, -1, -1, 38, + 39, -1, 41, 42, -1, 44 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 36, 37, 38, 39, 41, 42, 44, + 124, 125, 126, 127, 128, 133, 134, 135, 136, 137, + 138, 139, 140, 141, 173, 174, 175, 37, 43, 138, + 43, 74, 80, 176, 71, 77, 3, 33, 34, 35, + 130, 131, 136, 77, 80, 43, 137, 139, 72, 0, + 174, 139, 74, 143, 74, 159, 130, 129, 132, 137, + 131, 43, 70, 72, 79, 43, 45, 46, 47, 48, + 51, 52, 70, 81, 82, 84, 95, 96, 97, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 123, 140, 80, 142, 137, 144, 145, 13, 14, 15, + 17, 18, 19, 20, 40, 74, 75, 80, 106, 119, + 120, 122, 124, 125, 140, 149, 150, 151, 152, 160, + 161, 162, 165, 172, 43, 129, 132, 72, 79, 73, + 123, 120, 148, 106, 106, 122, 51, 52, 72, 76, + 71, 71, 77, 39, 120, 70, 106, 85, 86, 82, + 84, 53, 54, 88, 89, 55, 56, 57, 59, 58, + 93, 73, 144, 43, 146, 147, 75, 145, 80, 80, + 167, 70, 70, 80, 80, 122, 70, 75, 153, 60, + 61, 62, 69, 79, 121, 77, 80, 75, 150, 72, + 73, 123, 148, 73, 71, 98, 122, 43, 48, 101, + 120, 106, 106, 108, 108, 110, 110, 110, 110, 111, + 111, 115, 116, 117, 122, 75, 72, 77, 80, 156, + 157, 158, 168, 122, 80, 166, 160, 120, 120, 123, + 73, 73, 78, 123, 147, 40, 159, 151, 149, 161, + 169, 71, 122, 135, 164, 154, 73, 120, 73, 70, + 164, 170, 171, 156, 163, 43, 71, 75, 122, 80, + 71, 16, 79, 151, 155, 159, 71, 122, 155, 156, + 148, 80 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. However, + YYFAIL appears to be in use. Nevertheless, it is formally deprecated + in Bison 2.4.2's NEWS entry, where a plan to phase it out is + discussed. */ + +#define YYFAIL goto yyerrlab +#if defined YYFAIL + /* This is here to suppress warnings from the GCC cpp's + -Wunused-macros. Normally we don't worry about that warning, but + some users do, and we want to make it easy for users to remove + YYFAIL uses, which will produce warnings from Bison 2.5. */ +#endif + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (context, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, YYLEX_PARAM) +#else +# define YYLEX yylex (&yylval) +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, context); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, TParseContext* context) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep, context) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + TParseContext* context; +#endif +{ + if (!yyvaluep) + return; + YYUSE (context); +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, TParseContext* context) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep, context) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + TParseContext* context; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep, context); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule, TParseContext* context) +#else +static void +yy_reduce_print (yyvsp, yyrule, context) + YYSTYPE *yyvsp; + int yyrule; + TParseContext* context; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , context); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule, context); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, TParseContext* context) +#else +static void +yydestruct (yymsg, yytype, yyvaluep, context) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; + TParseContext* context; +#endif +{ + YYUSE (yyvaluep); + YYUSE (context); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (TParseContext* context); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + + + +/*-------------------------. +| yyparse or yypush_parse. | +`-------------------------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (TParseContext* context) +#else +int +yyparse (context) + TParseContext* context; +#endif +#endif +{ +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: + + { + // The symbol table search was done in the lexical phase + const TSymbol* symbol = (yyvsp[(1) - (1)].lex).symbol; + const TVariable* variable; + if (symbol == 0) { + context->error((yyvsp[(1) - (1)].lex).line, "undeclared identifier", (yyvsp[(1) - (1)].lex).string->c_str()); + context->recover(); + TType type(EbtFloat, EbpUndefined); + TVariable* fakeVariable = new TVariable((yyvsp[(1) - (1)].lex).string, type); + context->symbolTable.insert(*fakeVariable); + variable = fakeVariable; + } else { + // This identifier can only be a variable type symbol + if (! symbol->isVariable()) { + context->error((yyvsp[(1) - (1)].lex).line, "variable expected", (yyvsp[(1) - (1)].lex).string->c_str()); + context->recover(); + } + variable = static_cast<const TVariable*>(symbol); + } + + // don't delete $1.string, it's used by error recovery, and the pool + // pop will reclaim the memory + + if (variable->getType().getQualifier() == EvqConst ) { + ConstantUnion* constArray = variable->getConstPointer(); + TType t(variable->getType()); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(constArray, t, (yyvsp[(1) - (1)].lex).line); + } else + (yyval.interm.intermTypedNode) = context->intermediate.addSymbol(variable->getUniqueId(), + variable->getName(), + variable->getType(), (yyvsp[(1) - (1)].lex).line); + } + break; + + case 3: + + { + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); + } + break; + + case 4: + + { + // + // INT_TYPE is only 16-bit plus sign bit for vertex/fragment shaders, + // check for overflow for constants + // + if (abs((yyvsp[(1) - (1)].lex).i) >= (1 << 16)) { + context->error((yyvsp[(1) - (1)].lex).line, " integer constant overflow", ""); + context->recover(); + } + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst((yyvsp[(1) - (1)].lex).i); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), (yyvsp[(1) - (1)].lex).line); + } + break; + + case 5: + + { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setFConst((yyvsp[(1) - (1)].lex).f); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), (yyvsp[(1) - (1)].lex).line); + } + break; + + case 6: + + { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst((yyvsp[(1) - (1)].lex).b); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(1) - (1)].lex).line); + } + break; + + case 7: + + { + (yyval.interm.intermTypedNode) = (yyvsp[(2) - (3)].interm.intermTypedNode); + } + break; + + case 8: + + { + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); + } + break; + + case 9: + + { + if (!(yyvsp[(1) - (4)].interm.intermTypedNode)->isArray() && !(yyvsp[(1) - (4)].interm.intermTypedNode)->isMatrix() && !(yyvsp[(1) - (4)].interm.intermTypedNode)->isVector()) { + if ((yyvsp[(1) - (4)].interm.intermTypedNode)->getAsSymbolNode()) + context->error((yyvsp[(2) - (4)].lex).line, " left of '[' is not of type array, matrix, or vector ", (yyvsp[(1) - (4)].interm.intermTypedNode)->getAsSymbolNode()->getSymbol().c_str()); + else + context->error((yyvsp[(2) - (4)].lex).line, " left of '[' is not of type array, matrix, or vector ", "expression"); + context->recover(); + } + if ((yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getQualifier() == EvqConst && (yyvsp[(3) - (4)].interm.intermTypedNode)->getQualifier() == EvqConst) { + if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isArray()) { // constant folding for arrays + (yyval.interm.intermTypedNode) = context->addConstArrayNode((yyvsp[(3) - (4)].interm.intermTypedNode)->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), (yyvsp[(1) - (4)].interm.intermTypedNode), (yyvsp[(2) - (4)].lex).line); + } else if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isVector()) { // constant folding for vectors + TVectorFields fields; + fields.num = 1; + fields.offsets[0] = (yyvsp[(3) - (4)].interm.intermTypedNode)->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); // need to do it this way because v.xy sends fields integer array + (yyval.interm.intermTypedNode) = context->addConstVectorNode(fields, (yyvsp[(1) - (4)].interm.intermTypedNode), (yyvsp[(2) - (4)].lex).line); + } else if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isMatrix()) { // constant folding for matrices + (yyval.interm.intermTypedNode) = context->addConstMatrixNode((yyvsp[(3) - (4)].interm.intermTypedNode)->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), (yyvsp[(1) - (4)].interm.intermTypedNode), (yyvsp[(2) - (4)].lex).line); + } + } else { + if ((yyvsp[(3) - (4)].interm.intermTypedNode)->getQualifier() == EvqConst) { + if (((yyvsp[(1) - (4)].interm.intermTypedNode)->isVector() || (yyvsp[(1) - (4)].interm.intermTypedNode)->isMatrix()) && (yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getNominalSize() <= (yyvsp[(3) - (4)].interm.intermTypedNode)->getAsConstantUnion()->getUnionArrayPointer()->getIConst() && !(yyvsp[(1) - (4)].interm.intermTypedNode)->isArray() ) { + std::stringstream extraInfoStream; + extraInfoStream << "field selection out of range '" << (yyvsp[(3) - (4)].interm.intermTypedNode)->getAsConstantUnion()->getUnionArrayPointer()->getIConst() << "'"; + std::string extraInfo = extraInfoStream.str(); + context->error((yyvsp[(2) - (4)].lex).line, "", "[", extraInfo.c_str()); + context->recover(); + } else { + if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isArray()) { + if ((yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getArraySize() == 0) { + if ((yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getMaxArraySize() <= (yyvsp[(3) - (4)].interm.intermTypedNode)->getAsConstantUnion()->getUnionArrayPointer()->getIConst()) { + if (context->arraySetMaxSize((yyvsp[(1) - (4)].interm.intermTypedNode)->getAsSymbolNode(), (yyvsp[(1) - (4)].interm.intermTypedNode)->getTypePointer(), (yyvsp[(3) - (4)].interm.intermTypedNode)->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), true, (yyvsp[(2) - (4)].lex).line)) + context->recover(); + } else { + if (context->arraySetMaxSize((yyvsp[(1) - (4)].interm.intermTypedNode)->getAsSymbolNode(), (yyvsp[(1) - (4)].interm.intermTypedNode)->getTypePointer(), 0, false, (yyvsp[(2) - (4)].lex).line)) + context->recover(); + } + } else if ( (yyvsp[(3) - (4)].interm.intermTypedNode)->getAsConstantUnion()->getUnionArrayPointer()->getIConst() >= (yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getArraySize()) { + std::stringstream extraInfoStream; + extraInfoStream << "array index out of range '" << (yyvsp[(3) - (4)].interm.intermTypedNode)->getAsConstantUnion()->getUnionArrayPointer()->getIConst() << "'"; + std::string extraInfo = extraInfoStream.str(); + context->error((yyvsp[(2) - (4)].lex).line, "", "[", extraInfo.c_str()); + context->recover(); + } + } + (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpIndexDirect, (yyvsp[(1) - (4)].interm.intermTypedNode), (yyvsp[(3) - (4)].interm.intermTypedNode), (yyvsp[(2) - (4)].lex).line); + } + } else { + if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isArray() && (yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getArraySize() == 0) { + context->error((yyvsp[(2) - (4)].lex).line, "", "[", "array must be redeclared with a size before being indexed with a variable"); + context->recover(); + } + + (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpIndexIndirect, (yyvsp[(1) - (4)].interm.intermTypedNode), (yyvsp[(3) - (4)].interm.intermTypedNode), (yyvsp[(2) - (4)].lex).line); + } + } + if ((yyval.interm.intermTypedNode) == 0) { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setFConst(0.0f); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), (yyvsp[(2) - (4)].lex).line); + } else if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isArray()) { + if ((yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getStruct()) + (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getStruct(), (yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getTypeName())); + else + (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (4)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (4)].interm.intermTypedNode)->getPrecision(), EvqTemporary, (yyvsp[(1) - (4)].interm.intermTypedNode)->getNominalSize(), (yyvsp[(1) - (4)].interm.intermTypedNode)->isMatrix())); + + if ((yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getQualifier() == EvqConst) + (yyval.interm.intermTypedNode)->getTypePointer()->setQualifier(EvqConst); + } else if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isMatrix() && (yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getQualifier() == EvqConst) + (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (4)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (4)].interm.intermTypedNode)->getPrecision(), EvqConst, (yyvsp[(1) - (4)].interm.intermTypedNode)->getNominalSize())); + else if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isMatrix()) + (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (4)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (4)].interm.intermTypedNode)->getPrecision(), EvqTemporary, (yyvsp[(1) - (4)].interm.intermTypedNode)->getNominalSize())); + else if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isVector() && (yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getQualifier() == EvqConst) + (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (4)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (4)].interm.intermTypedNode)->getPrecision(), EvqConst)); + else if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isVector()) + (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (4)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (4)].interm.intermTypedNode)->getPrecision(), EvqTemporary)); + else + (yyval.interm.intermTypedNode)->setType((yyvsp[(1) - (4)].interm.intermTypedNode)->getType()); + } + break; + + case 10: + + { + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); + } + break; + + case 11: + + { + if ((yyvsp[(1) - (3)].interm.intermTypedNode)->isArray()) { + context->error((yyvsp[(3) - (3)].lex).line, "cannot apply dot operator to an array", "."); + context->recover(); + } + + if ((yyvsp[(1) - (3)].interm.intermTypedNode)->isVector()) { + TVectorFields fields; + if (! context->parseVectorFields(*(yyvsp[(3) - (3)].lex).string, (yyvsp[(1) - (3)].interm.intermTypedNode)->getNominalSize(), fields, (yyvsp[(3) - (3)].lex).line)) { + fields.num = 1; + fields.offsets[0] = 0; + context->recover(); + } + + if ((yyvsp[(1) - (3)].interm.intermTypedNode)->getType().getQualifier() == EvqConst) { // constant folding for vector fields + (yyval.interm.intermTypedNode) = context->addConstVectorNode(fields, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].lex).line); + if ((yyval.interm.intermTypedNode) == 0) { + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode); + } + else + (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (3)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (3)].interm.intermTypedNode)->getPrecision(), EvqConst, (int) (*(yyvsp[(3) - (3)].lex).string).size())); + } else { + TString vectorString = *(yyvsp[(3) - (3)].lex).string; + TIntermTyped* index = context->intermediate.addSwizzle(fields, (yyvsp[(3) - (3)].lex).line); + (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpVectorSwizzle, (yyvsp[(1) - (3)].interm.intermTypedNode), index, (yyvsp[(2) - (3)].lex).line); + (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (3)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (3)].interm.intermTypedNode)->getPrecision(), EvqTemporary, (int) vectorString.size())); + } + } else if ((yyvsp[(1) - (3)].interm.intermTypedNode)->isMatrix()) { + TMatrixFields fields; + if (! context->parseMatrixFields(*(yyvsp[(3) - (3)].lex).string, (yyvsp[(1) - (3)].interm.intermTypedNode)->getNominalSize(), fields, (yyvsp[(3) - (3)].lex).line)) { + fields.wholeRow = false; + fields.wholeCol = false; + fields.row = 0; + fields.col = 0; + context->recover(); + } + + if (fields.wholeRow || fields.wholeCol) { + context->error((yyvsp[(2) - (3)].lex).line, " non-scalar fields not implemented yet", "."); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst(0); + TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), (yyvsp[(3) - (3)].lex).line); + (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpIndexDirect, (yyvsp[(1) - (3)].interm.intermTypedNode), index, (yyvsp[(2) - (3)].lex).line); + (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (3)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (3)].interm.intermTypedNode)->getPrecision(),EvqTemporary, (yyvsp[(1) - (3)].interm.intermTypedNode)->getNominalSize())); + } else { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst(fields.col * (yyvsp[(1) - (3)].interm.intermTypedNode)->getNominalSize() + fields.row); + TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), (yyvsp[(3) - (3)].lex).line); + (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpIndexDirect, (yyvsp[(1) - (3)].interm.intermTypedNode), index, (yyvsp[(2) - (3)].lex).line); + (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (3)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (3)].interm.intermTypedNode)->getPrecision())); + } + } else if ((yyvsp[(1) - (3)].interm.intermTypedNode)->getBasicType() == EbtStruct) { + bool fieldFound = false; + const TTypeList* fields = (yyvsp[(1) - (3)].interm.intermTypedNode)->getType().getStruct(); + if (fields == 0) { + context->error((yyvsp[(2) - (3)].lex).line, "structure has no fields", "Internal Error"); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode); + } else { + unsigned int i; + for (i = 0; i < fields->size(); ++i) { + if ((*fields)[i].type->getFieldName() == *(yyvsp[(3) - (3)].lex).string) { + fieldFound = true; + break; + } + } + if (fieldFound) { + if ((yyvsp[(1) - (3)].interm.intermTypedNode)->getType().getQualifier() == EvqConst) { + (yyval.interm.intermTypedNode) = context->addConstStruct(*(yyvsp[(3) - (3)].lex).string, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line); + if ((yyval.interm.intermTypedNode) == 0) { + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode); + } + else { + (yyval.interm.intermTypedNode)->setType(*(*fields)[i].type); + // change the qualifier of the return type, not of the structure field + // as the structure definition is shared between various structures. + (yyval.interm.intermTypedNode)->getTypePointer()->setQualifier(EvqConst); + } + } else { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst(i); + TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, *(*fields)[i].type, (yyvsp[(3) - (3)].lex).line); + (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpIndexDirectStruct, (yyvsp[(1) - (3)].interm.intermTypedNode), index, (yyvsp[(2) - (3)].lex).line); + (yyval.interm.intermTypedNode)->setType(*(*fields)[i].type); + } + } else { + context->error((yyvsp[(2) - (3)].lex).line, " no such field in structure", (yyvsp[(3) - (3)].lex).string->c_str()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode); + } + } + } else { + context->error((yyvsp[(2) - (3)].lex).line, " field selection requires structure, vector, or matrix on left hand side", (yyvsp[(3) - (3)].lex).string->c_str()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode); + } + // don't delete $3.string, it's from the pool + } + break; + + case 12: + + { + if (context->lValueErrorCheck((yyvsp[(2) - (2)].lex).line, "++", (yyvsp[(1) - (2)].interm.intermTypedNode))) + context->recover(); + (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPostIncrement, (yyvsp[(1) - (2)].interm.intermTypedNode), (yyvsp[(2) - (2)].lex).line, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + context->unaryOpError((yyvsp[(2) - (2)].lex).line, "++", (yyvsp[(1) - (2)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (2)].interm.intermTypedNode); + } + } + break; + + case 13: + + { + if (context->lValueErrorCheck((yyvsp[(2) - (2)].lex).line, "--", (yyvsp[(1) - (2)].interm.intermTypedNode))) + context->recover(); + (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPostDecrement, (yyvsp[(1) - (2)].interm.intermTypedNode), (yyvsp[(2) - (2)].lex).line, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + context->unaryOpError((yyvsp[(2) - (2)].lex).line, "--", (yyvsp[(1) - (2)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (2)].interm.intermTypedNode); + } + } + break; + + case 14: + + { + if (context->integerErrorCheck((yyvsp[(1) - (1)].interm.intermTypedNode), "[]")) + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); + } + break; + + case 15: + + { + TFunction* fnCall = (yyvsp[(1) - (1)].interm).function; + TOperator op = fnCall->getBuiltInOp(); + + if (op != EOpNull) + { + // + // Then this should be a constructor. + // Don't go through the symbol table for constructors. + // Their parameters will be verified algorithmically. + // + TType type(EbtVoid, EbpUndefined); // use this to get the type back + if (context->constructorErrorCheck((yyvsp[(1) - (1)].interm).line, (yyvsp[(1) - (1)].interm).intermNode, *fnCall, op, &type)) { + (yyval.interm.intermTypedNode) = 0; + } else { + // + // It's a constructor, of type 'type'. + // + (yyval.interm.intermTypedNode) = context->addConstructor((yyvsp[(1) - (1)].interm).intermNode, &type, op, fnCall, (yyvsp[(1) - (1)].interm).line); + } + + if ((yyval.interm.intermTypedNode) == 0) { + context->recover(); + (yyval.interm.intermTypedNode) = context->intermediate.setAggregateOperator(0, op, (yyvsp[(1) - (1)].interm).line); + } + (yyval.interm.intermTypedNode)->setType(type); + } else { + // + // Not a constructor. Find it in the symbol table. + // + const TFunction* fnCandidate; + bool builtIn; + fnCandidate = context->findFunction((yyvsp[(1) - (1)].interm).line, fnCall, &builtIn); + if (fnCandidate) { + // + // A declared function. + // + if (builtIn && !fnCandidate->getExtension().empty() && + context->extensionErrorCheck((yyvsp[(1) - (1)].interm).line, fnCandidate->getExtension())) { + context->recover(); + } + op = fnCandidate->getBuiltInOp(); + if (builtIn && op != EOpNull) { + // + // A function call mapped to a built-in operation. + // + if (fnCandidate->getParamCount() == 1) { + // + // Treat it like a built-in unary operator. + // + (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(op, (yyvsp[(1) - (1)].interm).intermNode, 0, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + std::stringstream extraInfoStream; + extraInfoStream << "built in unary operator function. Type: " << static_cast<TIntermTyped*>((yyvsp[(1) - (1)].interm).intermNode)->getCompleteString(); + std::string extraInfo = extraInfoStream.str(); + context->error((yyvsp[(1) - (1)].interm).intermNode->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str()); + YYERROR; + } + } else { + (yyval.interm.intermTypedNode) = context->intermediate.setAggregateOperator((yyvsp[(1) - (1)].interm).intermAggregate, op, (yyvsp[(1) - (1)].interm).line); + } + } else { + // This is a real function call + + (yyval.interm.intermTypedNode) = context->intermediate.setAggregateOperator((yyvsp[(1) - (1)].interm).intermAggregate, EOpFunctionCall, (yyvsp[(1) - (1)].interm).line); + (yyval.interm.intermTypedNode)->setType(fnCandidate->getReturnType()); + + // this is how we know whether the given function is a builtIn function or a user defined function + // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also + // if builtIn == true, it's definitely a builtIn function with EOpNull + if (!builtIn) + (yyval.interm.intermTypedNode)->getAsAggregate()->setUserDefined(); + (yyval.interm.intermTypedNode)->getAsAggregate()->setName(fnCandidate->getMangledName()); + + TQualifier qual; + for (int i = 0; i < fnCandidate->getParamCount(); ++i) { + qual = fnCandidate->getParam(i).type->getQualifier(); + if (qual == EvqOut || qual == EvqInOut) { + if (context->lValueErrorCheck((yyval.interm.intermTypedNode)->getLine(), "assign", (yyval.interm.intermTypedNode)->getAsAggregate()->getSequence()[i]->getAsTyped())) { + context->error((yyvsp[(1) - (1)].interm).intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error"); + context->recover(); + } + } + } + } + (yyval.interm.intermTypedNode)->setType(fnCandidate->getReturnType()); + } else { + // error message was put out by PaFindFunction() + // Put on a dummy node for error recovery + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setFConst(0.0f); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), (yyvsp[(1) - (1)].interm).line); + context->recover(); + } + } + delete fnCall; + } + break; + + case 16: + + { + (yyval.interm) = (yyvsp[(1) - (1)].interm); + } + break; + + case 17: + + { + context->error((yyvsp[(3) - (3)].interm).line, "methods are not supported", ""); + context->recover(); + (yyval.interm) = (yyvsp[(3) - (3)].interm); + } + break; + + case 18: + + { + (yyval.interm) = (yyvsp[(1) - (2)].interm); + (yyval.interm).line = (yyvsp[(2) - (2)].lex).line; + } + break; + + case 19: + + { + (yyval.interm) = (yyvsp[(1) - (2)].interm); + (yyval.interm).line = (yyvsp[(2) - (2)].lex).line; + } + break; + + case 20: + + { + (yyval.interm).function = (yyvsp[(1) - (2)].interm.function); + (yyval.interm).intermNode = 0; + } + break; + + case 21: + + { + (yyval.interm).function = (yyvsp[(1) - (1)].interm.function); + (yyval.interm).intermNode = 0; + } + break; + + case 22: + + { + TParameter param = { 0, new TType((yyvsp[(2) - (2)].interm.intermTypedNode)->getType()) }; + (yyvsp[(1) - (2)].interm.function)->addParameter(param); + (yyval.interm).function = (yyvsp[(1) - (2)].interm.function); + (yyval.interm).intermNode = (yyvsp[(2) - (2)].interm.intermTypedNode); + } + break; + + case 23: + + { + TParameter param = { 0, new TType((yyvsp[(3) - (3)].interm.intermTypedNode)->getType()) }; + (yyvsp[(1) - (3)].interm).function->addParameter(param); + (yyval.interm).function = (yyvsp[(1) - (3)].interm).function; + (yyval.interm).intermNode = context->intermediate.growAggregate((yyvsp[(1) - (3)].interm).intermNode, (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line); + } + break; + + case 24: + + { + (yyval.interm.function) = (yyvsp[(1) - (2)].interm.function); + } + break; + + case 25: + + { + // + // Constructor + // + TOperator op = EOpNull; + if ((yyvsp[(1) - (1)].interm.type).userDef) { + op = EOpConstructStruct; + } else { + switch ((yyvsp[(1) - (1)].interm.type).type) { + case EbtFloat: + if ((yyvsp[(1) - (1)].interm.type).matrix) { + switch((yyvsp[(1) - (1)].interm.type).size) { + case 2: op = EOpConstructMat2; break; + case 3: op = EOpConstructMat3; break; + case 4: op = EOpConstructMat4; break; + } + } else { + switch((yyvsp[(1) - (1)].interm.type).size) { + case 1: op = EOpConstructFloat; break; + case 2: op = EOpConstructVec2; break; + case 3: op = EOpConstructVec3; break; + case 4: op = EOpConstructVec4; break; + } + } + break; + case EbtInt: + switch((yyvsp[(1) - (1)].interm.type).size) { + case 1: op = EOpConstructInt; break; + case 2: FRAG_VERT_ONLY("ivec2", (yyvsp[(1) - (1)].interm.type).line); op = EOpConstructIVec2; break; + case 3: FRAG_VERT_ONLY("ivec3", (yyvsp[(1) - (1)].interm.type).line); op = EOpConstructIVec3; break; + case 4: FRAG_VERT_ONLY("ivec4", (yyvsp[(1) - (1)].interm.type).line); op = EOpConstructIVec4; break; + } + break; + case EbtBool: + switch((yyvsp[(1) - (1)].interm.type).size) { + case 1: op = EOpConstructBool; break; + case 2: FRAG_VERT_ONLY("bvec2", (yyvsp[(1) - (1)].interm.type).line); op = EOpConstructBVec2; break; + case 3: FRAG_VERT_ONLY("bvec3", (yyvsp[(1) - (1)].interm.type).line); op = EOpConstructBVec3; break; + case 4: FRAG_VERT_ONLY("bvec4", (yyvsp[(1) - (1)].interm.type).line); op = EOpConstructBVec4; break; + } + break; + default: break; + } + if (op == EOpNull) { + context->error((yyvsp[(1) - (1)].interm.type).line, "cannot construct this type", getBasicString((yyvsp[(1) - (1)].interm.type).type)); + context->recover(); + (yyvsp[(1) - (1)].interm.type).type = EbtFloat; + op = EOpConstructFloat; + } + } + TString tempString; + TType type((yyvsp[(1) - (1)].interm.type)); + TFunction *function = new TFunction(&tempString, type, op); + (yyval.interm.function) = function; + } + break; + + case 26: + + { + if (context->reservedErrorCheck((yyvsp[(1) - (1)].lex).line, *(yyvsp[(1) - (1)].lex).string)) + context->recover(); + TType type(EbtVoid, EbpUndefined); + TFunction *function = new TFunction((yyvsp[(1) - (1)].lex).string, type); + (yyval.interm.function) = function; + } + break; + + case 27: + + { + if (context->reservedErrorCheck((yyvsp[(1) - (1)].lex).line, *(yyvsp[(1) - (1)].lex).string)) + context->recover(); + TType type(EbtVoid, EbpUndefined); + TFunction *function = new TFunction((yyvsp[(1) - (1)].lex).string, type); + (yyval.interm.function) = function; + } + break; + + case 28: + + { + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); + } + break; + + case 29: + + { + if (context->lValueErrorCheck((yyvsp[(1) - (2)].lex).line, "++", (yyvsp[(2) - (2)].interm.intermTypedNode))) + context->recover(); + (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPreIncrement, (yyvsp[(2) - (2)].interm.intermTypedNode), (yyvsp[(1) - (2)].lex).line, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + context->unaryOpError((yyvsp[(1) - (2)].lex).line, "++", (yyvsp[(2) - (2)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode); + } + } + break; + + case 30: + + { + if (context->lValueErrorCheck((yyvsp[(1) - (2)].lex).line, "--", (yyvsp[(2) - (2)].interm.intermTypedNode))) + context->recover(); + (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPreDecrement, (yyvsp[(2) - (2)].interm.intermTypedNode), (yyvsp[(1) - (2)].lex).line, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + context->unaryOpError((yyvsp[(1) - (2)].lex).line, "--", (yyvsp[(2) - (2)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode); + } + } + break; + + case 31: + + { + if ((yyvsp[(1) - (2)].interm).op != EOpNull) { + (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath((yyvsp[(1) - (2)].interm).op, (yyvsp[(2) - (2)].interm.intermTypedNode), (yyvsp[(1) - (2)].interm).line, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + const char* errorOp = ""; + switch((yyvsp[(1) - (2)].interm).op) { + case EOpNegative: errorOp = "-"; break; + case EOpLogicalNot: errorOp = "!"; break; + default: break; + } + context->unaryOpError((yyvsp[(1) - (2)].interm).line, errorOp, (yyvsp[(2) - (2)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode); + } + } else + (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode); + } + break; + + case 32: + + { (yyval.interm).line = (yyvsp[(1) - (1)].lex).line; (yyval.interm).op = EOpNull; } + break; + + case 33: + + { (yyval.interm).line = (yyvsp[(1) - (1)].lex).line; (yyval.interm).op = EOpNegative; } + break; + + case 34: + + { (yyval.interm).line = (yyvsp[(1) - (1)].lex).line; (yyval.interm).op = EOpLogicalNot; } + break; + + case 35: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 36: + + { + FRAG_VERT_ONLY("*", (yyvsp[(2) - (3)].lex).line); + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpMul, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yyvsp[(2) - (3)].lex).line, "*", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode); + } + } + break; + + case 37: + + { + FRAG_VERT_ONLY("/", (yyvsp[(2) - (3)].lex).line); + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpDiv, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yyvsp[(2) - (3)].lex).line, "/", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode); + } + } + break; + + case 38: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 39: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpAdd, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yyvsp[(2) - (3)].lex).line, "+", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode); + } + } + break; + + case 40: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpSub, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yyvsp[(2) - (3)].lex).line, "-", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode); + } + } + break; + + case 41: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 42: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 43: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLessThan, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yyvsp[(2) - (3)].lex).line, "<", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(2) - (3)].lex).line); + } + } + break; + + case 44: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpGreaterThan, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yyvsp[(2) - (3)].lex).line, ">", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(2) - (3)].lex).line); + } + } + break; + + case 45: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLessThanEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yyvsp[(2) - (3)].lex).line, "<=", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(2) - (3)].lex).line); + } + } + break; + + case 46: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpGreaterThanEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yyvsp[(2) - (3)].lex).line, ">=", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(2) - (3)].lex).line); + } + } + break; + + case 47: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 48: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yyvsp[(2) - (3)].lex).line, "==", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(2) - (3)].lex).line); + } + } + break; + + case 49: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpNotEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yyvsp[(2) - (3)].lex).line, "!=", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(2) - (3)].lex).line); + } + } + break; + + case 50: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 51: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 52: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 53: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 54: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLogicalAnd, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yyvsp[(2) - (3)].lex).line, "&&", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(2) - (3)].lex).line); + } + } + break; + + case 55: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 56: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLogicalXor, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yyvsp[(2) - (3)].lex).line, "^^", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(2) - (3)].lex).line); + } + } + break; + + case 57: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 58: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLogicalOr, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yyvsp[(2) - (3)].lex).line, "||", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(2) - (3)].lex).line); + } + } + break; + + case 59: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 60: + + { + if (context->boolErrorCheck((yyvsp[(2) - (5)].lex).line, (yyvsp[(1) - (5)].interm.intermTypedNode))) + context->recover(); + + (yyval.interm.intermTypedNode) = context->intermediate.addSelection((yyvsp[(1) - (5)].interm.intermTypedNode), (yyvsp[(3) - (5)].interm.intermTypedNode), (yyvsp[(5) - (5)].interm.intermTypedNode), (yyvsp[(2) - (5)].lex).line); + if ((yyvsp[(3) - (5)].interm.intermTypedNode)->getType() != (yyvsp[(5) - (5)].interm.intermTypedNode)->getType()) + (yyval.interm.intermTypedNode) = 0; + + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yyvsp[(2) - (5)].lex).line, ":", (yyvsp[(3) - (5)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(5) - (5)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(5) - (5)].interm.intermTypedNode); + } + } + break; + + case 61: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 62: + + { + if (context->lValueErrorCheck((yyvsp[(2) - (3)].interm).line, "assign", (yyvsp[(1) - (3)].interm.intermTypedNode))) + context->recover(); + (yyval.interm.intermTypedNode) = context->intermediate.addAssign((yyvsp[(2) - (3)].interm).op, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].interm).line); + if ((yyval.interm.intermTypedNode) == 0) { + context->assignError((yyvsp[(2) - (3)].interm).line, "assign", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode); + } + } + break; + + case 63: + + { (yyval.interm).line = (yyvsp[(1) - (1)].lex).line; (yyval.interm).op = EOpAssign; } + break; + + case 64: + + { FRAG_VERT_ONLY("*=", (yyvsp[(1) - (1)].lex).line); (yyval.interm).line = (yyvsp[(1) - (1)].lex).line; (yyval.interm).op = EOpMulAssign; } + break; + + case 65: + + { FRAG_VERT_ONLY("/=", (yyvsp[(1) - (1)].lex).line); (yyval.interm).line = (yyvsp[(1) - (1)].lex).line; (yyval.interm).op = EOpDivAssign; } + break; + + case 66: + + { (yyval.interm).line = (yyvsp[(1) - (1)].lex).line; (yyval.interm).op = EOpAddAssign; } + break; + + case 67: + + { (yyval.interm).line = (yyvsp[(1) - (1)].lex).line; (yyval.interm).op = EOpSubAssign; } + break; + + case 68: + + { + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); + } + break; + + case 69: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addComma((yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yyvsp[(2) - (3)].lex).line, ",", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(3) - (3)].interm.intermTypedNode); + } + } + break; + + case 70: + + { + if (context->constErrorCheck((yyvsp[(1) - (1)].interm.intermTypedNode))) + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); + } + break; + + case 71: + + { + TFunction &function = *((yyvsp[(1) - (2)].interm).function); + + TIntermAggregate *prototype = new TIntermAggregate; + prototype->setType(function.getReturnType()); + prototype->setName(function.getName()); + + for (int i = 0; i < function.getParamCount(); i++) + { + const TParameter ¶m = function.getParam(i); + if (param.name != 0) + { + TVariable *variable = new TVariable(param.name, *param.type); + + prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), (yyvsp[(1) - (2)].interm).line), (yyvsp[(1) - (2)].interm).line); + } + else + { + prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(0, "", *param.type, (yyvsp[(1) - (2)].interm).line), (yyvsp[(1) - (2)].interm).line); + } + } + + prototype->setOp(EOpPrototype); + (yyval.interm.intermNode) = prototype; + + context->symbolTable.pop(); + } + break; + + case 72: + + { + if ((yyvsp[(1) - (2)].interm).intermAggregate) + (yyvsp[(1) - (2)].interm).intermAggregate->setOp(EOpDeclaration); + (yyval.interm.intermNode) = (yyvsp[(1) - (2)].interm).intermAggregate; + } + break; + + case 73: + + { + context->symbolTable.setDefaultPrecision( (yyvsp[(3) - (4)].interm.type).type, (yyvsp[(2) - (4)].interm.precision) ); + (yyval.interm.intermNode) = 0; + } + break; + + case 74: + + { + // + // Multiple declarations of the same function are allowed. + // + // If this is a definition, the definition production code will check for redefinitions + // (we don't know at this point if it's a definition or not). + // + // Redeclarations are allowed. But, return types and parameter qualifiers must match. + // + TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find((yyvsp[(1) - (2)].interm.function)->getMangledName())); + if (prevDec) { + if (prevDec->getReturnType() != (yyvsp[(1) - (2)].interm.function)->getReturnType()) { + context->error((yyvsp[(2) - (2)].lex).line, "overloaded functions must have the same return type", (yyvsp[(1) - (2)].interm.function)->getReturnType().getBasicString()); + context->recover(); + } + for (int i = 0; i < prevDec->getParamCount(); ++i) { + if (prevDec->getParam(i).type->getQualifier() != (yyvsp[(1) - (2)].interm.function)->getParam(i).type->getQualifier()) { + context->error((yyvsp[(2) - (2)].lex).line, "overloaded functions must have the same parameter qualifiers", (yyvsp[(1) - (2)].interm.function)->getParam(i).type->getQualifierString()); + context->recover(); + } + } + } + + // + // If this is a redeclaration, it could also be a definition, + // in which case, we want to use the variable names from this one, and not the one that's + // being redeclared. So, pass back up this declaration, not the one in the symbol table. + // + (yyval.interm).function = (yyvsp[(1) - (2)].interm.function); + (yyval.interm).line = (yyvsp[(2) - (2)].lex).line; + + // We're at the inner scope level of the function's arguments and body statement. + // Add the function prototype to the surrounding scope instead. + context->symbolTable.getOuterLevel()->insert(*(yyval.interm).function); + } + break; + + case 75: + + { + (yyval.interm.function) = (yyvsp[(1) - (1)].interm.function); + } + break; + + case 76: + + { + (yyval.interm.function) = (yyvsp[(1) - (1)].interm.function); + } + break; + + case 77: + + { + // Add the parameter + (yyval.interm.function) = (yyvsp[(1) - (2)].interm.function); + if ((yyvsp[(2) - (2)].interm).param.type->getBasicType() != EbtVoid) + (yyvsp[(1) - (2)].interm.function)->addParameter((yyvsp[(2) - (2)].interm).param); + else + delete (yyvsp[(2) - (2)].interm).param.type; + } + break; + + case 78: + + { + // + // Only first parameter of one-parameter functions can be void + // The check for named parameters not being void is done in parameter_declarator + // + if ((yyvsp[(3) - (3)].interm).param.type->getBasicType() == EbtVoid) { + // + // This parameter > first is void + // + context->error((yyvsp[(2) - (3)].lex).line, "cannot be an argument type except for '(void)'", "void"); + context->recover(); + delete (yyvsp[(3) - (3)].interm).param.type; + } else { + // Add the parameter + (yyval.interm.function) = (yyvsp[(1) - (3)].interm.function); + (yyvsp[(1) - (3)].interm.function)->addParameter((yyvsp[(3) - (3)].interm).param); + } + } + break; + + case 79: + + { + if ((yyvsp[(1) - (3)].interm.type).qualifier != EvqGlobal && (yyvsp[(1) - (3)].interm.type).qualifier != EvqTemporary) { + context->error((yyvsp[(2) - (3)].lex).line, "no qualifiers allowed for function return", getQualifierString((yyvsp[(1) - (3)].interm.type).qualifier)); + context->recover(); + } + // make sure a sampler is not involved as well... + if (context->structQualifierErrorCheck((yyvsp[(2) - (3)].lex).line, (yyvsp[(1) - (3)].interm.type))) + context->recover(); + + // Add the function as a prototype after parsing it (we do not support recursion) + TFunction *function; + TType type((yyvsp[(1) - (3)].interm.type)); + function = new TFunction((yyvsp[(2) - (3)].lex).string, type); + (yyval.interm.function) = function; + + context->symbolTable.push(); + } + break; + + case 80: + + { + if ((yyvsp[(1) - (2)].interm.type).type == EbtVoid) { + context->error((yyvsp[(2) - (2)].lex).line, "illegal use of type 'void'", (yyvsp[(2) - (2)].lex).string->c_str()); + context->recover(); + } + if (context->reservedErrorCheck((yyvsp[(2) - (2)].lex).line, *(yyvsp[(2) - (2)].lex).string)) + context->recover(); + TParameter param = {(yyvsp[(2) - (2)].lex).string, new TType((yyvsp[(1) - (2)].interm.type))}; + (yyval.interm).line = (yyvsp[(2) - (2)].lex).line; + (yyval.interm).param = param; + } + break; + + case 81: + + { + // Check that we can make an array out of this type + if (context->arrayTypeErrorCheck((yyvsp[(3) - (5)].lex).line, (yyvsp[(1) - (5)].interm.type))) + context->recover(); + + if (context->reservedErrorCheck((yyvsp[(2) - (5)].lex).line, *(yyvsp[(2) - (5)].lex).string)) + context->recover(); + + int size; + if (context->arraySizeErrorCheck((yyvsp[(3) - (5)].lex).line, (yyvsp[(4) - (5)].interm.intermTypedNode), size)) + context->recover(); + (yyvsp[(1) - (5)].interm.type).setArray(true, size); + + TType* type = new TType((yyvsp[(1) - (5)].interm.type)); + TParameter param = { (yyvsp[(2) - (5)].lex).string, type }; + (yyval.interm).line = (yyvsp[(2) - (5)].lex).line; + (yyval.interm).param = param; + } + break; + + case 82: + + { + (yyval.interm) = (yyvsp[(3) - (3)].interm); + if (context->paramErrorCheck((yyvsp[(3) - (3)].interm).line, (yyvsp[(1) - (3)].interm.type).qualifier, (yyvsp[(2) - (3)].interm.qualifier), (yyval.interm).param.type)) + context->recover(); + } + break; + + case 83: + + { + (yyval.interm) = (yyvsp[(2) - (2)].interm); + if (context->parameterSamplerErrorCheck((yyvsp[(2) - (2)].interm).line, (yyvsp[(1) - (2)].interm.qualifier), *(yyvsp[(2) - (2)].interm).param.type)) + context->recover(); + if (context->paramErrorCheck((yyvsp[(2) - (2)].interm).line, EvqTemporary, (yyvsp[(1) - (2)].interm.qualifier), (yyval.interm).param.type)) + context->recover(); + } + break; + + case 84: + + { + (yyval.interm) = (yyvsp[(3) - (3)].interm); + if (context->paramErrorCheck((yyvsp[(3) - (3)].interm).line, (yyvsp[(1) - (3)].interm.type).qualifier, (yyvsp[(2) - (3)].interm.qualifier), (yyval.interm).param.type)) + context->recover(); + } + break; + + case 85: + + { + (yyval.interm) = (yyvsp[(2) - (2)].interm); + if (context->parameterSamplerErrorCheck((yyvsp[(2) - (2)].interm).line, (yyvsp[(1) - (2)].interm.qualifier), *(yyvsp[(2) - (2)].interm).param.type)) + context->recover(); + if (context->paramErrorCheck((yyvsp[(2) - (2)].interm).line, EvqTemporary, (yyvsp[(1) - (2)].interm.qualifier), (yyval.interm).param.type)) + context->recover(); + } + break; + + case 86: + + { + (yyval.interm.qualifier) = EvqIn; + } + break; + + case 87: + + { + (yyval.interm.qualifier) = EvqIn; + } + break; + + case 88: + + { + (yyval.interm.qualifier) = EvqOut; + } + break; + + case 89: + + { + (yyval.interm.qualifier) = EvqInOut; + } + break; + + case 90: + + { + TParameter param = { 0, new TType((yyvsp[(1) - (1)].interm.type)) }; + (yyval.interm).param = param; + } + break; + + case 91: + + { + (yyval.interm) = (yyvsp[(1) - (1)].interm); + } + break; + + case 92: + + { + if ((yyvsp[(1) - (3)].interm).type.type == EbtInvariant && !(yyvsp[(3) - (3)].lex).symbol) + { + context->error((yyvsp[(3) - (3)].lex).line, "undeclared identifier declared as invariant", (yyvsp[(3) - (3)].lex).string->c_str()); + context->recover(); + } + + TIntermSymbol* symbol = context->intermediate.addSymbol(0, *(yyvsp[(3) - (3)].lex).string, TType((yyvsp[(1) - (3)].interm).type), (yyvsp[(3) - (3)].lex).line); + (yyval.interm).intermAggregate = context->intermediate.growAggregate((yyvsp[(1) - (3)].interm).intermNode, symbol, (yyvsp[(3) - (3)].lex).line); + + if (context->structQualifierErrorCheck((yyvsp[(3) - (3)].lex).line, (yyval.interm).type)) + context->recover(); + + if (context->nonInitConstErrorCheck((yyvsp[(3) - (3)].lex).line, *(yyvsp[(3) - (3)].lex).string, (yyval.interm).type, false)) + context->recover(); + + TVariable* variable = 0; + if (context->nonInitErrorCheck((yyvsp[(3) - (3)].lex).line, *(yyvsp[(3) - (3)].lex).string, (yyval.interm).type, variable)) + context->recover(); + if (symbol && variable) + symbol->setId(variable->getUniqueId()); + } + break; + + case 93: + + { + if (context->structQualifierErrorCheck((yyvsp[(3) - (5)].lex).line, (yyvsp[(1) - (5)].interm).type)) + context->recover(); + + if (context->nonInitConstErrorCheck((yyvsp[(3) - (5)].lex).line, *(yyvsp[(3) - (5)].lex).string, (yyvsp[(1) - (5)].interm).type, true)) + context->recover(); + + (yyval.interm) = (yyvsp[(1) - (5)].interm); + + if (context->arrayTypeErrorCheck((yyvsp[(4) - (5)].lex).line, (yyvsp[(1) - (5)].interm).type) || context->arrayQualifierErrorCheck((yyvsp[(4) - (5)].lex).line, (yyvsp[(1) - (5)].interm).type)) + context->recover(); + else { + (yyvsp[(1) - (5)].interm).type.setArray(true); + TVariable* variable; + if (context->arrayErrorCheck((yyvsp[(4) - (5)].lex).line, *(yyvsp[(3) - (5)].lex).string, (yyvsp[(1) - (5)].interm).type, variable)) + context->recover(); + } + } + break; + + case 94: + + { + if (context->structQualifierErrorCheck((yyvsp[(3) - (6)].lex).line, (yyvsp[(1) - (6)].interm).type)) + context->recover(); + + if (context->nonInitConstErrorCheck((yyvsp[(3) - (6)].lex).line, *(yyvsp[(3) - (6)].lex).string, (yyvsp[(1) - (6)].interm).type, true)) + context->recover(); + + (yyval.interm) = (yyvsp[(1) - (6)].interm); + + if (context->arrayTypeErrorCheck((yyvsp[(4) - (6)].lex).line, (yyvsp[(1) - (6)].interm).type) || context->arrayQualifierErrorCheck((yyvsp[(4) - (6)].lex).line, (yyvsp[(1) - (6)].interm).type)) + context->recover(); + else { + int size; + if (context->arraySizeErrorCheck((yyvsp[(4) - (6)].lex).line, (yyvsp[(5) - (6)].interm.intermTypedNode), size)) + context->recover(); + (yyvsp[(1) - (6)].interm).type.setArray(true, size); + TVariable* variable = 0; + if (context->arrayErrorCheck((yyvsp[(4) - (6)].lex).line, *(yyvsp[(3) - (6)].lex).string, (yyvsp[(1) - (6)].interm).type, variable)) + context->recover(); + TType type = TType((yyvsp[(1) - (6)].interm).type); + type.setArraySize(size); + (yyval.interm).intermAggregate = context->intermediate.growAggregate((yyvsp[(1) - (6)].interm).intermNode, context->intermediate.addSymbol(variable ? variable->getUniqueId() : 0, *(yyvsp[(3) - (6)].lex).string, type, (yyvsp[(3) - (6)].lex).line), (yyvsp[(3) - (6)].lex).line); + } + } + break; + + case 95: + + { + if (context->structQualifierErrorCheck((yyvsp[(3) - (5)].lex).line, (yyvsp[(1) - (5)].interm).type)) + context->recover(); + + (yyval.interm) = (yyvsp[(1) - (5)].interm); + + TIntermNode* intermNode; + if (!context->executeInitializer((yyvsp[(3) - (5)].lex).line, *(yyvsp[(3) - (5)].lex).string, (yyvsp[(1) - (5)].interm).type, (yyvsp[(5) - (5)].interm.intermTypedNode), intermNode)) { + // + // build the intermediate representation + // + if (intermNode) + (yyval.interm).intermAggregate = context->intermediate.growAggregate((yyvsp[(1) - (5)].interm).intermNode, intermNode, (yyvsp[(4) - (5)].lex).line); + else + (yyval.interm).intermAggregate = (yyvsp[(1) - (5)].interm).intermAggregate; + } else { + context->recover(); + (yyval.interm).intermAggregate = 0; + } + } + break; + + case 96: + + { + (yyval.interm).type = (yyvsp[(1) - (1)].interm.type); + (yyval.interm).intermAggregate = context->intermediate.makeAggregate(context->intermediate.addSymbol(0, "", TType((yyvsp[(1) - (1)].interm.type)), (yyvsp[(1) - (1)].interm.type).line), (yyvsp[(1) - (1)].interm.type).line); + } + break; + + case 97: + + { + TIntermSymbol* symbol = context->intermediate.addSymbol(0, *(yyvsp[(2) - (2)].lex).string, TType((yyvsp[(1) - (2)].interm.type)), (yyvsp[(2) - (2)].lex).line); + (yyval.interm).intermAggregate = context->intermediate.makeAggregate(symbol, (yyvsp[(2) - (2)].lex).line); + + if (context->structQualifierErrorCheck((yyvsp[(2) - (2)].lex).line, (yyval.interm).type)) + context->recover(); + + if (context->nonInitConstErrorCheck((yyvsp[(2) - (2)].lex).line, *(yyvsp[(2) - (2)].lex).string, (yyval.interm).type, false)) + context->recover(); + + (yyval.interm).type = (yyvsp[(1) - (2)].interm.type); + + TVariable* variable = 0; + if (context->nonInitErrorCheck((yyvsp[(2) - (2)].lex).line, *(yyvsp[(2) - (2)].lex).string, (yyval.interm).type, variable)) + context->recover(); + if (variable && symbol) + symbol->setId(variable->getUniqueId()); + } + break; + + case 98: + + { + context->error((yyvsp[(2) - (4)].lex).line, "unsized array declarations not supported", (yyvsp[(2) - (4)].lex).string->c_str()); + context->recover(); + + TIntermSymbol* symbol = context->intermediate.addSymbol(0, *(yyvsp[(2) - (4)].lex).string, TType((yyvsp[(1) - (4)].interm.type)), (yyvsp[(2) - (4)].lex).line); + (yyval.interm).intermAggregate = context->intermediate.makeAggregate(symbol, (yyvsp[(2) - (4)].lex).line); + (yyval.interm).type = (yyvsp[(1) - (4)].interm.type); + } + break; + + case 99: + + { + TType type = TType((yyvsp[(1) - (5)].interm.type)); + int size; + if (context->arraySizeErrorCheck((yyvsp[(2) - (5)].lex).line, (yyvsp[(4) - (5)].interm.intermTypedNode), size)) + context->recover(); + type.setArraySize(size); + TIntermSymbol* symbol = context->intermediate.addSymbol(0, *(yyvsp[(2) - (5)].lex).string, type, (yyvsp[(2) - (5)].lex).line); + (yyval.interm).intermAggregate = context->intermediate.makeAggregate(symbol, (yyvsp[(2) - (5)].lex).line); + + if (context->structQualifierErrorCheck((yyvsp[(2) - (5)].lex).line, (yyvsp[(1) - (5)].interm.type))) + context->recover(); + + if (context->nonInitConstErrorCheck((yyvsp[(2) - (5)].lex).line, *(yyvsp[(2) - (5)].lex).string, (yyvsp[(1) - (5)].interm.type), true)) + context->recover(); + + (yyval.interm).type = (yyvsp[(1) - (5)].interm.type); + + if (context->arrayTypeErrorCheck((yyvsp[(3) - (5)].lex).line, (yyvsp[(1) - (5)].interm.type)) || context->arrayQualifierErrorCheck((yyvsp[(3) - (5)].lex).line, (yyvsp[(1) - (5)].interm.type))) + context->recover(); + else { + int size; + if (context->arraySizeErrorCheck((yyvsp[(3) - (5)].lex).line, (yyvsp[(4) - (5)].interm.intermTypedNode), size)) + context->recover(); + + (yyvsp[(1) - (5)].interm.type).setArray(true, size); + TVariable* variable = 0; + if (context->arrayErrorCheck((yyvsp[(3) - (5)].lex).line, *(yyvsp[(2) - (5)].lex).string, (yyvsp[(1) - (5)].interm.type), variable)) + context->recover(); + if (variable && symbol) + symbol->setId(variable->getUniqueId()); + } + } + break; + + case 100: + + { + if (context->structQualifierErrorCheck((yyvsp[(2) - (4)].lex).line, (yyvsp[(1) - (4)].interm.type))) + context->recover(); + + (yyval.interm).type = (yyvsp[(1) - (4)].interm.type); + + TIntermNode* intermNode; + if (!context->executeInitializer((yyvsp[(2) - (4)].lex).line, *(yyvsp[(2) - (4)].lex).string, (yyvsp[(1) - (4)].interm.type), (yyvsp[(4) - (4)].interm.intermTypedNode), intermNode)) { + // + // Build intermediate representation + // + if(intermNode) + (yyval.interm).intermAggregate = context->intermediate.makeAggregate(intermNode, (yyvsp[(3) - (4)].lex).line); + else + (yyval.interm).intermAggregate = 0; + } else { + context->recover(); + (yyval.interm).intermAggregate = 0; + } + } + break; + + case 101: + + { + VERTEX_ONLY("invariant declaration", (yyvsp[(1) - (2)].lex).line); + if (context->globalErrorCheck((yyvsp[(1) - (2)].lex).line, context->symbolTable.atGlobalLevel(), "invariant varying")) + context->recover(); + (yyval.interm).type.setBasic(EbtInvariant, EvqInvariantVaryingOut, (yyvsp[(2) - (2)].lex).line); + if (!(yyvsp[(2) - (2)].lex).symbol) + { + context->error((yyvsp[(2) - (2)].lex).line, "undeclared identifier declared as invariant", (yyvsp[(2) - (2)].lex).string->c_str()); + context->recover(); + + (yyval.interm).intermAggregate = 0; + } + else + { + TIntermSymbol *symbol = context->intermediate.addSymbol(0, *(yyvsp[(2) - (2)].lex).string, TType((yyval.interm).type), (yyvsp[(2) - (2)].lex).line); + (yyval.interm).intermAggregate = context->intermediate.makeAggregate(symbol, (yyvsp[(2) - (2)].lex).line); + } + } + break; + + case 102: + + { + (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type); + + if ((yyvsp[(1) - (1)].interm.type).array) { + context->error((yyvsp[(1) - (1)].interm.type).line, "not supported", "first-class array"); + context->recover(); + (yyvsp[(1) - (1)].interm.type).setArray(false); + } + } + break; + + case 103: + + { + if ((yyvsp[(2) - (2)].interm.type).array) { + context->error((yyvsp[(2) - (2)].interm.type).line, "not supported", "first-class array"); + context->recover(); + (yyvsp[(2) - (2)].interm.type).setArray(false); + } + + if ((yyvsp[(1) - (2)].interm.type).qualifier == EvqAttribute && + ((yyvsp[(2) - (2)].interm.type).type == EbtBool || (yyvsp[(2) - (2)].interm.type).type == EbtInt)) { + context->error((yyvsp[(2) - (2)].interm.type).line, "cannot be bool or int", getQualifierString((yyvsp[(1) - (2)].interm.type).qualifier)); + context->recover(); + } + if (((yyvsp[(1) - (2)].interm.type).qualifier == EvqVaryingIn || (yyvsp[(1) - (2)].interm.type).qualifier == EvqVaryingOut) && + ((yyvsp[(2) - (2)].interm.type).type == EbtBool || (yyvsp[(2) - (2)].interm.type).type == EbtInt)) { + context->error((yyvsp[(2) - (2)].interm.type).line, "cannot be bool or int", getQualifierString((yyvsp[(1) - (2)].interm.type).qualifier)); + context->recover(); + } + (yyval.interm.type) = (yyvsp[(2) - (2)].interm.type); + (yyval.interm.type).qualifier = (yyvsp[(1) - (2)].interm.type).qualifier; + } + break; + + case 104: + + { + (yyval.interm.type).setBasic(EbtVoid, EvqConst, (yyvsp[(1) - (1)].lex).line); + } + break; + + case 105: + + { + VERTEX_ONLY("attribute", (yyvsp[(1) - (1)].lex).line); + if (context->globalErrorCheck((yyvsp[(1) - (1)].lex).line, context->symbolTable.atGlobalLevel(), "attribute")) + context->recover(); + (yyval.interm.type).setBasic(EbtVoid, EvqAttribute, (yyvsp[(1) - (1)].lex).line); + } + break; + + case 106: + + { + if (context->globalErrorCheck((yyvsp[(1) - (1)].lex).line, context->symbolTable.atGlobalLevel(), "varying")) + context->recover(); + if (context->shaderType == SH_VERTEX_SHADER) + (yyval.interm.type).setBasic(EbtVoid, EvqVaryingOut, (yyvsp[(1) - (1)].lex).line); + else + (yyval.interm.type).setBasic(EbtVoid, EvqVaryingIn, (yyvsp[(1) - (1)].lex).line); + } + break; + + case 107: + + { + if (context->globalErrorCheck((yyvsp[(1) - (2)].lex).line, context->symbolTable.atGlobalLevel(), "invariant varying")) + context->recover(); + if (context->shaderType == SH_VERTEX_SHADER) + (yyval.interm.type).setBasic(EbtVoid, EvqInvariantVaryingOut, (yyvsp[(1) - (2)].lex).line); + else + (yyval.interm.type).setBasic(EbtVoid, EvqInvariantVaryingIn, (yyvsp[(1) - (2)].lex).line); + } + break; + + case 108: + + { + if (context->globalErrorCheck((yyvsp[(1) - (1)].lex).line, context->symbolTable.atGlobalLevel(), "uniform")) + context->recover(); + (yyval.interm.type).setBasic(EbtVoid, EvqUniform, (yyvsp[(1) - (1)].lex).line); + } + break; + + case 109: + + { + (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type); + + if ((yyval.interm.type).precision == EbpUndefined) { + (yyval.interm.type).precision = context->symbolTable.getDefaultPrecision((yyvsp[(1) - (1)].interm.type).type); + if (context->precisionErrorCheck((yyvsp[(1) - (1)].interm.type).line, (yyval.interm.type).precision, (yyvsp[(1) - (1)].interm.type).type)) { + context->recover(); + } + } + } + break; + + case 110: + + { + (yyval.interm.type) = (yyvsp[(2) - (2)].interm.type); + (yyval.interm.type).precision = (yyvsp[(1) - (2)].interm.precision); + } + break; + + case 111: + + { + (yyval.interm.precision) = EbpHigh; + } + break; + + case 112: + + { + (yyval.interm.precision) = EbpMedium; + } + break; + + case 113: + + { + (yyval.interm.precision) = EbpLow; + } + break; + + case 114: + + { + (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type); + } + break; + + case 115: + + { + (yyval.interm.type) = (yyvsp[(1) - (4)].interm.type); + + if (context->arrayTypeErrorCheck((yyvsp[(2) - (4)].lex).line, (yyvsp[(1) - (4)].interm.type))) + context->recover(); + else { + int size; + if (context->arraySizeErrorCheck((yyvsp[(2) - (4)].lex).line, (yyvsp[(3) - (4)].interm.intermTypedNode), size)) + context->recover(); + (yyval.interm.type).setArray(true, size); + } + } + break; + + case 116: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtVoid, qual, (yyvsp[(1) - (1)].lex).line); + } + break; + + case 117: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yyvsp[(1) - (1)].lex).line); + } + break; + + case 118: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtInt, qual, (yyvsp[(1) - (1)].lex).line); + } + break; + + case 119: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtBool, qual, (yyvsp[(1) - (1)].lex).line); + } + break; + + case 120: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yyvsp[(1) - (1)].lex).line); + (yyval.interm.type).setAggregate(2); + } + break; + + case 121: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yyvsp[(1) - (1)].lex).line); + (yyval.interm.type).setAggregate(3); + } + break; + + case 122: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yyvsp[(1) - (1)].lex).line); + (yyval.interm.type).setAggregate(4); + } + break; + + case 123: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtBool, qual, (yyvsp[(1) - (1)].lex).line); + (yyval.interm.type).setAggregate(2); + } + break; + + case 124: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtBool, qual, (yyvsp[(1) - (1)].lex).line); + (yyval.interm.type).setAggregate(3); + } + break; + + case 125: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtBool, qual, (yyvsp[(1) - (1)].lex).line); + (yyval.interm.type).setAggregate(4); + } + break; + + case 126: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtInt, qual, (yyvsp[(1) - (1)].lex).line); + (yyval.interm.type).setAggregate(2); + } + break; + + case 127: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtInt, qual, (yyvsp[(1) - (1)].lex).line); + (yyval.interm.type).setAggregate(3); + } + break; + + case 128: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtInt, qual, (yyvsp[(1) - (1)].lex).line); + (yyval.interm.type).setAggregate(4); + } + break; + + case 129: + + { + FRAG_VERT_ONLY("mat2", (yyvsp[(1) - (1)].lex).line); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yyvsp[(1) - (1)].lex).line); + (yyval.interm.type).setAggregate(2, true); + } + break; + + case 130: + + { + FRAG_VERT_ONLY("mat3", (yyvsp[(1) - (1)].lex).line); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yyvsp[(1) - (1)].lex).line); + (yyval.interm.type).setAggregate(3, true); + } + break; + + case 131: + + { + FRAG_VERT_ONLY("mat4", (yyvsp[(1) - (1)].lex).line); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yyvsp[(1) - (1)].lex).line); + (yyval.interm.type).setAggregate(4, true); + } + break; + + case 132: + + { + FRAG_VERT_ONLY("sampler2D", (yyvsp[(1) - (1)].lex).line); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtSampler2D, qual, (yyvsp[(1) - (1)].lex).line); + } + break; + + case 133: + + { + FRAG_VERT_ONLY("samplerCube", (yyvsp[(1) - (1)].lex).line); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtSamplerCube, qual, (yyvsp[(1) - (1)].lex).line); + } + break; + + case 134: + + { + FRAG_VERT_ONLY("struct", (yyvsp[(1) - (1)].interm.type).line); + (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type); + (yyval.interm.type).qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + } + break; + + case 135: + + { + // + // This is for user defined type names. The lexical phase looked up the + // type. + // + TType& structure = static_cast<TVariable*>((yyvsp[(1) - (1)].lex).symbol)->getType(); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtStruct, qual, (yyvsp[(1) - (1)].lex).line); + (yyval.interm.type).userDef = &structure; + } + break; + + case 136: + + { if (context->enterStructDeclaration((yyvsp[(2) - (3)].lex).line, *(yyvsp[(2) - (3)].lex).string)) context->recover(); } + break; + + case 137: + + { + if (context->reservedErrorCheck((yyvsp[(2) - (6)].lex).line, *(yyvsp[(2) - (6)].lex).string)) + context->recover(); + + TType* structure = new TType((yyvsp[(5) - (6)].interm.typeList), *(yyvsp[(2) - (6)].lex).string); + TVariable* userTypeDef = new TVariable((yyvsp[(2) - (6)].lex).string, *structure, true); + if (! context->symbolTable.insert(*userTypeDef)) { + context->error((yyvsp[(2) - (6)].lex).line, "redefinition", (yyvsp[(2) - (6)].lex).string->c_str(), "struct"); + context->recover(); + } + (yyval.interm.type).setBasic(EbtStruct, EvqTemporary, (yyvsp[(1) - (6)].lex).line); + (yyval.interm.type).userDef = structure; + context->exitStructDeclaration(); + } + break; + + case 138: + + { if (context->enterStructDeclaration((yyvsp[(2) - (2)].lex).line, *(yyvsp[(2) - (2)].lex).string)) context->recover(); } + break; + + case 139: + + { + TType* structure = new TType((yyvsp[(4) - (5)].interm.typeList), TString("")); + (yyval.interm.type).setBasic(EbtStruct, EvqTemporary, (yyvsp[(1) - (5)].lex).line); + (yyval.interm.type).userDef = structure; + context->exitStructDeclaration(); + } + break; + + case 140: + + { + (yyval.interm.typeList) = (yyvsp[(1) - (1)].interm.typeList); + } + break; + + case 141: + + { + (yyval.interm.typeList) = (yyvsp[(1) - (2)].interm.typeList); + for (unsigned int i = 0; i < (yyvsp[(2) - (2)].interm.typeList)->size(); ++i) { + for (unsigned int j = 0; j < (yyval.interm.typeList)->size(); ++j) { + if ((*(yyval.interm.typeList))[j].type->getFieldName() == (*(yyvsp[(2) - (2)].interm.typeList))[i].type->getFieldName()) { + context->error((*(yyvsp[(2) - (2)].interm.typeList))[i].line, "duplicate field name in structure:", "struct", (*(yyvsp[(2) - (2)].interm.typeList))[i].type->getFieldName().c_str()); + context->recover(); + } + } + (yyval.interm.typeList)->push_back((*(yyvsp[(2) - (2)].interm.typeList))[i]); + } + } + break; + + case 142: + + { + (yyval.interm.typeList) = (yyvsp[(2) - (3)].interm.typeList); + + if (context->voidErrorCheck((yyvsp[(1) - (3)].interm.type).line, (*(yyvsp[(2) - (3)].interm.typeList))[0].type->getFieldName(), (yyvsp[(1) - (3)].interm.type))) { + context->recover(); + } + for (unsigned int i = 0; i < (yyval.interm.typeList)->size(); ++i) { + // + // Careful not to replace already known aspects of type, like array-ness + // + TType* type = (*(yyval.interm.typeList))[i].type; + type->setBasicType((yyvsp[(1) - (3)].interm.type).type); + type->setNominalSize((yyvsp[(1) - (3)].interm.type).size); + type->setMatrix((yyvsp[(1) - (3)].interm.type).matrix); + type->setPrecision((yyvsp[(1) - (3)].interm.type).precision); + + // don't allow arrays of arrays + if (type->isArray()) { + if (context->arrayTypeErrorCheck((yyvsp[(1) - (3)].interm.type).line, (yyvsp[(1) - (3)].interm.type))) + context->recover(); + } + if ((yyvsp[(1) - (3)].interm.type).array) + type->setArraySize((yyvsp[(1) - (3)].interm.type).arraySize); + if ((yyvsp[(1) - (3)].interm.type).userDef) { + type->setStruct((yyvsp[(1) - (3)].interm.type).userDef->getStruct()); + type->setTypeName((yyvsp[(1) - (3)].interm.type).userDef->getTypeName()); + } + + if (context->structNestingErrorCheck((yyvsp[(1) - (3)].interm.type).line, *type)) { + context->recover(); + } + } + } + break; + + case 143: + + { + (yyval.interm.typeList) = NewPoolTTypeList(); + (yyval.interm.typeList)->push_back((yyvsp[(1) - (1)].interm.typeLine)); + } + break; + + case 144: + + { + (yyval.interm.typeList)->push_back((yyvsp[(3) - (3)].interm.typeLine)); + } + break; + + case 145: + + { + if (context->reservedErrorCheck((yyvsp[(1) - (1)].lex).line, *(yyvsp[(1) - (1)].lex).string)) + context->recover(); + + (yyval.interm.typeLine).type = new TType(EbtVoid, EbpUndefined); + (yyval.interm.typeLine).line = (yyvsp[(1) - (1)].lex).line; + (yyval.interm.typeLine).type->setFieldName(*(yyvsp[(1) - (1)].lex).string); + } + break; + + case 146: + + { + if (context->reservedErrorCheck((yyvsp[(1) - (4)].lex).line, *(yyvsp[(1) - (4)].lex).string)) + context->recover(); + + (yyval.interm.typeLine).type = new TType(EbtVoid, EbpUndefined); + (yyval.interm.typeLine).line = (yyvsp[(1) - (4)].lex).line; + (yyval.interm.typeLine).type->setFieldName(*(yyvsp[(1) - (4)].lex).string); + + int size; + if (context->arraySizeErrorCheck((yyvsp[(2) - (4)].lex).line, (yyvsp[(3) - (4)].interm.intermTypedNode), size)) + context->recover(); + (yyval.interm.typeLine).type->setArraySize(size); + } + break; + + case 147: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 148: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); } + break; + + case 149: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermAggregate); } + break; + + case 150: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); } + break; + + case 151: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); } + break; + + case 152: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); } + break; + + case 153: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); } + break; + + case 154: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); } + break; + + case 155: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); } + break; + + case 156: + + { (yyval.interm.intermAggregate) = 0; } + break; + + case 157: + + { context->symbolTable.push(); } + break; + + case 158: + + { context->symbolTable.pop(); } + break; + + case 159: + + { + if ((yyvsp[(3) - (5)].interm.intermAggregate) != 0) { + (yyvsp[(3) - (5)].interm.intermAggregate)->setOp(EOpSequence); + (yyvsp[(3) - (5)].interm.intermAggregate)->setEndLine((yyvsp[(5) - (5)].lex).line); + } + (yyval.interm.intermAggregate) = (yyvsp[(3) - (5)].interm.intermAggregate); + } + break; + + case 160: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); } + break; + + case 161: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); } + break; + + case 162: + + { context->symbolTable.push(); } + break; + + case 163: + + { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[(2) - (2)].interm.intermNode); } + break; + + case 164: + + { context->symbolTable.push(); } + break; + + case 165: + + { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[(2) - (2)].interm.intermNode); } + break; + + case 166: + + { + (yyval.interm.intermNode) = 0; + } + break; + + case 167: + + { + if ((yyvsp[(2) - (3)].interm.intermAggregate)) { + (yyvsp[(2) - (3)].interm.intermAggregate)->setOp(EOpSequence); + (yyvsp[(2) - (3)].interm.intermAggregate)->setEndLine((yyvsp[(3) - (3)].lex).line); + } + (yyval.interm.intermNode) = (yyvsp[(2) - (3)].interm.intermAggregate); + } + break; + + case 168: + + { + (yyval.interm.intermAggregate) = context->intermediate.makeAggregate((yyvsp[(1) - (1)].interm.intermNode), 0); + } + break; + + case 169: + + { + (yyval.interm.intermAggregate) = context->intermediate.growAggregate((yyvsp[(1) - (2)].interm.intermAggregate), (yyvsp[(2) - (2)].interm.intermNode), 0); + } + break; + + case 170: + + { (yyval.interm.intermNode) = 0; } + break; + + case 171: + + { (yyval.interm.intermNode) = static_cast<TIntermNode*>((yyvsp[(1) - (2)].interm.intermTypedNode)); } + break; + + case 172: + + { + if (context->boolErrorCheck((yyvsp[(1) - (5)].lex).line, (yyvsp[(3) - (5)].interm.intermTypedNode))) + context->recover(); + (yyval.interm.intermNode) = context->intermediate.addSelection((yyvsp[(3) - (5)].interm.intermTypedNode), (yyvsp[(5) - (5)].interm.nodePair), (yyvsp[(1) - (5)].lex).line); + } + break; + + case 173: + + { + (yyval.interm.nodePair).node1 = (yyvsp[(1) - (3)].interm.intermNode); + (yyval.interm.nodePair).node2 = (yyvsp[(3) - (3)].interm.intermNode); + } + break; + + case 174: + + { + (yyval.interm.nodePair).node1 = (yyvsp[(1) - (1)].interm.intermNode); + (yyval.interm.nodePair).node2 = 0; + } + break; + + case 175: + + { + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); + if (context->boolErrorCheck((yyvsp[(1) - (1)].interm.intermTypedNode)->getLine(), (yyvsp[(1) - (1)].interm.intermTypedNode))) + context->recover(); + } + break; + + case 176: + + { + TIntermNode* intermNode; + if (context->structQualifierErrorCheck((yyvsp[(2) - (4)].lex).line, (yyvsp[(1) - (4)].interm.type))) + context->recover(); + if (context->boolErrorCheck((yyvsp[(2) - (4)].lex).line, (yyvsp[(1) - (4)].interm.type))) + context->recover(); + + if (!context->executeInitializer((yyvsp[(2) - (4)].lex).line, *(yyvsp[(2) - (4)].lex).string, (yyvsp[(1) - (4)].interm.type), (yyvsp[(4) - (4)].interm.intermTypedNode), intermNode)) + (yyval.interm.intermTypedNode) = (yyvsp[(4) - (4)].interm.intermTypedNode); + else { + context->recover(); + (yyval.interm.intermTypedNode) = 0; + } + } + break; + + case 177: + + { context->symbolTable.push(); ++context->loopNestingLevel; } + break; + + case 178: + + { + context->symbolTable.pop(); + (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopWhile, 0, (yyvsp[(4) - (6)].interm.intermTypedNode), 0, (yyvsp[(6) - (6)].interm.intermNode), (yyvsp[(1) - (6)].lex).line); + --context->loopNestingLevel; + } + break; + + case 179: + + { ++context->loopNestingLevel; } + break; + + case 180: + + { + if (context->boolErrorCheck((yyvsp[(8) - (8)].lex).line, (yyvsp[(6) - (8)].interm.intermTypedNode))) + context->recover(); + + (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopDoWhile, 0, (yyvsp[(6) - (8)].interm.intermTypedNode), 0, (yyvsp[(3) - (8)].interm.intermNode), (yyvsp[(4) - (8)].lex).line); + --context->loopNestingLevel; + } + break; + + case 181: + + { context->symbolTable.push(); ++context->loopNestingLevel; } + break; + + case 182: + + { + context->symbolTable.pop(); + (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopFor, (yyvsp[(4) - (7)].interm.intermNode), reinterpret_cast<TIntermTyped*>((yyvsp[(5) - (7)].interm.nodePair).node1), reinterpret_cast<TIntermTyped*>((yyvsp[(5) - (7)].interm.nodePair).node2), (yyvsp[(7) - (7)].interm.intermNode), (yyvsp[(1) - (7)].lex).line); + --context->loopNestingLevel; + } + break; + + case 183: + + { + (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); + } + break; + + case 184: + + { + (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); + } + break; + + case 185: + + { + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); + } + break; + + case 186: + + { + (yyval.interm.intermTypedNode) = 0; + } + break; + + case 187: + + { + (yyval.interm.nodePair).node1 = (yyvsp[(1) - (2)].interm.intermTypedNode); + (yyval.interm.nodePair).node2 = 0; + } + break; + + case 188: + + { + (yyval.interm.nodePair).node1 = (yyvsp[(1) - (3)].interm.intermTypedNode); + (yyval.interm.nodePair).node2 = (yyvsp[(3) - (3)].interm.intermTypedNode); + } + break; + + case 189: + + { + if (context->loopNestingLevel <= 0) { + context->error((yyvsp[(1) - (2)].lex).line, "continue statement only allowed in loops", ""); + context->recover(); + } + (yyval.interm.intermNode) = context->intermediate.addBranch(EOpContinue, (yyvsp[(1) - (2)].lex).line); + } + break; + + case 190: + + { + if (context->loopNestingLevel <= 0) { + context->error((yyvsp[(1) - (2)].lex).line, "break statement only allowed in loops", ""); + context->recover(); + } + (yyval.interm.intermNode) = context->intermediate.addBranch(EOpBreak, (yyvsp[(1) - (2)].lex).line); + } + break; + + case 191: + + { + (yyval.interm.intermNode) = context->intermediate.addBranch(EOpReturn, (yyvsp[(1) - (2)].lex).line); + if (context->currentFunctionType->getBasicType() != EbtVoid) { + context->error((yyvsp[(1) - (2)].lex).line, "non-void function must return a value", "return"); + context->recover(); + } + } + break; + + case 192: + + { + (yyval.interm.intermNode) = context->intermediate.addBranch(EOpReturn, (yyvsp[(2) - (3)].interm.intermTypedNode), (yyvsp[(1) - (3)].lex).line); + context->functionReturnsValue = true; + if (context->currentFunctionType->getBasicType() == EbtVoid) { + context->error((yyvsp[(1) - (3)].lex).line, "void function cannot return a value", "return"); + context->recover(); + } else if (*(context->currentFunctionType) != (yyvsp[(2) - (3)].interm.intermTypedNode)->getType()) { + context->error((yyvsp[(1) - (3)].lex).line, "function return is not matching type:", "return"); + context->recover(); + } + } + break; + + case 193: + + { + FRAG_ONLY("discard", (yyvsp[(1) - (2)].lex).line); + (yyval.interm.intermNode) = context->intermediate.addBranch(EOpKill, (yyvsp[(1) - (2)].lex).line); + } + break; + + case 194: + + { + (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); + context->treeRoot = (yyval.interm.intermNode); + } + break; + + case 195: + + { + (yyval.interm.intermNode) = context->intermediate.growAggregate((yyvsp[(1) - (2)].interm.intermNode), (yyvsp[(2) - (2)].interm.intermNode), 0); + context->treeRoot = (yyval.interm.intermNode); + } + break; + + case 196: + + { + (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); + } + break; + + case 197: + + { + (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); + } + break; + + case 198: + + { + TFunction* function = (yyvsp[(1) - (1)].interm).function; + + const TSymbol *builtIn = context->symbolTable.findBuiltIn(function->getMangledName()); + + if (builtIn) + { + context->error((yyvsp[(1) - (1)].interm).line, "built-in functions cannot be redefined", function->getName().c_str()); + context->recover(); + } + + TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find(function->getMangledName())); + // + // Note: 'prevDec' could be 'function' if this is the first time we've seen function + // as it would have just been put in the symbol table. Otherwise, we're looking up + // an earlier occurance. + // + if (prevDec->isDefined()) { + // + // Then this function already has a body. + // + context->error((yyvsp[(1) - (1)].interm).line, "function already has a body", function->getName().c_str()); + context->recover(); + } + prevDec->setDefined(); + + // + // Raise error message if main function takes any parameters or return anything other than void + // + if (function->getName() == "main") { + if (function->getParamCount() > 0) { + context->error((yyvsp[(1) - (1)].interm).line, "function cannot take any parameter(s)", function->getName().c_str()); + context->recover(); + } + if (function->getReturnType().getBasicType() != EbtVoid) { + context->error((yyvsp[(1) - (1)].interm).line, "", function->getReturnType().getBasicString(), "main function cannot return a value"); + context->recover(); + } + } + + // + // Remember the return type for later checking for RETURN statements. + // + context->currentFunctionType = &(prevDec->getReturnType()); + context->functionReturnsValue = false; + + // + // Insert parameters into the symbol table. + // If the parameter has no name, it's not an error, just don't insert it + // (could be used for unused args). + // + // Also, accumulate the list of parameters into the HIL, so lower level code + // knows where to find parameters. + // + TIntermAggregate* paramNodes = new TIntermAggregate; + for (int i = 0; i < function->getParamCount(); i++) { + const TParameter& param = function->getParam(i); + if (param.name != 0) { + TVariable *variable = new TVariable(param.name, *param.type); + // + // Insert the parameters with name in the symbol table. + // + if (! context->symbolTable.insert(*variable)) { + context->error((yyvsp[(1) - (1)].interm).line, "redefinition", variable->getName().c_str()); + context->recover(); + delete variable; + } + + // + // Add the parameter to the HIL + // + paramNodes = context->intermediate.growAggregate( + paramNodes, + context->intermediate.addSymbol(variable->getUniqueId(), + variable->getName(), + variable->getType(), (yyvsp[(1) - (1)].interm).line), + (yyvsp[(1) - (1)].interm).line); + } else { + paramNodes = context->intermediate.growAggregate(paramNodes, context->intermediate.addSymbol(0, "", *param.type, (yyvsp[(1) - (1)].interm).line), (yyvsp[(1) - (1)].interm).line); + } + } + context->intermediate.setAggregateOperator(paramNodes, EOpParameters, (yyvsp[(1) - (1)].interm).line); + (yyvsp[(1) - (1)].interm).intermAggregate = paramNodes; + context->loopNestingLevel = 0; + } + break; + + case 199: + + { + //?? Check that all paths return a value if return type != void ? + // May be best done as post process phase on intermediate code + if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) { + context->error((yyvsp[(1) - (3)].interm).line, "function does not return a value:", "", (yyvsp[(1) - (3)].interm).function->getName().c_str()); + context->recover(); + } + + (yyval.interm.intermNode) = context->intermediate.growAggregate((yyvsp[(1) - (3)].interm).intermAggregate, (yyvsp[(3) - (3)].interm.intermNode), 0); + context->intermediate.setAggregateOperator((yyval.interm.intermNode), EOpFunction, (yyvsp[(1) - (3)].interm).line); + (yyval.interm.intermNode)->getAsAggregate()->setName((yyvsp[(1) - (3)].interm).function->getMangledName().c_str()); + (yyval.interm.intermNode)->getAsAggregate()->setType((yyvsp[(1) - (3)].interm).function->getReturnType()); + + // store the pragma information for debug and optimize and other vendor specific + // information. This information can be queried from the parse tree + (yyval.interm.intermNode)->getAsAggregate()->setOptimize(context->pragma().optimize); + (yyval.interm.intermNode)->getAsAggregate()->setDebug(context->pragma().debug); + + if ((yyvsp[(3) - (3)].interm.intermNode) && (yyvsp[(3) - (3)].interm.intermNode)->getAsAggregate()) + (yyval.interm.intermNode)->getAsAggregate()->setEndLine((yyvsp[(3) - (3)].interm.intermNode)->getAsAggregate()->getEndLine()); + + context->symbolTable.pop(); + } + break; + + + + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (context, YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (context, yymsg); + } + else + { + yyerror (context, YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, context); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp, context); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (context, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, context); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, context); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + + + +int glslang_parse(TParseContext* context) { + return yyparse(context); +} + +
diff --git a/src/GLES2/compiler/glslang_tab.h b/src/GLES2/compiler/glslang_tab.h new file mode 100644 index 0000000..5227361 --- /dev/null +++ b/src/GLES2/compiler/glslang_tab.h
@@ -0,0 +1,182 @@ +/* A Bison parser, made by GNU Bison 2.4.2. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2006, 2009-2010 Free Software + Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + INVARIANT = 258, + HIGH_PRECISION = 259, + MEDIUM_PRECISION = 260, + LOW_PRECISION = 261, + PRECISION = 262, + ATTRIBUTE = 263, + CONST_QUAL = 264, + BOOL_TYPE = 265, + FLOAT_TYPE = 266, + INT_TYPE = 267, + BREAK = 268, + CONTINUE = 269, + DO = 270, + ELSE = 271, + FOR = 272, + IF = 273, + DISCARD = 274, + RETURN = 275, + BVEC2 = 276, + BVEC3 = 277, + BVEC4 = 278, + IVEC2 = 279, + IVEC3 = 280, + IVEC4 = 281, + VEC2 = 282, + VEC3 = 283, + VEC4 = 284, + MATRIX2 = 285, + MATRIX3 = 286, + MATRIX4 = 287, + IN_QUAL = 288, + OUT_QUAL = 289, + INOUT_QUAL = 290, + UNIFORM = 291, + VARYING = 292, + STRUCT = 293, + VOID_TYPE = 294, + WHILE = 295, + SAMPLER2D = 296, + SAMPLERCUBE = 297, + IDENTIFIER = 298, + TYPE_NAME = 299, + FLOATCONSTANT = 300, + INTCONSTANT = 301, + BOOLCONSTANT = 302, + FIELD_SELECTION = 303, + LEFT_OP = 304, + RIGHT_OP = 305, + INC_OP = 306, + DEC_OP = 307, + LE_OP = 308, + GE_OP = 309, + EQ_OP = 310, + NE_OP = 311, + AND_OP = 312, + OR_OP = 313, + XOR_OP = 314, + MUL_ASSIGN = 315, + DIV_ASSIGN = 316, + ADD_ASSIGN = 317, + MOD_ASSIGN = 318, + LEFT_ASSIGN = 319, + RIGHT_ASSIGN = 320, + AND_ASSIGN = 321, + XOR_ASSIGN = 322, + OR_ASSIGN = 323, + SUB_ASSIGN = 324, + LEFT_PAREN = 325, + RIGHT_PAREN = 326, + LEFT_BRACKET = 327, + RIGHT_BRACKET = 328, + LEFT_BRACE = 329, + RIGHT_BRACE = 330, + DOT = 331, + COMMA = 332, + COLON = 333, + EQUAL = 334, + SEMICOLON = 335, + BANG = 336, + DASH = 337, + TILDE = 338, + PLUS = 339, + STAR = 340, + SLASH = 341, + PERCENT = 342, + LEFT_ANGLE = 343, + RIGHT_ANGLE = 344, + VERTICAL_BAR = 345, + CARET = 346, + AMPERSAND = 347, + QUESTION = 348 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + + + struct { + TSourceLoc line; + union { + TString *string; + float f; + int i; + bool b; + }; + TSymbol* symbol; + } lex; + struct { + TSourceLoc line; + TOperator op; + union { + TIntermNode* intermNode; + TIntermNodePair nodePair; + TIntermTyped* intermTypedNode; + TIntermAggregate* intermAggregate; + }; + union { + TPublicType type; + TPrecision precision; + TQualifier qualifier; + TFunction* function; + TParameter param; + TTypeLine typeLine; + TTypeList* typeList; + }; + } interm; + + + +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +
diff --git a/src/GLES2/compiler/intermOut.cpp b/src/GLES2/compiler/intermOut.cpp new file mode 100644 index 0000000..798a69a --- /dev/null +++ b/src/GLES2/compiler/intermOut.cpp
@@ -0,0 +1,417 @@ +// +// 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/localintermediate.h" + +// +// Two purposes: +// 1. Show an example of how to iterate tree. Functions can +// also directly call Traverse() on children themselves to +// have finer grained control over the process than shown here. +// See the last function for how to get started. +// 2. Print out a text based description of the tree. +// + +// +// Use this class to carry along data from node to node in +// the traversal +// +class TOutputTraverser : public TIntermTraverser { +public: + TOutputTraverser(TInfoSinkBase& i) : sink(i) { } + TInfoSinkBase& sink; + +protected: + void visitSymbol(TIntermSymbol*); + void visitConstantUnion(TIntermConstantUnion*); + bool visitBinary(Visit visit, TIntermBinary*); + bool visitUnary(Visit visit, TIntermUnary*); + bool visitSelection(Visit visit, TIntermSelection*); + bool visitAggregate(Visit visit, TIntermAggregate*); + bool visitLoop(Visit visit, TIntermLoop*); + bool visitBranch(Visit visit, TIntermBranch*); +}; + +TString TType::getCompleteString() const +{ + TStringStream stream; + + if (qualifier != EvqTemporary && qualifier != EvqGlobal) + stream << getQualifierString() << " " << getPrecisionString() << " "; + if (array) + stream << "array of "; + if (matrix) + stream << size << "X" << size << " matrix of "; + else if (size > 1) + stream << size << "-component vector of "; + + stream << getBasicString(); + return stream.str(); +} + +// +// Helper functions for printing, not part of traversing. +// + +void OutputTreeText(TInfoSinkBase& sink, TIntermNode* node, const int depth) +{ + int i; + + sink.location(node->getLine()); + + for (i = 0; i < depth; ++i) + sink << " "; +} + +// +// The rest of the file are the traversal functions. The last one +// is the one that starts the traversal. +// +// Return true from interior nodes to have the external traversal +// continue on to children. If you process children yourself, +// return false. +// + +void TOutputTraverser::visitSymbol(TIntermSymbol* node) +{ + OutputTreeText(sink, node, depth); + + sink << "'" << node->getSymbol() << "' "; + sink << "(" << node->getCompleteString() << ")\n"; +} + +bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary* node) +{ + TInfoSinkBase& out = sink; + + OutputTreeText(out, node, depth); + + switch (node->getOp()) { + case EOpAssign: out << "move second child to first child"; break; + case EOpInitialize: out << "initialize first child with second child"; break; + case EOpAddAssign: out << "add second child into first child"; break; + case EOpSubAssign: out << "subtract second child into first child"; break; + case EOpMulAssign: out << "multiply second child into first child"; break; + case EOpVectorTimesMatrixAssign: out << "matrix mult second child into first child"; break; + case EOpVectorTimesScalarAssign: out << "vector scale second child into first child"; break; + case EOpMatrixTimesScalarAssign: out << "matrix scale second child into first child"; break; + case EOpMatrixTimesMatrixAssign: out << "matrix mult second child into first child"; break; + case EOpDivAssign: out << "divide second child into first child"; break; + case EOpIndexDirect: out << "direct index"; break; + case EOpIndexIndirect: out << "indirect index"; break; + case EOpIndexDirectStruct: out << "direct index for structure"; break; + case EOpVectorSwizzle: out << "vector swizzle"; break; + + case EOpAdd: out << "add"; break; + case EOpSub: out << "subtract"; break; + case EOpMul: out << "component-wise multiply"; break; + case EOpDiv: out << "divide"; break; + case EOpEqual: out << "Compare Equal"; break; + case EOpNotEqual: out << "Compare Not Equal"; break; + case EOpLessThan: out << "Compare Less Than"; break; + case EOpGreaterThan: out << "Compare Greater Than"; break; + case EOpLessThanEqual: out << "Compare Less Than or Equal"; break; + case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break; + + case EOpVectorTimesScalar: out << "vector-scale"; break; + case EOpVectorTimesMatrix: out << "vector-times-matrix"; break; + case EOpMatrixTimesVector: out << "matrix-times-vector"; break; + case EOpMatrixTimesScalar: out << "matrix-scale"; break; + case EOpMatrixTimesMatrix: out << "matrix-multiply"; break; + + case EOpLogicalOr: out << "logical-or"; break; + case EOpLogicalXor: out << "logical-xor"; break; + case EOpLogicalAnd: out << "logical-and"; break; + default: out << "<unknown op>"; + } + + out << " (" << node->getCompleteString() << ")"; + + out << "\n"; + + return true; +} + +bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary* node) +{ + TInfoSinkBase& out = sink; + + OutputTreeText(out, node, depth); + + switch (node->getOp()) { + case EOpNegative: out << "Negate value"; break; + case EOpVectorLogicalNot: + case EOpLogicalNot: out << "Negate conditional"; break; + + case EOpPostIncrement: out << "Post-Increment"; break; + case EOpPostDecrement: out << "Post-Decrement"; break; + case EOpPreIncrement: out << "Pre-Increment"; break; + case EOpPreDecrement: out << "Pre-Decrement"; break; + + case EOpConvIntToBool: out << "Convert int to bool"; break; + case EOpConvFloatToBool:out << "Convert float to bool";break; + case EOpConvBoolToFloat:out << "Convert bool to float";break; + case EOpConvIntToFloat: out << "Convert int to float"; break; + case EOpConvFloatToInt: out << "Convert float to int"; break; + case EOpConvBoolToInt: out << "Convert bool to int"; break; + + case EOpRadians: out << "radians"; break; + case EOpDegrees: out << "degrees"; break; + case EOpSin: out << "sine"; break; + case EOpCos: out << "cosine"; break; + case EOpTan: out << "tangent"; break; + case EOpAsin: out << "arc sine"; break; + case EOpAcos: out << "arc cosine"; break; + case EOpAtan: out << "arc tangent"; break; + + case EOpExp: out << "exp"; break; + case EOpLog: out << "log"; break; + case EOpExp2: out << "exp2"; break; + case EOpLog2: out << "log2"; break; + case EOpSqrt: out << "sqrt"; break; + case EOpInverseSqrt: out << "inverse sqrt"; break; + + case EOpAbs: out << "Absolute value"; break; + case EOpSign: out << "Sign"; break; + case EOpFloor: out << "Floor"; break; + case EOpCeil: out << "Ceiling"; break; + case EOpFract: out << "Fraction"; break; + + case EOpLength: out << "length"; break; + case EOpNormalize: out << "normalize"; break; + // case EOpDPdx: out << "dPdx"; break; + // case EOpDPdy: out << "dPdy"; break; + // case EOpFwidth: out << "fwidth"; break; + + case EOpAny: out << "any"; break; + case EOpAll: out << "all"; break; + + default: out.message(EPrefixError, "Bad unary op"); + } + + out << " (" << node->getCompleteString() << ")"; + + out << "\n"; + + return true; +} + +bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node) +{ + TInfoSinkBase& out = sink; + + if (node->getOp() == EOpNull) { + out.message(EPrefixError, "node is still EOpNull!"); + return true; + } + + OutputTreeText(out, node, depth); + + switch (node->getOp()) { + case EOpSequence: out << "Sequence\n"; return true; + case EOpComma: out << "Comma\n"; return true; + case EOpFunction: out << "Function Definition: " << node->getName(); break; + case EOpFunctionCall: out << "Function Call: " << node->getName(); break; + case EOpParameters: out << "Function Parameters: "; break; + + case EOpConstructFloat: out << "Construct float"; break; + case EOpConstructVec2: out << "Construct vec2"; break; + case EOpConstructVec3: out << "Construct vec3"; break; + case EOpConstructVec4: out << "Construct vec4"; break; + case EOpConstructBool: out << "Construct bool"; break; + case EOpConstructBVec2: out << "Construct bvec2"; break; + case EOpConstructBVec3: out << "Construct bvec3"; break; + case EOpConstructBVec4: out << "Construct bvec4"; break; + case EOpConstructInt: out << "Construct int"; break; + case EOpConstructIVec2: out << "Construct ivec2"; break; + case EOpConstructIVec3: out << "Construct ivec3"; break; + case EOpConstructIVec4: out << "Construct ivec4"; break; + case EOpConstructMat2: out << "Construct mat2"; break; + case EOpConstructMat3: out << "Construct mat3"; break; + case EOpConstructMat4: out << "Construct mat4"; break; + case EOpConstructStruct: out << "Construct structure"; break; + + case EOpLessThan: out << "Compare Less Than"; break; + case EOpGreaterThan: out << "Compare Greater Than"; break; + case EOpLessThanEqual: out << "Compare Less Than or Equal"; break; + case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break; + case EOpVectorEqual: out << "Equal"; break; + case EOpVectorNotEqual: out << "NotEqual"; break; + + case EOpMod: out << "mod"; break; + case EOpPow: out << "pow"; break; + + case EOpAtan: out << "arc tangent"; break; + + case EOpMin: out << "min"; break; + case EOpMax: out << "max"; break; + case EOpClamp: out << "clamp"; break; + case EOpMix: out << "mix"; break; + case EOpStep: out << "step"; break; + case EOpSmoothStep: out << "smoothstep"; break; + + case EOpDistance: out << "distance"; break; + case EOpDot: out << "dot-product"; break; + case EOpCross: out << "cross-product"; break; + case EOpFaceForward: out << "face-forward"; break; + case EOpReflect: out << "reflect"; break; + case EOpRefract: out << "refract"; break; + case EOpMul: out << "component-wise multiply"; break; + + default: out.message(EPrefixError, "Bad aggregation op"); + } + + if (node->getOp() != EOpSequence && node->getOp() != EOpParameters) + out << " (" << node->getCompleteString() << ")"; + + out << "\n"; + + return true; +} + +bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node) +{ + TInfoSinkBase& out = sink; + + OutputTreeText(out, node, depth); + + out << "Test condition and select"; + out << " (" << node->getCompleteString() << ")\n"; + + ++depth; + + OutputTreeText(sink, node, depth); + out << "Condition\n"; + node->getCondition()->traverse(this); + + OutputTreeText(sink, node, depth); + if (node->getTrueBlock()) { + out << "true case\n"; + node->getTrueBlock()->traverse(this); + } else + out << "true case is null\n"; + + if (node->getFalseBlock()) { + OutputTreeText(sink, node, depth); + out << "false case\n"; + node->getFalseBlock()->traverse(this); + } + + --depth; + + return false; +} + +void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node) +{ + TInfoSinkBase& out = sink; + + int size = node->getType().getObjectSize(); + + for (int i = 0; i < size; i++) { + OutputTreeText(out, node, depth); + switch (node->getUnionArrayPointer()[i].getType()) { + case EbtBool: + if (node->getUnionArrayPointer()[i].getBConst()) + out << "true"; + else + out << "false"; + + out << " (" << "const bool" << ")"; + out << "\n"; + break; + case EbtFloat: + out << node->getUnionArrayPointer()[i].getFConst(); + out << " (const float)\n"; + break; + case EbtInt: + out << node->getUnionArrayPointer()[i].getIConst(); + out << " (const int)\n"; + break; + default: + out.message(EPrefixInternalError, "Unknown constant", node->getLine()); + break; + } + } +} + +bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node) +{ + TInfoSinkBase& out = sink; + + OutputTreeText(out, node, depth); + + out << "Loop with condition "; + if (node->getType() == ELoopDoWhile) + out << "not "; + out << "tested first\n"; + + ++depth; + + OutputTreeText(sink, node, depth); + if (node->getCondition()) { + out << "Loop Condition\n"; + node->getCondition()->traverse(this); + } else + out << "No loop condition\n"; + + OutputTreeText(sink, node, depth); + if (node->getBody()) { + out << "Loop Body\n"; + node->getBody()->traverse(this); + } else + out << "No loop body\n"; + + if (node->getExpression()) { + OutputTreeText(sink, node, depth); + out << "Loop Terminal Expression\n"; + node->getExpression()->traverse(this); + } + + --depth; + + return false; +} + +bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node) +{ + TInfoSinkBase& out = sink; + + OutputTreeText(out, node, depth); + + switch (node->getFlowOp()) { + case EOpKill: out << "Branch: Kill"; break; + case EOpBreak: out << "Branch: Break"; break; + case EOpContinue: out << "Branch: Continue"; break; + case EOpReturn: out << "Branch: Return"; break; + default: out << "Branch: Unknown Branch"; break; + } + + if (node->getExpression()) { + out << " with expression\n"; + ++depth; + node->getExpression()->traverse(this); + --depth; + } else + out << "\n"; + + return false; +} + +// +// This function is the one to call externally to start the traversal. +// Individual functions can be initialized to 0 to skip processing of that +// type of node. It's children will still be processed. +// +void TIntermediate::outputTree(TIntermNode* root) +{ + if (root == 0) + return; + + TOutputTraverser it(infoSink.info); + + root->traverse(&it); +}
diff --git a/src/GLES2/compiler/intermediate.h b/src/GLES2/compiler/intermediate.h new file mode 100644 index 0000000..5ed5f54 --- /dev/null +++ b/src/GLES2/compiler/intermediate.h
@@ -0,0 +1,551 @@ +// +// Copyright (c) 2002-2012 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. +// + +// +// Definition of the in-memory high-level intermediate representation +// of shaders. This is a tree that parser creates. +// +// Nodes in the tree are defined as a hierarchy of classes derived from +// TIntermNode. Each is a node in a tree. There is no preset branching factor; +// each node can have it's own type of list of children. +// + +#ifndef __INTERMEDIATE_H +#define __INTERMEDIATE_H + +#include "compiler/Common.h" +#include "compiler/Types.h" +#include "compiler/ConstantUnion.h" + +// +// Operators used by the high-level (parse tree) representation. +// +enum TOperator { + EOpNull, // if in a node, should only mean a node is still being built + EOpSequence, // denotes a list of statements, or parameters, etc. + EOpFunctionCall, + EOpFunction, // For function definition + EOpParameters, // an aggregate listing the parameters to a function + + EOpDeclaration, + EOpPrototype, + + // + // Unary operators + // + + EOpNegative, + EOpLogicalNot, + EOpVectorLogicalNot, + + EOpPostIncrement, + EOpPostDecrement, + EOpPreIncrement, + EOpPreDecrement, + + EOpConvIntToBool, + EOpConvFloatToBool, + EOpConvBoolToFloat, + EOpConvIntToFloat, + EOpConvFloatToInt, + EOpConvBoolToInt, + + // + // binary operations + // + + EOpAdd, + EOpSub, + EOpMul, + EOpDiv, + EOpEqual, + EOpNotEqual, + EOpVectorEqual, + EOpVectorNotEqual, + EOpLessThan, + EOpGreaterThan, + EOpLessThanEqual, + EOpGreaterThanEqual, + EOpComma, + + EOpVectorTimesScalar, + EOpVectorTimesMatrix, + EOpMatrixTimesVector, + EOpMatrixTimesScalar, + + EOpLogicalOr, + EOpLogicalXor, + EOpLogicalAnd, + + EOpIndexDirect, + EOpIndexIndirect, + EOpIndexDirectStruct, + + EOpVectorSwizzle, + + // + // Built-in functions potentially mapped to operators + // + + EOpRadians, + EOpDegrees, + EOpSin, + EOpCos, + EOpTan, + EOpAsin, + EOpAcos, + EOpAtan, + + EOpPow, + EOpExp, + EOpLog, + EOpExp2, + EOpLog2, + EOpSqrt, + EOpInverseSqrt, + + EOpAbs, + EOpSign, + EOpFloor, + EOpCeil, + EOpFract, + EOpMod, + EOpMin, + EOpMax, + EOpClamp, + EOpMix, + EOpStep, + EOpSmoothStep, + + EOpLength, + EOpDistance, + EOpDot, + EOpCross, + EOpNormalize, + EOpFaceForward, + EOpReflect, + EOpRefract, + + EOpDFdx, // Fragment only, OES_standard_derivatives extension + EOpDFdy, // Fragment only, OES_standard_derivatives extension + EOpFwidth, // Fragment only, OES_standard_derivatives extension + + EOpMatrixTimesMatrix, + + EOpAny, + EOpAll, + + // + // Branch + // + + EOpKill, // Fragment only + EOpReturn, + EOpBreak, + EOpContinue, + + // + // Constructors + // + + EOpConstructInt, + EOpConstructBool, + EOpConstructFloat, + EOpConstructVec2, + EOpConstructVec3, + EOpConstructVec4, + EOpConstructBVec2, + EOpConstructBVec3, + EOpConstructBVec4, + EOpConstructIVec2, + EOpConstructIVec3, + EOpConstructIVec4, + EOpConstructMat2, + EOpConstructMat3, + EOpConstructMat4, + EOpConstructStruct, + + // + // moves + // + + EOpAssign, + EOpInitialize, + EOpAddAssign, + EOpSubAssign, + EOpMulAssign, + EOpVectorTimesMatrixAssign, + EOpVectorTimesScalarAssign, + EOpMatrixTimesScalarAssign, + EOpMatrixTimesMatrixAssign, + EOpDivAssign, +}; + +extern const char* getOperatorString(TOperator op); + +class TIntermTraverser; +class TIntermAggregate; +class TIntermBinary; +class TIntermUnary; +class TIntermConstantUnion; +class TIntermSelection; +class TIntermTyped; +class TIntermSymbol; +class TIntermLoop; +class TIntermBranch; +class TInfoSink; + +// +// Base class for the tree nodes +// +class TIntermNode { +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + + TIntermNode() : line(0) {} + + TSourceLoc getLine() const { return line; } + void setLine(TSourceLoc l) { line = l; } + + virtual void traverse(TIntermTraverser*) = 0; + virtual TIntermTyped* getAsTyped() { return 0; } + virtual TIntermConstantUnion* getAsConstantUnion() { return 0; } + virtual TIntermAggregate* getAsAggregate() { return 0; } + virtual TIntermBinary* getAsBinaryNode() { return 0; } + virtual TIntermUnary* getAsUnaryNode() { return 0; } + virtual TIntermSelection* getAsSelectionNode() { return 0; } + virtual TIntermSymbol* getAsSymbolNode() { return 0; } + virtual TIntermLoop* getAsLoopNode() { return 0; } + virtual TIntermBranch* getAsBranchNode() { return 0; } + virtual ~TIntermNode() { } + +protected: + TSourceLoc line; +}; + +// +// This is just to help yacc. +// +struct TIntermNodePair { + TIntermNode* node1; + TIntermNode* node2; +}; + +// +// Intermediate class for nodes that have a type. +// +class TIntermTyped : public TIntermNode { +public: + TIntermTyped(const TType& t) : type(t) { } + virtual TIntermTyped* getAsTyped() { return this; } + + void setType(const TType& t) { type = t; } + const TType& getType() const { return type; } + TType* getTypePointer() { return &type; } + + TBasicType getBasicType() const { return type.getBasicType(); } + TQualifier getQualifier() const { return type.getQualifier(); } + TPrecision getPrecision() const { return type.getPrecision(); } + int getNominalSize() const { return type.getNominalSize(); } + + bool isMatrix() const { return type.isMatrix(); } + bool isArray() const { return type.isArray(); } + bool isVector() const { return type.isVector(); } + bool isScalar() const { return type.isScalar(); } + bool isRegister() const { return type.isRegister(); } // Fits in a 4-element register + bool isStruct() const { return type.isStruct(); } + const char* getBasicString() const { return type.getBasicString(); } + const char* getQualifierString() const { return type.getQualifierString(); } + TString getCompleteString() const { return type.getCompleteString(); } + + int totalRegisterCount() const { return type.totalRegisterCount(); } + int elementRegisterCount() const { return type.elementRegisterCount(); } + int getArraySize() const { return type.getArraySize(); } + +protected: + TType type; +}; + +// +// Handle for, do-while, and while loops. +// +enum TLoopType { + ELoopFor, + ELoopWhile, + ELoopDoWhile, +}; + +class TIntermLoop : public TIntermNode { +public: + TIntermLoop(TLoopType aType, + TIntermNode *aInit, TIntermTyped* aCond, TIntermTyped* aExpr, + TIntermNode* aBody) : + type(aType), + init(aInit), + cond(aCond), + expr(aExpr), + body(aBody), + unrollFlag(false) { } + + virtual TIntermLoop* getAsLoopNode() { return this; } + virtual void traverse(TIntermTraverser*); + + TLoopType getType() const { return type; } + TIntermNode* getInit() { return init; } + TIntermTyped* getCondition() { return cond; } + TIntermTyped* getExpression() { return expr; } + TIntermNode* getBody() { return body; } + + void setUnrollFlag(bool flag) { unrollFlag = flag; } + bool getUnrollFlag() { return unrollFlag; } + +protected: + TLoopType type; + TIntermNode* init; // for-loop initialization + TIntermTyped* cond; // loop exit condition + TIntermTyped* expr; // for-loop expression + TIntermNode* body; // loop body + + bool unrollFlag; // Whether the loop should be unrolled or not. +}; + +// +// Handle break, continue, return, and kill. +// +class TIntermBranch : public TIntermNode { +public: + TIntermBranch(TOperator op, TIntermTyped* e) : + flowOp(op), + expression(e) { } + + virtual TIntermBranch* getAsBranchNode() { return this; } + virtual void traverse(TIntermTraverser*); + + TOperator getFlowOp() { return flowOp; } + TIntermTyped* getExpression() { return expression; } + +protected: + TOperator flowOp; + TIntermTyped* expression; // non-zero except for "return exp;" statements +}; + +// +// Nodes that correspond to symbols or constants in the source code. +// +class TIntermSymbol : public TIntermTyped { +public: + // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from + // per process globalpoolallocator, then it causes increased memory usage per compile + // it is essential to use "symbol = sym" to assign to symbol + TIntermSymbol(int i, const TString& sym, const TType& t) : + TIntermTyped(t), id(i) { symbol = sym; } + + int getId() const { return id; } + const TString& getSymbol() const { return symbol; } + + void setId(int newId) { id = newId; } + + virtual void traverse(TIntermTraverser*); + virtual TIntermSymbol* getAsSymbolNode() { return this; } + +protected: + int id; + TString symbol; +}; + +class TIntermConstantUnion : public TIntermTyped { +public: + TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { } + + ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; } + void setUnionArrayPointer(ConstantUnion *c) { unionArrayPointer = c; } + + virtual TIntermConstantUnion* getAsConstantUnion() { return this; } + virtual void traverse(TIntermTraverser*); + + TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&); + +protected: + ConstantUnion *unionArrayPointer; +}; + +// +// Intermediate class for node types that hold operators. +// +class TIntermOperator : public TIntermTyped { +public: + TOperator getOp() const { return op; } + void setOp(TOperator o) { op = o; } + + bool modifiesState() const; + bool isConstructor() const; + +protected: + TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {} + TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {} + TOperator op; +}; + +// +// Nodes for all the basic binary math operators. +// +class TIntermBinary : public TIntermOperator { +public: + TIntermBinary(TOperator o) : TIntermOperator(o) {} + + virtual TIntermBinary* getAsBinaryNode() { return this; } + virtual void traverse(TIntermTraverser*); + + void setLeft(TIntermTyped* n) { left = n; } + void setRight(TIntermTyped* n) { right = n; } + TIntermTyped* getLeft() const { return left; } + TIntermTyped* getRight() const { return right; } + bool promote(TInfoSink&); + +protected: + TIntermTyped* left; + TIntermTyped* right; +}; + +// +// Nodes for unary math operators. +// +class TIntermUnary : public TIntermOperator { +public: + TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0) {} + TIntermUnary(TOperator o) : TIntermOperator(o), operand(0) {} + + virtual void traverse(TIntermTraverser*); + virtual TIntermUnary* getAsUnaryNode() { return this; } + + void setOperand(TIntermTyped* o) { operand = o; } + TIntermTyped* getOperand() { return operand; } + bool promote(TInfoSink&); + +protected: + TIntermTyped* operand; +}; + +typedef TVector<TIntermNode*> TIntermSequence; +typedef TVector<int> TQualifierList; + +// +// Nodes that operate on an arbitrary sized set of children. +// +class TIntermAggregate : public TIntermOperator { +public: + TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), endLine(0) { } + TIntermAggregate(TOperator o) : TIntermOperator(o) { } + ~TIntermAggregate() { } + + virtual TIntermAggregate* getAsAggregate() { return this; } + virtual void traverse(TIntermTraverser*); + + TIntermSequence& getSequence() { return sequence; } + + void setName(const TString& n) { name = n; } + const TString& getName() const { return name; } + + void setUserDefined() { userDefined = true; } + bool isUserDefined() const { return userDefined; } + + void setOptimize(bool o) { optimize = o; } + bool getOptimize() { return optimize; } + void setDebug(bool d) { debug = d; } + bool getDebug() { return debug; } + + void setEndLine(TSourceLoc line) { endLine = line; } + TSourceLoc getEndLine() const { return endLine; } + +protected: + TIntermAggregate(const TIntermAggregate&); // disallow copy constructor + TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator + TIntermSequence sequence; + TString name; + bool userDefined; // used for user defined function names + + bool optimize; + bool debug; + TSourceLoc endLine; +}; + +// +// For if tests. Simplified since there is no switch statement. +// +class TIntermSelection : public TIntermTyped { +public: + TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) : + TIntermTyped(TType(EbtVoid, EbpUndefined)), condition(cond), trueBlock(trueB), falseBlock(falseB) {} + TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) : + TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) + { + this->type.setQualifier(EvqTemporary); + } + + virtual void traverse(TIntermTraverser*); + + bool usesTernaryOperator() const { return getBasicType() != EbtVoid; } + TIntermTyped* getCondition() const { return condition; } + TIntermNode* getTrueBlock() const { return trueBlock; } + TIntermNode* getFalseBlock() const { return falseBlock; } + TIntermSelection* getAsSelectionNode() { return this; } + +protected: + TIntermTyped* condition; + TIntermNode* trueBlock; + TIntermNode* falseBlock; +}; + +enum Visit +{ + PreVisit, + InVisit, + PostVisit +}; + +// +// For traversing the tree. User should derive from this, +// put their traversal specific data in it, and then pass +// it to a Traverse method. +// +// When using this, just fill in the methods for nodes you want visited. +// Return false from a pre-visit to skip visiting that node's subtree. +// +class TIntermTraverser +{ +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + + TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) : + preVisit(preVisit), + inVisit(inVisit), + postVisit(postVisit), + rightToLeft(rightToLeft), + depth(0) {} + virtual ~TIntermTraverser() {}; + + virtual void visitSymbol(TIntermSymbol*) {} + virtual void visitConstantUnion(TIntermConstantUnion*) {} + virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;} + virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;} + virtual bool visitSelection(Visit visit, TIntermSelection*) {return true;} + virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;} + virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;} + virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;} + + void incrementDepth() {depth++;} + void decrementDepth() {depth--;} + + const bool preVisit; + const bool inVisit; + const bool postVisit; + const bool rightToLeft; + +protected: + int depth; +}; + +#endif // __INTERMEDIATE_H
diff --git a/src/GLES2/compiler/localintermediate.h b/src/GLES2/compiler/localintermediate.h new file mode 100644 index 0000000..56890bd --- /dev/null +++ b/src/GLES2/compiler/localintermediate.h
@@ -0,0 +1,58 @@ +// +// 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. +// + +#ifndef _LOCAL_INTERMEDIATE_INCLUDED_ +#define _LOCAL_INTERMEDIATE_INCLUDED_ + +#include "GLSLANG/ShaderLang.h" +#include "compiler/intermediate.h" +#include "compiler/SymbolTable.h" + +struct TVectorFields { + int offsets[4]; + int num; +}; + +// +// Set of helper functions to help parse and build the tree. +// +class TInfoSink; +class TIntermediate { +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + + TIntermediate(TInfoSink& i) : infoSink(i) { } + TIntermSymbol* addSymbol(int Id, const TString&, const TType&, TSourceLoc); + TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*); + TIntermTyped* addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc, TSymbolTable&); + TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc); + TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc); + TIntermTyped* addUnaryMath(TOperator op, TIntermNode* child, TSourceLoc, TSymbolTable&); + TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, TSourceLoc); + TIntermAggregate* makeAggregate(TIntermNode* node, TSourceLoc); + TIntermAggregate* setAggregateOperator(TIntermNode*, TOperator, TSourceLoc); + TIntermNode* addSelection(TIntermTyped* cond, TIntermNodePair code, TSourceLoc); + TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc); + TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc); + TIntermConstantUnion* addConstantUnion(ConstantUnion*, const TType&, TSourceLoc); + TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) ; + bool parseConstTree(TSourceLoc, TIntermNode*, ConstantUnion*, TOperator, TSymbolTable&, TType, bool singleConstantParam = false); + TIntermNode* addLoop(TLoopType, TIntermNode*, TIntermTyped*, TIntermTyped*, TIntermNode*, TSourceLoc); + TIntermBranch* addBranch(TOperator, TSourceLoc); + TIntermBranch* addBranch(TOperator, TIntermTyped*, TSourceLoc); + TIntermTyped* addSwizzle(TVectorFields&, TSourceLoc); + bool postProcess(TIntermNode*); + void remove(TIntermNode*); + void outputTree(TIntermNode*); + +protected: + TInfoSink& infoSink; + +private: + void operator=(TIntermediate&); // prevent assignments +}; + +#endif // _LOCAL_INTERMEDIATE_INCLUDED_
diff --git a/src/GLES2/compiler/osinclude.h b/src/GLES2/compiler/osinclude.h new file mode 100644 index 0000000..42379f0 --- /dev/null +++ b/src/GLES2/compiler/osinclude.h
@@ -0,0 +1,65 @@ +// +// Copyright (c) 2002-2012 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. +// + +#ifndef __OSINCLUDE_H +#define __OSINCLUDE_H + +// +// This file contains contains os-specific datatypes and +// declares any os-specific functions. +// + +#if defined(_WIN32) || defined(_WIN64) +#define ANGLE_OS_WIN +#elif defined(__APPLE__) || defined(__linux__) || \ + defined(__FreeBSD__) || defined(__OpenBSD__) || \ + defined(__sun) || defined(ANDROID) || \ + defined(__GLIBC__) || defined(__GNU__) || \ + defined(__QNX__) +#define ANGLE_OS_POSIX +#else +#error Unsupported platform. +#endif + +#if defined(ANGLE_OS_WIN) +#define STRICT +#define VC_EXTRALEAN 1 +#include <windows.h> +#elif defined(ANGLE_OS_POSIX) +#include <pthread.h> +#include <semaphore.h> +#include <errno.h> +#endif + + +#include "compiler/debug.h" + +// +// Thread Local Storage Operations +// +#if defined(ANGLE_OS_WIN) +typedef DWORD OS_TLSIndex; +#define OS_INVALID_TLS_INDEX (TLS_OUT_OF_INDEXES) +#elif defined(ANGLE_OS_POSIX) +typedef unsigned int OS_TLSIndex; +#define OS_INVALID_TLS_INDEX 0xFFFFFFFF +#endif + +OS_TLSIndex OS_AllocTLSIndex(); +bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue); +bool OS_FreeTLSIndex(OS_TLSIndex nIndex); + +inline void* OS_GetTLSValue(OS_TLSIndex nIndex) +{ + ASSERT(nIndex != OS_INVALID_TLS_INDEX); +#if defined(ANGLE_OS_WIN) + return TlsGetValue(nIndex); +#elif defined(ANGLE_OS_POSIX) + return pthread_getspecific(nIndex); +#endif // ANGLE_OS_WIN +} + +#endif // __OSINCLUDE_H
diff --git a/src/GLES2/compiler/ossource_posix.cpp b/src/GLES2/compiler/ossource_posix.cpp new file mode 100644 index 0000000..1e1e699 --- /dev/null +++ b/src/GLES2/compiler/ossource_posix.cpp
@@ -0,0 +1,64 @@ +// +// 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. +// + +// +// This file contains the posix specific functions +// +#include "compiler/osinclude.h" + +#if !defined(ANGLE_OS_POSIX) +#error Trying to build a posix specific file in a non-posix build. +#endif + +// +// Thread Local Storage Operations +// +OS_TLSIndex OS_AllocTLSIndex() +{ + pthread_key_t pPoolIndex; + + // + // Create global pool key. + // + if ((pthread_key_create(&pPoolIndex, NULL)) != 0) { + assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage"); + return false; + } + else { + return pPoolIndex; + } +} + + +bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue) +{ + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } + + if (pthread_setspecific(nIndex, lpvValue) == 0) + return true; + else + return false; +} + + +bool OS_FreeTLSIndex(OS_TLSIndex nIndex) +{ + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } + + // + // Delete the global pool key. + // + if (pthread_key_delete(nIndex) == 0) + return true; + else + return false; +}
diff --git a/src/GLES2/compiler/ossource_win.cpp b/src/GLES2/compiler/ossource_win.cpp new file mode 100644 index 0000000..89922fe --- /dev/null +++ b/src/GLES2/compiler/ossource_win.cpp
@@ -0,0 +1,57 @@ +// +// 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/osinclude.h" +// +// This file contains contains the window's specific functions +// + +#if !defined(ANGLE_OS_WIN) +#error Trying to build a windows specific file in a non windows build. +#endif + + +// +// Thread Local Storage Operations +// +OS_TLSIndex OS_AllocTLSIndex() +{ + DWORD dwIndex = TlsAlloc(); + if (dwIndex == TLS_OUT_OF_INDEXES) { + assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage"); + return OS_INVALID_TLS_INDEX; + } + + return dwIndex; +} + + +bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue) +{ + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } + + if (TlsSetValue(nIndex, lpvValue)) + return true; + else + return false; +} + + +bool OS_FreeTLSIndex(OS_TLSIndex nIndex) +{ + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } + + if (TlsFree(nIndex)) + return true; + else + return false; +}
diff --git a/src/GLES2/compiler/parseConst.cpp b/src/GLES2/compiler/parseConst.cpp new file mode 100644 index 0000000..9a8a50c --- /dev/null +++ b/src/GLES2/compiler/parseConst.cpp
@@ -0,0 +1,238 @@ +// +// 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/ParseHelper.h" + +// +// Use this class to carry along data from node to node in +// the traversal +// +class TConstTraverser : public TIntermTraverser { +public: + TConstTraverser(ConstantUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TSymbolTable& symTable, TType& t) + : error(false), + index(0), + unionArray(cUnion), + type(t), + constructorType(constructType), + singleConstantParam(singleConstParam), + infoSink(sink), + symbolTable(symTable), + size(0), + isMatrix(false), + matrixSize(0) { + } + + bool error; + +protected: + void visitSymbol(TIntermSymbol*); + void visitConstantUnion(TIntermConstantUnion*); + bool visitBinary(Visit visit, TIntermBinary*); + bool visitUnary(Visit visit, TIntermUnary*); + bool visitSelection(Visit visit, TIntermSelection*); + bool visitAggregate(Visit visit, TIntermAggregate*); + bool visitLoop(Visit visit, TIntermLoop*); + bool visitBranch(Visit visit, TIntermBranch*); + + int index; + ConstantUnion *unionArray; + TType type; + TOperator constructorType; + bool singleConstantParam; + TInfoSink& infoSink; + TSymbolTable& symbolTable; + int size; // size of the constructor ( 4 for vec4) + bool isMatrix; + int matrixSize; // dimension of the matrix (nominal size and not the instance size) +}; + +// +// The rest of the file are the traversal functions. The last one +// is the one that starts the traversal. +// +// Return true from interior nodes to have the external traversal +// continue on to children. If you process children yourself, +// return false. +// + +void TConstTraverser::visitSymbol(TIntermSymbol* node) +{ + infoSink.info.message(EPrefixInternalError, "Symbol Node found in constant constructor", node->getLine()); + return; + +} + +bool TConstTraverser::visitBinary(Visit visit, TIntermBinary* node) +{ + TQualifier qualifier = node->getType().getQualifier(); + + if (qualifier != EvqConst) { + TString buf; + buf.append("'constructor' : assigning non-constant to "); + buf.append(type.getCompleteString()); + infoSink.info.message(EPrefixError, buf.c_str(), node->getLine()); + error = true; + return false; + } + + infoSink.info.message(EPrefixInternalError, "Binary Node found in constant constructor", node->getLine()); + + return false; +} + +bool TConstTraverser::visitUnary(Visit visit, TIntermUnary* node) +{ + TString buf; + buf.append("'constructor' : assigning non-constant to "); + buf.append(type.getCompleteString()); + infoSink.info.message(EPrefixError, buf.c_str(), node->getLine()); + error = true; + return false; +} + +bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate* node) +{ + if (!node->isConstructor() && node->getOp() != EOpComma) { + TString buf; + buf.append("'constructor' : assigning non-constant to "); + buf.append(type.getCompleteString()); + infoSink.info.message(EPrefixError, buf.c_str(), node->getLine()); + error = true; + return false; + } + + if (node->getSequence().size() == 0) { + error = true; + return false; + } + + bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion(); + if (flag) + { + singleConstantParam = true; + constructorType = node->getOp(); + size = node->getType().getObjectSize(); + + if (node->getType().isMatrix()) { + isMatrix = true; + matrixSize = node->getType().getNominalSize(); + } + } + + for (TIntermSequence::iterator p = node->getSequence().begin(); + p != node->getSequence().end(); p++) { + + if (node->getOp() == EOpComma) + index = 0; + + (*p)->traverse(this); + } + if (flag) + { + singleConstantParam = false; + constructorType = EOpNull; + size = 0; + isMatrix = false; + matrixSize = 0; + } + return false; +} + +bool TConstTraverser::visitSelection(Visit visit, TIntermSelection* node) +{ + infoSink.info.message(EPrefixInternalError, "Selection Node found in constant constructor", node->getLine()); + error = true; + return false; +} + +void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node) +{ + ConstantUnion* leftUnionArray = unionArray; + int instanceSize = type.getObjectSize(); + + if (index >= instanceSize) + return; + + if (!singleConstantParam) { + int size = node->getType().getObjectSize(); + + ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); + for (int i=0; i < size; i++) { + if (index >= instanceSize) + return; + leftUnionArray[index] = rightUnionArray[i]; + + (index)++; + } + } else { + int totalSize = index + size; + ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); + if (!isMatrix) { + int count = 0; + for (int i = index; i < totalSize; i++) { + if (i >= instanceSize) + return; + + leftUnionArray[i] = rightUnionArray[count]; + + (index)++; + + if (node->getType().getObjectSize() > 1) + count++; + } + } else { // for matrix constructors + int count = 0; + int element = index; + for (int i = index; i < totalSize; i++) { + if (i >= instanceSize) + return; + if (element - i == 0 || (i - element) % (matrixSize + 1) == 0 ) + leftUnionArray[i] = rightUnionArray[count]; + else + leftUnionArray[i].setFConst(0.0f); + + (index)++; + + if (node->getType().getObjectSize() > 1) + count++; + } + } + } +} + +bool TConstTraverser::visitLoop(Visit visit, TIntermLoop* node) +{ + infoSink.info.message(EPrefixInternalError, "Loop Node found in constant constructor", node->getLine()); + error = true; + return false; +} + +bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node) +{ + infoSink.info.message(EPrefixInternalError, "Branch Node found in constant constructor", node->getLine()); + error = true; + return false; +} + +// +// This function is the one to call externally to start the traversal. +// Individual functions can be initialized to 0 to skip processing of that +// type of node. It's children will still be processed. +// +bool TIntermediate::parseConstTree(TSourceLoc line, TIntermNode* root, ConstantUnion* unionArray, TOperator constructorType, TSymbolTable& symbolTable, TType t, bool singleConstantParam) +{ + if (root == 0) + return false; + + TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, symbolTable, t); + + root->traverse(&it); + if (it.error) + return true; + else + return false; +}
diff --git a/src/GLES2/compiler/preprocessor/Diagnostics.cpp b/src/GLES2/compiler/preprocessor/Diagnostics.cpp new file mode 100644 index 0000000..06d1d80 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/Diagnostics.cpp
@@ -0,0 +1,127 @@ +// +// Copyright (c) 2012 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 "Diagnostics.h" + +#include <cassert> + +namespace pp +{ + +Diagnostics::~Diagnostics() +{ +} + +void Diagnostics::report(ID id, + const SourceLocation& loc, + const std::string& text) +{ + // TODO(alokp): Keep a count of errors and warnings. + print(id, loc, text); +} + +Diagnostics::Severity Diagnostics::severity(ID id) +{ + if ((id > ERROR_BEGIN) && (id < ERROR_END)) + return PP_ERROR; + + if ((id > WARNING_BEGIN) && (id < WARNING_END)) + return PP_WARNING; + + assert(false); + return PP_ERROR; +} + +std::string Diagnostics::message(ID id) +{ + switch (id) + { + // Errors begin. + case INTERNAL_ERROR: + return "internal error"; + case OUT_OF_MEMORY: + return "out of memory"; + case INVALID_CHARACTER: + return "invalid character"; + case INVALID_NUMBER: + return "invalid number"; + case INTEGER_OVERFLOW: + return "integer overflow"; + case FLOAT_OVERFLOW: + return "float overflow"; + case TOKEN_TOO_LONG: + return "token too long"; + case INVALID_EXPRESSION: + return "invalid expression"; + case DIVISION_BY_ZERO: + return "division by zero"; + case EOF_IN_COMMENT: + return "unexpected end of file found in comment"; + case UNEXPECTED_TOKEN: + return "unexpected token"; + case DIRECTIVE_INVALID_NAME: + return "invalid directive name"; + case MACRO_NAME_RESERVED: + return "macro name is reserved"; + case MACRO_REDEFINED: + return "macro redefined"; + case MACRO_PREDEFINED_REDEFINED: + return "predefined macro redefined"; + case MACRO_PREDEFINED_UNDEFINED: + return "predefined macro undefined"; + case MACRO_UNTERMINATED_INVOCATION: + return "unterminated macro invocation"; + case MACRO_TOO_FEW_ARGS: + return "Not enough arguments for macro"; + case MACRO_TOO_MANY_ARGS: + return "Too many arguments for macro"; + case CONDITIONAL_ENDIF_WITHOUT_IF: + return "unexpected #endif found without a matching #if"; + case CONDITIONAL_ELSE_WITHOUT_IF: + return "unexpected #else found without a matching #if"; + case CONDITIONAL_ELSE_AFTER_ELSE: + return "unexpected #else found after another #else"; + case CONDITIONAL_ELIF_WITHOUT_IF: + return "unexpected #elif found without a matching #if"; + case CONDITIONAL_ELIF_AFTER_ELSE: + return "unexpected #elif found after #else"; + case CONDITIONAL_UNTERMINATED: + return "unexpected end of file found in conditional block"; + case INVALID_EXTENSION_NAME: + return "invalid extension name"; + case INVALID_EXTENSION_BEHAVIOR: + return "invalid extension behavior"; + case INVALID_EXTENSION_DIRECTIVE: + return "invalid extension directive"; + case INVALID_VERSION_NUMBER: + return "invalid version number"; + case INVALID_VERSION_DIRECTIVE: + return "invalid version directive"; + case VERSION_NOT_FIRST_STATEMENT: + return "#version directive must occur before anything else, " + "except for comments and white space"; + case INVALID_LINE_NUMBER: + return "invalid line number"; + case INVALID_FILE_NUMBER: + return "invalid file number"; + case INVALID_LINE_DIRECTIVE: + return "invalid line directive"; + // Errors end. + // Warnings begin. + case EOF_IN_DIRECTIVE: + return "unexpected end of file found in directive"; + case CONDITIONAL_UNEXPECTED_TOKEN: + return "unexpected token after conditional expression"; + case UNRECOGNIZED_PRAGMA: + return "unrecognized pragma"; + // Warnings end. + default: + assert(false); + return ""; + } +} + +} // namespace pp
diff --git a/src/GLES2/compiler/preprocessor/Diagnostics.h b/src/GLES2/compiler/preprocessor/Diagnostics.h new file mode 100644 index 0000000..4db9c30 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/Diagnostics.h
@@ -0,0 +1,87 @@ +// +// Copyright (c) 2012 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. +// + +#ifndef COMPILER_PREPROCESSOR_DIAGNOSTICS_H_ +#define COMPILER_PREPROCESSOR_DIAGNOSTICS_H_ + +#include <string> + +namespace pp +{ + +struct SourceLocation; + +// Base class for reporting diagnostic messages. +// Derived classes are responsible for formatting and printing the messages. +class Diagnostics +{ + public: + enum Severity + { + PP_ERROR, + PP_WARNING + }; + enum ID + { + ERROR_BEGIN, + INTERNAL_ERROR, + OUT_OF_MEMORY, + INVALID_CHARACTER, + INVALID_NUMBER, + INTEGER_OVERFLOW, + FLOAT_OVERFLOW, + TOKEN_TOO_LONG, + INVALID_EXPRESSION, + DIVISION_BY_ZERO, + EOF_IN_COMMENT, + UNEXPECTED_TOKEN, + DIRECTIVE_INVALID_NAME, + MACRO_NAME_RESERVED, + MACRO_REDEFINED, + MACRO_PREDEFINED_REDEFINED, + MACRO_PREDEFINED_UNDEFINED, + MACRO_UNTERMINATED_INVOCATION, + MACRO_TOO_FEW_ARGS, + MACRO_TOO_MANY_ARGS, + CONDITIONAL_ENDIF_WITHOUT_IF, + CONDITIONAL_ELSE_WITHOUT_IF, + CONDITIONAL_ELSE_AFTER_ELSE, + CONDITIONAL_ELIF_WITHOUT_IF, + CONDITIONAL_ELIF_AFTER_ELSE, + CONDITIONAL_UNTERMINATED, + INVALID_EXTENSION_NAME, + INVALID_EXTENSION_BEHAVIOR, + INVALID_EXTENSION_DIRECTIVE, + INVALID_VERSION_NUMBER, + INVALID_VERSION_DIRECTIVE, + VERSION_NOT_FIRST_STATEMENT, + INVALID_LINE_NUMBER, + INVALID_FILE_NUMBER, + INVALID_LINE_DIRECTIVE, + ERROR_END, + + WARNING_BEGIN, + EOF_IN_DIRECTIVE, + CONDITIONAL_UNEXPECTED_TOKEN, + UNRECOGNIZED_PRAGMA, + WARNING_END + }; + + virtual ~Diagnostics(); + + void report(ID id, const SourceLocation& loc, const std::string& text); + + protected: + Severity severity(ID id); + std::string message(ID id); + + virtual void print(ID id, + const SourceLocation& loc, + const std::string& text) = 0; +}; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_DIAGNOSTICS_H_
diff --git a/src/GLES2/compiler/preprocessor/DirectiveHandler.cpp b/src/GLES2/compiler/preprocessor/DirectiveHandler.cpp new file mode 100644 index 0000000..d67bee3 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/DirectiveHandler.cpp
@@ -0,0 +1,16 @@ +// +// Copyright (c) 2012 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 "DirectiveHandler.h" + +namespace pp +{ + +DirectiveHandler::~DirectiveHandler() +{ +} + +} // namespace pp
diff --git a/src/GLES2/compiler/preprocessor/DirectiveHandler.h b/src/GLES2/compiler/preprocessor/DirectiveHandler.h new file mode 100644 index 0000000..572b897 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/DirectiveHandler.h
@@ -0,0 +1,43 @@ +// +// Copyright (c) 2012 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. +// + +#ifndef COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_ +#define COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_ + +#include <string> + +namespace pp +{ + +struct SourceLocation; + +// Base class for handling directives. +// Preprocessor uses this class to notify the clients about certain +// preprocessor directives. Derived classes are responsible for +// handling them in an appropriate manner. +class DirectiveHandler +{ + public: + virtual ~DirectiveHandler(); + + virtual void handleError(const SourceLocation& loc, + const std::string& msg) = 0; + + // Handle pragma of form: #pragma name[(value)] + virtual void handlePragma(const SourceLocation& loc, + const std::string& name, + const std::string& value) = 0; + + virtual void handleExtension(const SourceLocation& loc, + const std::string& name, + const std::string& behavior) = 0; + + virtual void handleVersion(const SourceLocation& loc, + int version) = 0; +}; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_
diff --git a/src/GLES2/compiler/preprocessor/DirectiveParser.cpp b/src/GLES2/compiler/preprocessor/DirectiveParser.cpp new file mode 100644 index 0000000..0038469 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/DirectiveParser.cpp
@@ -0,0 +1,932 @@ +// +// Copyright (c) 2011 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 "DirectiveParser.h" + +#include <cassert> +#include <cstdlib> +#include <sstream> + +#include "Diagnostics.h" +#include "DirectiveHandler.h" +#include "ExpressionParser.h" +#include "MacroExpander.h" +#include "Token.h" +#include "Tokenizer.h" + +namespace { +enum DirectiveType +{ + DIRECTIVE_NONE, + DIRECTIVE_DEFINE, + DIRECTIVE_UNDEF, + DIRECTIVE_IF, + DIRECTIVE_IFDEF, + DIRECTIVE_IFNDEF, + DIRECTIVE_ELSE, + DIRECTIVE_ELIF, + DIRECTIVE_ENDIF, + DIRECTIVE_ERROR, + DIRECTIVE_PRAGMA, + DIRECTIVE_EXTENSION, + DIRECTIVE_VERSION, + DIRECTIVE_LINE +}; +} // namespace + +static DirectiveType getDirective(const pp::Token* token) +{ + static const std::string kDirectiveDefine("define"); + static const std::string kDirectiveUndef("undef"); + static const std::string kDirectiveIf("if"); + static const std::string kDirectiveIfdef("ifdef"); + static const std::string kDirectiveIfndef("ifndef"); + static const std::string kDirectiveElse("else"); + static const std::string kDirectiveElif("elif"); + static const std::string kDirectiveEndif("endif"); + static const std::string kDirectiveError("error"); + static const std::string kDirectivePragma("pragma"); + static const std::string kDirectiveExtension("extension"); + static const std::string kDirectiveVersion("version"); + static const std::string kDirectiveLine("line"); + + if (token->type != pp::Token::IDENTIFIER) + return DIRECTIVE_NONE; + + if (token->text == kDirectiveDefine) + return DIRECTIVE_DEFINE; + else if (token->text == kDirectiveUndef) + return DIRECTIVE_UNDEF; + else if (token->text == kDirectiveIf) + return DIRECTIVE_IF; + else if (token->text == kDirectiveIfdef) + return DIRECTIVE_IFDEF; + else if (token->text == kDirectiveIfndef) + return DIRECTIVE_IFNDEF; + else if (token->text == kDirectiveElse) + return DIRECTIVE_ELSE; + else if (token->text == kDirectiveElif) + return DIRECTIVE_ELIF; + else if (token->text == kDirectiveEndif) + return DIRECTIVE_ENDIF; + else if (token->text == kDirectiveError) + return DIRECTIVE_ERROR; + else if (token->text == kDirectivePragma) + return DIRECTIVE_PRAGMA; + else if (token->text == kDirectiveExtension) + return DIRECTIVE_EXTENSION; + else if (token->text == kDirectiveVersion) + return DIRECTIVE_VERSION; + else if (token->text == kDirectiveLine) + return DIRECTIVE_LINE; + + return DIRECTIVE_NONE; +} + +static bool isConditionalDirective(DirectiveType directive) +{ + switch (directive) + { + case DIRECTIVE_IF: + case DIRECTIVE_IFDEF: + case DIRECTIVE_IFNDEF: + case DIRECTIVE_ELSE: + case DIRECTIVE_ELIF: + case DIRECTIVE_ENDIF: + return true; + default: + return false; + } +} + +// Returns true if the token represents End Of Directive. +static bool isEOD(const pp::Token* token) +{ + return (token->type == '\n') || (token->type == pp::Token::LAST); +} + +static void skipUntilEOD(pp::Lexer* lexer, pp::Token* token) +{ + while(!isEOD(token)) + { + lexer->lex(token); + } +} + +static bool isMacroNameReserved(const std::string& name) +{ + // Names prefixed with "GL_" are reserved. + if (name.substr(0, 3) == "GL_") + return true; + + // Names containing two consecutive underscores are reserved. + if (name.find("__") != std::string::npos) + return true; + + return false; +} + +static bool isMacroPredefined(const std::string& name, + const pp::MacroSet& macroSet) +{ + pp::MacroSet::const_iterator iter = macroSet.find(name); + return iter != macroSet.end() ? iter->second.predefined : false; +} + +namespace pp +{ + +class DefinedParser : public Lexer +{ + public: + DefinedParser(Lexer* lexer, + const MacroSet* macroSet, + Diagnostics* diagnostics) : + mLexer(lexer), + mMacroSet(macroSet), + mDiagnostics(diagnostics) + { + } + + protected: + virtual void lex(Token* token) + { + static const std::string kDefined("defined"); + + mLexer->lex(token); + if (token->type != Token::IDENTIFIER) + return; + if (token->text != kDefined) + return; + + bool paren = false; + mLexer->lex(token); + if (token->type == '(') + { + paren = true; + mLexer->lex(token); + } + + if (token->type != Token::IDENTIFIER) + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, token->text); + skipUntilEOD(mLexer, token); + return; + } + MacroSet::const_iterator iter = mMacroSet->find(token->text); + std::string expression = iter != mMacroSet->end() ? "1" : "0"; + + if (paren) + { + mLexer->lex(token); + if (token->type != ')') + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, token->text); + skipUntilEOD(mLexer, token); + return; + } + } + + // We have a valid defined operator. + // Convert the current token into a CONST_INT token. + token->type = Token::CONST_INT; + token->text = expression; + } + + private: + Lexer* mLexer; + const MacroSet* mMacroSet; + Diagnostics* mDiagnostics; +}; + +DirectiveParser::DirectiveParser(Tokenizer* tokenizer, + MacroSet* macroSet, + Diagnostics* diagnostics, + DirectiveHandler* directiveHandler) : + mPastFirstStatement(false), + mTokenizer(tokenizer), + mMacroSet(macroSet), + mDiagnostics(diagnostics), + mDirectiveHandler(directiveHandler) +{ +} + +void DirectiveParser::lex(Token* token) +{ + do + { + mTokenizer->lex(token); + + if (token->type == Token::PP_HASH) + { + parseDirective(token); + mPastFirstStatement = true; + } + + if (token->type == Token::LAST) + { + if (!mConditionalStack.empty()) + { + const ConditionalBlock& block = mConditionalStack.back(); + mDiagnostics->report(Diagnostics::CONDITIONAL_UNTERMINATED, + block.location, block.type); + } + break; + } + + } while (skipping() || (token->type == '\n')); + + mPastFirstStatement = true; +} + +void DirectiveParser::parseDirective(Token* token) +{ + assert(token->type == Token::PP_HASH); + + mTokenizer->lex(token); + if (isEOD(token)) + { + // Empty Directive. + return; + } + + DirectiveType directive = getDirective(token); + + // While in an excluded conditional block/group, + // we only parse conditional directives. + if (skipping() && !isConditionalDirective(directive)) + { + skipUntilEOD(mTokenizer, token); + return; + } + + switch(directive) + { + case DIRECTIVE_NONE: + mDiagnostics->report(Diagnostics::DIRECTIVE_INVALID_NAME, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + break; + case DIRECTIVE_DEFINE: + parseDefine(token); + break; + case DIRECTIVE_UNDEF: + parseUndef(token); + break; + case DIRECTIVE_IF: + parseIf(token); + break; + case DIRECTIVE_IFDEF: + parseIfdef(token); + break; + case DIRECTIVE_IFNDEF: + parseIfndef(token); + break; + case DIRECTIVE_ELSE: + parseElse(token); + break; + case DIRECTIVE_ELIF: + parseElif(token); + break; + case DIRECTIVE_ENDIF: + parseEndif(token); + break; + case DIRECTIVE_ERROR: + parseError(token); + break; + case DIRECTIVE_PRAGMA: + parsePragma(token); + break; + case DIRECTIVE_EXTENSION: + parseExtension(token); + break; + case DIRECTIVE_VERSION: + parseVersion(token); + break; + case DIRECTIVE_LINE: + parseLine(token); + break; + default: + assert(false); + break; + } + + skipUntilEOD(mTokenizer, token); + if (token->type == Token::LAST) + { + mDiagnostics->report(Diagnostics::EOF_IN_DIRECTIVE, + token->location, token->text); + } +} + +void DirectiveParser::parseDefine(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_DEFINE); + + mTokenizer->lex(token); + if (token->type != Token::IDENTIFIER) + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, token->text); + return; + } + if (isMacroPredefined(token->text, *mMacroSet)) + { + mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_REDEFINED, + token->location, token->text); + return; + } + if (isMacroNameReserved(token->text)) + { + mDiagnostics->report(Diagnostics::MACRO_NAME_RESERVED, + token->location, token->text); + return; + } + + Macro macro; + macro.type = Macro::kTypeObj; + macro.name = token->text; + + mTokenizer->lex(token); + if (token->type == '(' && !token->hasLeadingSpace()) + { + // Function-like macro. Collect arguments. + macro.type = Macro::kTypeFunc; + do { + mTokenizer->lex(token); + if (token->type != Token::IDENTIFIER) + break; + macro.parameters.push_back(token->text); + + mTokenizer->lex(token); // Get ','. + } while (token->type == ','); + + if (token->type != ')') + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, + token->text); + return; + } + mTokenizer->lex(token); // Get ')'. + } + + while ((token->type != '\n') && (token->type != Token::LAST)) + { + // Reset the token location because it is unnecessary in replacement + // list. Resetting it also allows us to reuse Token::equals() to + // compare macros. + token->location = SourceLocation(); + macro.replacements.push_back(*token); + mTokenizer->lex(token); + } + if (!macro.replacements.empty()) + { + // Whitespace preceding the replacement list is not considered part of + // the replacement list for either form of macro. + macro.replacements.front().setHasLeadingSpace(false); + } + + // Check for macro redefinition. + MacroSet::const_iterator iter = mMacroSet->find(macro.name); + if (iter != mMacroSet->end() && !macro.equals(iter->second)) + { + mDiagnostics->report(Diagnostics::MACRO_REDEFINED, + token->location, + macro.name); + return; + } + mMacroSet->insert(std::make_pair(macro.name, macro)); +} + +void DirectiveParser::parseUndef(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_UNDEF); + + mTokenizer->lex(token); + if (token->type != Token::IDENTIFIER) + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, token->text); + return; + } + + MacroSet::iterator iter = mMacroSet->find(token->text); + if (iter != mMacroSet->end()) + { + if (iter->second.predefined) + { + mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_UNDEFINED, + token->location, token->text); + } + else + { + mMacroSet->erase(iter); + } + } + + mTokenizer->lex(token); +} + +void DirectiveParser::parseIf(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_IF); + parseConditionalIf(token); +} + +void DirectiveParser::parseIfdef(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_IFDEF); + parseConditionalIf(token); +} + +void DirectiveParser::parseIfndef(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_IFNDEF); + parseConditionalIf(token); +} + +void DirectiveParser::parseElse(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_ELSE); + + if (mConditionalStack.empty()) + { + mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_WITHOUT_IF, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + return; + } + + ConditionalBlock& block = mConditionalStack.back(); + if (block.skipBlock) + { + // No diagnostics. Just skip the whole line. + skipUntilEOD(mTokenizer, token); + return; + } + if (block.foundElseGroup) + { + mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_AFTER_ELSE, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + return; + } + + block.foundElseGroup = true; + block.skipGroup = block.foundValidGroup; + block.foundValidGroup = true; + + // Warn if there are extra tokens after #else. + mTokenizer->lex(token); + if (!isEOD(token)) + { + mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + } +} + +void DirectiveParser::parseElif(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_ELIF); + + if (mConditionalStack.empty()) + { + mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_WITHOUT_IF, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + return; + } + + ConditionalBlock& block = mConditionalStack.back(); + if (block.skipBlock) + { + // No diagnostics. Just skip the whole line. + skipUntilEOD(mTokenizer, token); + return; + } + if (block.foundElseGroup) + { + mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_AFTER_ELSE, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + return; + } + if (block.foundValidGroup) + { + // Do not parse the expression. + // Also be careful not to emit a diagnostic. + block.skipGroup = true; + skipUntilEOD(mTokenizer, token); + return; + } + + int expression = parseExpressionIf(token); + block.skipGroup = expression == 0; + block.foundValidGroup = expression != 0; +} + +void DirectiveParser::parseEndif(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_ENDIF); + + if (mConditionalStack.empty()) + { + mDiagnostics->report(Diagnostics::CONDITIONAL_ENDIF_WITHOUT_IF, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + return; + } + + mConditionalStack.pop_back(); + + // Warn if there are tokens after #endif. + mTokenizer->lex(token); + if (!isEOD(token)) + { + mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + } +} + +void DirectiveParser::parseError(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_ERROR); + + std::ostringstream stream; + mTokenizer->lex(token); + while ((token->type != '\n') && (token->type != Token::LAST)) + { + stream << *token; + mTokenizer->lex(token); + } + mDirectiveHandler->handleError(token->location, stream.str()); +} + +// Parses pragma of form: #pragma name[(value)]. +void DirectiveParser::parsePragma(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_PRAGMA); + + enum State + { + PRAGMA_NAME, + LEFT_PAREN, + PRAGMA_VALUE, + RIGHT_PAREN + }; + + bool valid = true; + std::string name, value; + int state = PRAGMA_NAME; + + mTokenizer->lex(token); + while ((token->type != '\n') && (token->type != Token::LAST)) + { + switch(state++) + { + case PRAGMA_NAME: + name = token->text; + valid = valid && (token->type == Token::IDENTIFIER); + break; + case LEFT_PAREN: + valid = valid && (token->type == '('); + break; + case PRAGMA_VALUE: + value = token->text; + valid = valid && (token->type == Token::IDENTIFIER); + break; + case RIGHT_PAREN: + valid = valid && (token->type == ')'); + break; + default: + valid = false; + break; + } + mTokenizer->lex(token); + } + + valid = valid && ((state == PRAGMA_NAME) || // Empty pragma. + (state == LEFT_PAREN) || // Without value. + (state == RIGHT_PAREN + 1)); // With value. + if (!valid) + { + mDiagnostics->report(Diagnostics::UNRECOGNIZED_PRAGMA, + token->location, name); + } + else if (state > PRAGMA_NAME) // Do not notify for empty pragma. + { + mDirectiveHandler->handlePragma(token->location, name, value); + } +} + +void DirectiveParser::parseExtension(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_EXTENSION); + + enum State + { + EXT_NAME, + COLON, + EXT_BEHAVIOR + }; + + bool valid = true; + std::string name, behavior; + int state = EXT_NAME; + + mTokenizer->lex(token); + while ((token->type != '\n') && (token->type != Token::LAST)) + { + switch (state++) + { + case EXT_NAME: + if (valid && (token->type != Token::IDENTIFIER)) + { + mDiagnostics->report(Diagnostics::INVALID_EXTENSION_NAME, + token->location, token->text); + valid = false; + } + if (valid) name = token->text; + break; + case COLON: + if (valid && (token->type != ':')) + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, token->text); + valid = false; + } + break; + case EXT_BEHAVIOR: + if (valid && (token->type != Token::IDENTIFIER)) + { + mDiagnostics->report(Diagnostics::INVALID_EXTENSION_BEHAVIOR, + token->location, token->text); + valid = false; + } + if (valid) behavior = token->text; + break; + default: + if (valid) + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, token->text); + valid = false; + } + break; + } + mTokenizer->lex(token); + } + if (valid && (state != EXT_BEHAVIOR + 1)) + { + mDiagnostics->report(Diagnostics::INVALID_EXTENSION_DIRECTIVE, + token->location, token->text); + valid = false; + } + if (valid) + mDirectiveHandler->handleExtension(token->location, name, behavior); +} + +void DirectiveParser::parseVersion(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_VERSION); + + if (mPastFirstStatement) + { + mDiagnostics->report(Diagnostics::VERSION_NOT_FIRST_STATEMENT, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + return; + } + + enum State + { + VERSION_NUMBER + }; + + bool valid = true; + int version = 0; + int state = VERSION_NUMBER; + + mTokenizer->lex(token); + while ((token->type != '\n') && (token->type != Token::LAST)) + { + switch (state++) + { + case VERSION_NUMBER: + if (valid && (token->type != Token::CONST_INT)) + { + mDiagnostics->report(Diagnostics::INVALID_VERSION_NUMBER, + token->location, token->text); + valid = false; + } + if (valid && !token->iValue(&version)) + { + mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW, + token->location, token->text); + valid = false; + } + break; + default: + if (valid) + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, token->text); + valid = false; + } + break; + } + mTokenizer->lex(token); + } + if (valid && (state != VERSION_NUMBER + 1)) + { + mDiagnostics->report(Diagnostics::INVALID_VERSION_DIRECTIVE, + token->location, token->text); + valid = false; + } + if (valid) + mDirectiveHandler->handleVersion(token->location, version); +} + +void DirectiveParser::parseLine(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_LINE); + + enum State + { + LINE_NUMBER, + FILE_NUMBER + }; + + bool valid = true; + int line = 0, file = 0; + int state = LINE_NUMBER; + + MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics); + macroExpander.lex(token); + while ((token->type != '\n') && (token->type != Token::LAST)) + { + switch (state++) + { + case LINE_NUMBER: + if (valid && (token->type != Token::CONST_INT)) + { + mDiagnostics->report(Diagnostics::INVALID_LINE_NUMBER, + token->location, token->text); + valid = false; + } + if (valid && !token->iValue(&line)) + { + mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW, + token->location, token->text); + valid = false; + } + break; + case FILE_NUMBER: + if (valid && (token->type != Token::CONST_INT)) + { + mDiagnostics->report(Diagnostics::INVALID_FILE_NUMBER, + token->location, token->text); + valid = false; + } + if (valid && !token->iValue(&file)) + { + mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW, + token->location, token->text); + valid = false; + } + break; + default: + if (valid) + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, token->text); + valid = false; + } + break; + } + macroExpander.lex(token); + } + + if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1)) + { + mDiagnostics->report(Diagnostics::INVALID_LINE_DIRECTIVE, + token->location, token->text); + valid = false; + } + if (valid) + { + mTokenizer->setLineNumber(line); + if (state == FILE_NUMBER + 1) mTokenizer->setFileNumber(file); + } +} + +bool DirectiveParser::skipping() const +{ + if (mConditionalStack.empty()) return false; + + const ConditionalBlock& block = mConditionalStack.back(); + return block.skipBlock || block.skipGroup; +} + +void DirectiveParser::parseConditionalIf(Token* token) +{ + ConditionalBlock block; + block.type = token->text; + block.location = token->location; + + if (skipping()) + { + // This conditional block is inside another conditional group + // which is skipped. As a consequence this whole block is skipped. + // Be careful not to parse the conditional expression that might + // emit a diagnostic. + skipUntilEOD(mTokenizer, token); + block.skipBlock = true; + } + else + { + DirectiveType directive = getDirective(token); + + int expression = 0; + switch (directive) + { + case DIRECTIVE_IF: + expression = parseExpressionIf(token); + break; + case DIRECTIVE_IFDEF: + expression = parseExpressionIfdef(token); + break; + case DIRECTIVE_IFNDEF: + expression = parseExpressionIfdef(token) == 0 ? 1 : 0; + break; + default: + assert(false); + break; + } + block.skipGroup = expression == 0; + block.foundValidGroup = expression != 0; + } + mConditionalStack.push_back(block); +} + +int DirectiveParser::parseExpressionIf(Token* token) +{ + assert((getDirective(token) == DIRECTIVE_IF) || + (getDirective(token) == DIRECTIVE_ELIF)); + + DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics); + MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics); + ExpressionParser expressionParser(¯oExpander, mDiagnostics); + + int expression = 0; + macroExpander.lex(token); + expressionParser.parse(token, &expression); + + // Warn if there are tokens after #if expression. + if (!isEOD(token)) + { + mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + } + + return expression; +} + +int DirectiveParser::parseExpressionIfdef(Token* token) +{ + assert((getDirective(token) == DIRECTIVE_IFDEF) || + (getDirective(token) == DIRECTIVE_IFNDEF)); + + mTokenizer->lex(token); + if (token->type != Token::IDENTIFIER) + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + return 0; + } + + MacroSet::const_iterator iter = mMacroSet->find(token->text); + int expression = iter != mMacroSet->end() ? 1 : 0; + + // Warn if there are tokens after #ifdef expression. + mTokenizer->lex(token); + if (!isEOD(token)) + { + mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + } + return expression; +} + +} // namespace pp
diff --git a/src/GLES2/compiler/preprocessor/DirectiveParser.h b/src/GLES2/compiler/preprocessor/DirectiveParser.h new file mode 100644 index 0000000..7b07392 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/DirectiveParser.h
@@ -0,0 +1,82 @@ +// +// Copyright (c) 2012 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. +// + +#ifndef COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_ +#define COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_ + +#include "Lexer.h" +#include "Macro.h" +#include "pp_utils.h" +#include "SourceLocation.h" + +namespace pp +{ + +class Diagnostics; +class DirectiveHandler; +class Tokenizer; + +class DirectiveParser : public Lexer +{ + public: + DirectiveParser(Tokenizer* tokenizer, + MacroSet* macroSet, + Diagnostics* diagnostics, + DirectiveHandler* directiveHandler); + + virtual void lex(Token* token); + + private: + PP_DISALLOW_COPY_AND_ASSIGN(DirectiveParser); + + void parseDirective(Token* token); + void parseDefine(Token* token); + void parseUndef(Token* token); + void parseIf(Token* token); + void parseIfdef(Token* token); + void parseIfndef(Token* token); + void parseElse(Token* token); + void parseElif(Token* token); + void parseEndif(Token* token); + void parseError(Token* token); + void parsePragma(Token* token); + void parseExtension(Token* token); + void parseVersion(Token* token); + void parseLine(Token* token); + + bool skipping() const; + void parseConditionalIf(Token* token); + int parseExpressionIf(Token* token); + int parseExpressionIfdef(Token* token); + + struct ConditionalBlock + { + std::string type; + SourceLocation location; + bool skipBlock; + bool skipGroup; + bool foundValidGroup; + bool foundElseGroup; + + ConditionalBlock() : + skipBlock(false), + skipGroup(false), + foundValidGroup(false), + foundElseGroup(false) + { + } + }; + bool mPastFirstStatement; + std::vector<ConditionalBlock> mConditionalStack; + Tokenizer* mTokenizer; + MacroSet* mMacroSet; + Diagnostics* mDiagnostics; + DirectiveHandler* mDirectiveHandler; +}; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_ +
diff --git a/src/GLES2/compiler/preprocessor/ExpressionParser.cpp b/src/GLES2/compiler/preprocessor/ExpressionParser.cpp new file mode 100644 index 0000000..6bcae27 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/ExpressionParser.cpp
@@ -0,0 +1,1926 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.4.1" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + +/* Substitute the variable and function names. */ +#define yyparse ppparse +#define yylex pplex +#define yyerror pperror +#define yylval pplval +#define yychar ppchar +#define yydebug ppdebug +#define yynerrs ppnerrs + + +/* Copy the first part of user declarations. */ + + +// +// Copyright (c) 2012 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. +// + +// This file is auto-generated by generate_parser.sh. DO NOT EDIT! + +#if defined(__GNUC__) +// Triggered by the auto-generated pplval variable. +#pragma GCC diagnostic ignored "-Wuninitialized" +#elif defined(_MSC_VER) +#pragma warning(disable: 4065 4701) +#endif + +#include "ExpressionParser.h" + +#include <cassert> +#include <sstream> + +#include "Diagnostics.h" +#include "Lexer.h" +#include "Token.h" + +#if defined(_MSC_VER) +typedef __int64 YYSTYPE; +#else +#include <stdint.h> +typedef intmax_t YYSTYPE; +#endif // _MSC_VER +#define YYSTYPE_IS_TRIVIAL 1 +#define YYSTYPE_IS_DECLARED 1 + +namespace { +struct Context +{ + pp::Diagnostics* diagnostics; + pp::Lexer* lexer; + pp::Token* token; + int* result; +}; +} // namespace + + +static int yylex(YYSTYPE* lvalp, Context* context); +static void yyerror(Context* context, const char* reason); + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + TOK_CONST_INT = 258, + TOK_OP_OR = 259, + TOK_OP_AND = 260, + TOK_OP_NE = 261, + TOK_OP_EQ = 262, + TOK_OP_GE = 263, + TOK_OP_LE = 264, + TOK_OP_RIGHT = 265, + TOK_OP_LEFT = 266, + TOK_UNARY = 267 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef int YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + +/* Copy the second part of user declarations. */ + + + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 14 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 175 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 27 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 3 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 26 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 52 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 267 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 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, 23, 2, 2, 2, 21, 8, 2, + 25, 26, 19, 17, 2, 18, 2, 20, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 11, 2, 12, 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, 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, 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, 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, 1, 2, 3, 4, + 5, 9, 10, 13, 14, 15, 16, 22 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint8 yyprhs[] = +{ + 0, 0, 3, 5, 7, 11, 15, 19, 23, 27, + 31, 35, 39, 43, 47, 51, 55, 59, 63, 67, + 71, 75, 79, 82, 85, 88, 91 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 28, 0, -1, 29, -1, 3, -1, 29, 4, 29, + -1, 29, 5, 29, -1, 29, 6, 29, -1, 29, + 7, 29, -1, 29, 8, 29, -1, 29, 9, 29, + -1, 29, 10, 29, -1, 29, 13, 29, -1, 29, + 14, 29, -1, 29, 12, 29, -1, 29, 11, 29, + -1, 29, 15, 29, -1, 29, 16, 29, -1, 29, + 18, 29, -1, 29, 17, 29, -1, 29, 21, 29, + -1, 29, 20, 29, -1, 29, 19, 29, -1, 23, + 29, -1, 24, 29, -1, 18, 29, -1, 17, 29, + -1, 25, 29, 26, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint8 yyrline[] = +{ + 0, 85, 85, 92, 93, 96, 99, 102, 105, 108, + 111, 114, 117, 120, 123, 126, 129, 132, 135, 138, + 151, 164, 167, 170, 173, 176, 179 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "TOK_CONST_INT", "TOK_OP_OR", + "TOK_OP_AND", "'|'", "'^'", "'&'", "TOK_OP_NE", "TOK_OP_EQ", "'<'", + "'>'", "TOK_OP_GE", "TOK_OP_LE", "TOK_OP_RIGHT", "TOK_OP_LEFT", "'+'", + "'-'", "'*'", "'/'", "'%'", "TOK_UNARY", "'!'", "'~'", "'('", "')'", + "$accept", "input", "expression", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 124, 94, 38, 261, + 262, 60, 62, 263, 264, 265, 266, 43, 45, 42, + 47, 37, 267, 33, 126, 40, 41 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 27, 28, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 1, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 2, 2, 2, 2, 3 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 0, 3, 0, 0, 0, 0, 0, 0, 2, 25, + 24, 22, 23, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 4, 5, 6, 7, 8, 9, + 10, 14, 13, 11, 12, 15, 16, 18, 17, 21, + 20, 19 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 7, 8 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -11 +static const yytype_int16 yypact[] = +{ + 46, -11, 46, 46, 46, 46, 46, 12, 68, -11, + -11, -11, -11, 27, -11, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, -11, 85, 101, 116, 130, 143, 154, + 154, -10, -10, -10, -10, 37, 37, 31, 31, -11, + -11, -11 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -11, -11, -2 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -1 +static const yytype_uint8 yytable[] = +{ + 9, 10, 11, 12, 13, 26, 27, 28, 29, 30, + 31, 32, 14, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, + 30, 31, 32, 33, 28, 29, 30, 31, 32, 0, + 0, 0, 0, 2, 3, 0, 0, 0, 0, 4, + 5, 6, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 17, 18, 19, + 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[] = +{ + 2, 3, 4, 5, 6, 15, 16, 17, 18, 19, + 20, 21, 0, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 3, + 19, 20, 21, 26, 17, 18, 19, 20, 21, -1, + -1, -1, -1, 17, 18, -1, -1, -1, -1, 23, + 24, 25, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 6, 7, 8, + 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 + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 3, 17, 18, 23, 24, 25, 28, 29, 29, + 29, 29, 29, 29, 0, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 26, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (context, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, YYLEX_PARAM) +#else +# define YYLEX yylex (&yylval, context) +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, context); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, Context *context) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep, context) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + Context *context; +#endif +{ + if (!yyvaluep) + return; + YYUSE (context); +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, Context *context) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep, context) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + Context *context; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep, context); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule, Context *context) +#else +static void +yy_reduce_print (yyvsp, yyrule, context) + YYSTYPE *yyvsp; + int yyrule; + Context *context; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , context); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule, context); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, Context *context) +#else +static void +yydestruct (yymsg, yytype, yyvaluep, context) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; + Context *context; +#endif +{ + YYUSE (yyvaluep); + YYUSE (context); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (Context *context); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + + + +/*-------------------------. +| yyparse or yypush_parse. | +`-------------------------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (Context *context) +#else +int +yyparse (context) + Context *context; +#endif +#endif +{ +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: + + { + *(context->result) = static_cast<int>((yyvsp[(1) - (1)])); + YYACCEPT; + } + break; + + case 4: + + { + (yyval) = (yyvsp[(1) - (3)]) || (yyvsp[(3) - (3)]); + } + break; + + case 5: + + { + (yyval) = (yyvsp[(1) - (3)]) && (yyvsp[(3) - (3)]); + } + break; + + case 6: + + { + (yyval) = (yyvsp[(1) - (3)]) | (yyvsp[(3) - (3)]); + } + break; + + case 7: + + { + (yyval) = (yyvsp[(1) - (3)]) ^ (yyvsp[(3) - (3)]); + } + break; + + case 8: + + { + (yyval) = (yyvsp[(1) - (3)]) & (yyvsp[(3) - (3)]); + } + break; + + case 9: + + { + (yyval) = (yyvsp[(1) - (3)]) != (yyvsp[(3) - (3)]); + } + break; + + case 10: + + { + (yyval) = (yyvsp[(1) - (3)]) == (yyvsp[(3) - (3)]); + } + break; + + case 11: + + { + (yyval) = (yyvsp[(1) - (3)]) >= (yyvsp[(3) - (3)]); + } + break; + + case 12: + + { + (yyval) = (yyvsp[(1) - (3)]) <= (yyvsp[(3) - (3)]); + } + break; + + case 13: + + { + (yyval) = (yyvsp[(1) - (3)]) > (yyvsp[(3) - (3)]); + } + break; + + case 14: + + { + (yyval) = (yyvsp[(1) - (3)]) < (yyvsp[(3) - (3)]); + } + break; + + case 15: + + { + (yyval) = (yyvsp[(1) - (3)]) >> (yyvsp[(3) - (3)]); + } + break; + + case 16: + + { + (yyval) = (yyvsp[(1) - (3)]) << (yyvsp[(3) - (3)]); + } + break; + + case 17: + + { + (yyval) = (yyvsp[(1) - (3)]) - (yyvsp[(3) - (3)]); + } + break; + + case 18: + + { + (yyval) = (yyvsp[(1) - (3)]) + (yyvsp[(3) - (3)]); + } + break; + + case 19: + + { + if ((yyvsp[(3) - (3)]) == 0) { + std::ostringstream stream; + stream << (yyvsp[(1) - (3)]) << " % " << (yyvsp[(3) - (3)]); + std::string text = stream.str(); + context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO, + context->token->location, + text.c_str()); + YYABORT; + } else { + (yyval) = (yyvsp[(1) - (3)]) % (yyvsp[(3) - (3)]); + } + } + break; + + case 20: + + { + if ((yyvsp[(3) - (3)]) == 0) { + std::ostringstream stream; + stream << (yyvsp[(1) - (3)]) << " / " << (yyvsp[(3) - (3)]); + std::string text = stream.str(); + context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO, + context->token->location, + text.c_str()); + YYABORT; + } else { + (yyval) = (yyvsp[(1) - (3)]) / (yyvsp[(3) - (3)]); + } + } + break; + + case 21: + + { + (yyval) = (yyvsp[(1) - (3)]) * (yyvsp[(3) - (3)]); + } + break; + + case 22: + + { + (yyval) = ! (yyvsp[(2) - (2)]); + } + break; + + case 23: + + { + (yyval) = ~ (yyvsp[(2) - (2)]); + } + break; + + case 24: + + { + (yyval) = - (yyvsp[(2) - (2)]); + } + break; + + case 25: + + { + (yyval) = + (yyvsp[(2) - (2)]); + } + break; + + case 26: + + { + (yyval) = (yyvsp[(2) - (3)]); + } + break; + + + + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (context, YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (context, yymsg); + } + else + { + yyerror (context, YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, context); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp, context); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (context, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, context); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, context); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + + + +int yylex(YYSTYPE* lvalp, Context* context) +{ + int type = 0; + + pp::Token* token = context->token; + switch (token->type) + { + case pp::Token::CONST_INT: + { + unsigned int val = 0; + if (!token->uValue(&val)) + { + context->diagnostics->report(pp::Diagnostics::INTEGER_OVERFLOW, + token->location, token->text); + } + *lvalp = static_cast<YYSTYPE>(val); + type = TOK_CONST_INT; + break; + } + case pp::Token::OP_OR: type = TOK_OP_OR; break; + case pp::Token::OP_AND: type = TOK_OP_AND; break; + case pp::Token::OP_NE: type = TOK_OP_NE; break; + case pp::Token::OP_EQ: type = TOK_OP_EQ; break; + case pp::Token::OP_GE: type = TOK_OP_GE; break; + case pp::Token::OP_LE: type = TOK_OP_LE; break; + case pp::Token::OP_RIGHT: type = TOK_OP_RIGHT; break; + case pp::Token::OP_LEFT: type = TOK_OP_LEFT; break; + case '|': type = '|'; break; + case '^': type = '^'; break; + case '&': type = '&'; break; + case '>': type = '>'; break; + case '<': type = '<'; break; + case '-': type = '-'; break; + case '+': type = '+'; break; + case '%': type = '%'; break; + case '/': type = '/'; break; + case '*': type = '*'; break; + case '!': type = '!'; break; + case '~': type = '~'; break; + case '(': type = '('; break; + case ')': type = ')'; break; + + default: break; + } + + // Advance to the next token if the current one is valid. + if (type != 0) context->lexer->lex(token); + + return type; +} + +void yyerror(Context* context, const char* reason) +{ + context->diagnostics->report(pp::Diagnostics::INVALID_EXPRESSION, + context->token->location, + reason); +} + +namespace pp { + +ExpressionParser::ExpressionParser(Lexer* lexer, Diagnostics* diagnostics) : + mLexer(lexer), + mDiagnostics(diagnostics) +{ +} + +bool ExpressionParser::parse(Token* token, int* result) +{ + Context context; + context.diagnostics = mDiagnostics; + context.lexer = mLexer; + context.token = token; + context.result = result; + int ret = yyparse(&context); + switch (ret) + { + case 0: + case 1: + break; + + case 2: + mDiagnostics->report(Diagnostics::OUT_OF_MEMORY, token->location, ""); + break; + + default: + assert(false); + mDiagnostics->report(Diagnostics::INTERNAL_ERROR, token->location, ""); + break; + } + + return ret == 0; +} + +} // namespace pp +
diff --git a/src/GLES2/compiler/preprocessor/ExpressionParser.h b/src/GLES2/compiler/preprocessor/ExpressionParser.h new file mode 100644 index 0000000..3ee5b7a --- /dev/null +++ b/src/GLES2/compiler/preprocessor/ExpressionParser.h
@@ -0,0 +1,34 @@ +// +// Copyright (c) 2012 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. +// + +#ifndef COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_ +#define COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_ + +#include "pp_utils.h" + +namespace pp +{ + +class Diagnostics; +class Lexer; +struct Token; + +class ExpressionParser +{ + public: + ExpressionParser(Lexer* lexer, Diagnostics* diagnostics); + + bool parse(Token* token, int* result); + + private: + PP_DISALLOW_COPY_AND_ASSIGN(ExpressionParser); + + Lexer* mLexer; + Diagnostics* mDiagnostics; +}; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_
diff --git a/src/GLES2/compiler/preprocessor/ExpressionParser.y b/src/GLES2/compiler/preprocessor/ExpressionParser.y new file mode 100644 index 0000000..2104d77 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/ExpressionParser.y
@@ -0,0 +1,279 @@ +/* +// +// Copyright (c) 2012 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. +// + +This file contains the Yacc grammar for GLSL ES preprocessor expression. + +IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh, +WHICH GENERATES THE GLSL ES preprocessor expression parser. +*/ + +%{ +// +// Copyright (c) 2012 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. +// + +// This file is auto-generated by generate_parser.sh. DO NOT EDIT! + +#if defined(__GNUC__) +// Triggered by the auto-generated pplval variable. +#pragma GCC diagnostic ignored "-Wuninitialized" +#elif defined(_MSC_VER) +#pragma warning(disable: 4065 4701) +#endif + +#include "ExpressionParser.h" + +#include <cassert> +#include <sstream> + +#include "Diagnostics.h" +#include "Lexer.h" +#include "Token.h" + +#if defined(_MSC_VER) +typedef __int64 YYSTYPE; +#else +#include <stdint.h> +typedef intmax_t YYSTYPE; +#endif // _MSC_VER +#define YYSTYPE_IS_TRIVIAL 1 +#define YYSTYPE_IS_DECLARED 1 + +namespace { +struct Context +{ + pp::Diagnostics* diagnostics; + pp::Lexer* lexer; + pp::Token* token; + int* result; +}; +} // namespace +%} + +%pure-parser +%name-prefix="pp" +%parse-param {Context *context} +%lex-param {Context *context} + +%{ +static int yylex(YYSTYPE* lvalp, Context* context); +static void yyerror(Context* context, const char* reason); +%} + +%token TOK_CONST_INT +%left TOK_OP_OR +%left TOK_OP_AND +%left '|' +%left '^' +%left '&' +%left TOK_OP_EQ TOK_OP_NE +%left '<' '>' TOK_OP_LE TOK_OP_GE +%left TOK_OP_LEFT TOK_OP_RIGHT +%left '+' '-' +%left '*' '/' '%' +%right TOK_UNARY + +%% + +input + : expression { + *(context->result) = static_cast<int>($1); + YYACCEPT; + } +; + +expression + : TOK_CONST_INT + | expression TOK_OP_OR expression { + $$ = $1 || $3; + } + | expression TOK_OP_AND expression { + $$ = $1 && $3; + } + | expression '|' expression { + $$ = $1 | $3; + } + | expression '^' expression { + $$ = $1 ^ $3; + } + | expression '&' expression { + $$ = $1 & $3; + } + | expression TOK_OP_NE expression { + $$ = $1 != $3; + } + | expression TOK_OP_EQ expression { + $$ = $1 == $3; + } + | expression TOK_OP_GE expression { + $$ = $1 >= $3; + } + | expression TOK_OP_LE expression { + $$ = $1 <= $3; + } + | expression '>' expression { + $$ = $1 > $3; + } + | expression '<' expression { + $$ = $1 < $3; + } + | expression TOK_OP_RIGHT expression { + $$ = $1 >> $3; + } + | expression TOK_OP_LEFT expression { + $$ = $1 << $3; + } + | expression '-' expression { + $$ = $1 - $3; + } + | expression '+' expression { + $$ = $1 + $3; + } + | expression '%' expression { + if ($3 == 0) { + std::ostringstream stream; + stream << $1 << " % " << $3; + std::string text = stream.str(); + context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO, + context->token->location, + text.c_str()); + YYABORT; + } else { + $$ = $1 % $3; + } + } + | expression '/' expression { + if ($3 == 0) { + std::ostringstream stream; + stream << $1 << " / " << $3; + std::string text = stream.str(); + context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO, + context->token->location, + text.c_str()); + YYABORT; + } else { + $$ = $1 / $3; + } + } + | expression '*' expression { + $$ = $1 * $3; + } + | '!' expression %prec TOK_UNARY { + $$ = ! $2; + } + | '~' expression %prec TOK_UNARY { + $$ = ~ $2; + } + | '-' expression %prec TOK_UNARY { + $$ = - $2; + } + | '+' expression %prec TOK_UNARY { + $$ = + $2; + } + | '(' expression ')' { + $$ = $2; + } +; + +%% + +int yylex(YYSTYPE* lvalp, Context* context) +{ + int type = 0; + + pp::Token* token = context->token; + switch (token->type) + { + case pp::Token::CONST_INT: + { + unsigned int val = 0; + if (!token->uValue(&val)) + { + context->diagnostics->report(pp::Diagnostics::INTEGER_OVERFLOW, + token->location, token->text); + } + *lvalp = static_cast<YYSTYPE>(val); + type = TOK_CONST_INT; + break; + } + case pp::Token::OP_OR: type = TOK_OP_OR; break; + case pp::Token::OP_AND: type = TOK_OP_AND; break; + case pp::Token::OP_NE: type = TOK_OP_NE; break; + case pp::Token::OP_EQ: type = TOK_OP_EQ; break; + case pp::Token::OP_GE: type = TOK_OP_GE; break; + case pp::Token::OP_LE: type = TOK_OP_LE; break; + case pp::Token::OP_RIGHT: type = TOK_OP_RIGHT; break; + case pp::Token::OP_LEFT: type = TOK_OP_LEFT; break; + case '|': type = '|'; break; + case '^': type = '^'; break; + case '&': type = '&'; break; + case '>': type = '>'; break; + case '<': type = '<'; break; + case '-': type = '-'; break; + case '+': type = '+'; break; + case '%': type = '%'; break; + case '/': type = '/'; break; + case '*': type = '*'; break; + case '!': type = '!'; break; + case '~': type = '~'; break; + case '(': type = '('; break; + case ')': type = ')'; break; + + default: break; + } + + // Advance to the next token if the current one is valid. + if (type != 0) context->lexer->lex(token); + + return type; +} + +void yyerror(Context* context, const char* reason) +{ + context->diagnostics->report(pp::Diagnostics::INVALID_EXPRESSION, + context->token->location, + reason); +} + +namespace pp { + +ExpressionParser::ExpressionParser(Lexer* lexer, Diagnostics* diagnostics) : + mLexer(lexer), + mDiagnostics(diagnostics) +{ +} + +bool ExpressionParser::parse(Token* token, int* result) +{ + Context context; + context.diagnostics = mDiagnostics; + context.lexer = mLexer; + context.token = token; + context.result = result; + int ret = yyparse(&context); + switch (ret) + { + case 0: + case 1: + break; + + case 2: + mDiagnostics->report(Diagnostics::OUT_OF_MEMORY, token->location, ""); + break; + + default: + assert(false); + mDiagnostics->report(Diagnostics::INTERNAL_ERROR, token->location, ""); + break; + } + + return ret == 0; +} + +} // namespace pp
diff --git a/src/GLES2/compiler/preprocessor/Input.cpp b/src/GLES2/compiler/preprocessor/Input.cpp new file mode 100644 index 0000000..5cbf138 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/Input.cpp
@@ -0,0 +1,55 @@ +// +// Copyright (c) 2011 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 "Input.h" + +#include <algorithm> +#include <cassert> +#include <cstring> + +namespace pp +{ + +Input::Input() : mCount(0), mString(0) +{ +} + +Input::Input(int count, const char* const string[], const int length[]) : + mCount(count), + mString(string) +{ + assert(mCount >= 0); + mLength.reserve(mCount); + for (int i = 0; i < mCount; ++i) + { + int len = length ? length[i] : -1; + mLength.push_back(len < 0 ? strlen(mString[i]) : len); + } +} + +int Input::read(char* buf, int maxSize) +{ + int nRead = 0; + while ((nRead < maxSize) && (mReadLoc.sIndex < mCount)) + { + int size = mLength[mReadLoc.sIndex] - mReadLoc.cIndex; + size = std::min(size, maxSize); + memcpy(buf + nRead, mString[mReadLoc.sIndex] + mReadLoc.cIndex, size); + nRead += size; + mReadLoc.cIndex += size; + + // Advance string if we reached the end of current string. + if (mReadLoc.cIndex == mLength[mReadLoc.sIndex]) + { + ++mReadLoc.sIndex; + mReadLoc.cIndex = 0; + } + } + return nRead; +} + +} // namespace pp +
diff --git a/src/GLES2/compiler/preprocessor/Input.h b/src/GLES2/compiler/preprocessor/Input.h new file mode 100644 index 0000000..8e5b1e9 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/Input.h
@@ -0,0 +1,48 @@ +// +// Copyright (c) 2011 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. +// + +#ifndef COMPILER_PREPROCESSOR_INPUT_H_ +#define COMPILER_PREPROCESSOR_INPUT_H_ + +#include <vector> + +namespace pp +{ + +// Holds and reads input for Lexer. +class Input +{ + public: + Input(); + Input(int count, const char* const string[], const int length[]); + + int count() const { return mCount; } + const char* string(int index) const { return mString[index]; } + int length(int index) const { return mLength[index]; } + + int read(char* buf, int maxSize); + + struct Location + { + int sIndex; // String index; + int cIndex; // Char index. + + Location() : sIndex(0), cIndex(0) { } + }; + const Location& readLoc() const { return mReadLoc; } + + private: + // Input. + int mCount; + const char* const* mString; + std::vector<int> mLength; + + Location mReadLoc; +}; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_INPUT_H_ +
diff --git a/src/GLES2/compiler/preprocessor/Lexer.cpp b/src/GLES2/compiler/preprocessor/Lexer.cpp new file mode 100644 index 0000000..231a906 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/Lexer.cpp
@@ -0,0 +1,16 @@ +// +// Copyright (c) 2012 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 "Lexer.h" + +namespace pp +{ + +Lexer::~Lexer() +{ +} + +} // namespace pp
diff --git a/src/GLES2/compiler/preprocessor/Lexer.h b/src/GLES2/compiler/preprocessor/Lexer.h new file mode 100644 index 0000000..cb29a10 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/Lexer.h
@@ -0,0 +1,25 @@ +// +// Copyright (c) 2012 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. +// + +#ifndef COMPILER_PREPROCESSOR_LEXER_H_ +#define COMPILER_PREPROCESSOR_LEXER_H_ + +namespace pp +{ + +struct Token; + +class Lexer +{ + public: + virtual ~Lexer(); + + virtual void lex(Token* token) = 0; +}; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_LEXER_H_ +
diff --git a/src/GLES2/compiler/preprocessor/Macro.cpp b/src/GLES2/compiler/preprocessor/Macro.cpp new file mode 100644 index 0000000..3c57afe --- /dev/null +++ b/src/GLES2/compiler/preprocessor/Macro.cpp
@@ -0,0 +1,23 @@ +// +// Copyright (c) 2011 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 "Macro.h" + +#include "Token.h" + +namespace pp +{ + +bool Macro::equals(const Macro& other) const +{ + return (type == other.type) && + (name == other.name) && + (parameters == other.parameters) && + (replacements == other.replacements); +} + +} // namespace pp +
diff --git a/src/GLES2/compiler/preprocessor/Macro.h b/src/GLES2/compiler/preprocessor/Macro.h new file mode 100644 index 0000000..36faae9 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/Macro.h
@@ -0,0 +1,44 @@ +// +// Copyright (c) 2012 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. +// + +#ifndef COMPILER_PREPROCESSOR_MACRO_H_ +#define COMPILER_PREPROCESSOR_MACRO_H_ + +#include <map> +#include <string> +#include <vector> + +namespace pp +{ + +struct Token; + +struct Macro +{ + enum Type + { + kTypeObj, + kTypeFunc + }; + typedef std::vector<std::string> Parameters; + typedef std::vector<Token> Replacements; + + Macro() : predefined(false), disabled(false), type(kTypeObj) { } + bool equals(const Macro& other) const; + + bool predefined; + mutable bool disabled; + + Type type; + std::string name; + Parameters parameters; + Replacements replacements; +}; + +typedef std::map<std::string, Macro> MacroSet; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_MACRO_H_
diff --git a/src/GLES2/compiler/preprocessor/MacroExpander.cpp b/src/GLES2/compiler/preprocessor/MacroExpander.cpp new file mode 100644 index 0000000..d8bbe8b --- /dev/null +++ b/src/GLES2/compiler/preprocessor/MacroExpander.cpp
@@ -0,0 +1,370 @@ +// +// Copyright (c) 2011 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 "MacroExpander.h" + +#include <algorithm> +#include <sstream> + +#include "Diagnostics.h" +#include "Token.h" + +namespace pp +{ + +class TokenLexer : public Lexer +{ + public: + typedef std::vector<Token> TokenVector; + + TokenLexer(TokenVector* tokens) + { + tokens->swap(mTokens); + mIter = mTokens.begin(); + } + + virtual void lex(Token* token) + { + if (mIter == mTokens.end()) + { + token->reset(); + token->type = Token::LAST; + } + else + { + *token = *mIter++; + } + } + + private: + PP_DISALLOW_COPY_AND_ASSIGN(TokenLexer); + + TokenVector mTokens; + TokenVector::const_iterator mIter; +}; + +MacroExpander::MacroExpander(Lexer* lexer, + MacroSet* macroSet, + Diagnostics* diagnostics) : + mLexer(lexer), + mMacroSet(macroSet), + mDiagnostics(diagnostics) +{ +} + +MacroExpander::~MacroExpander() +{ + for (size_t i = 0; i < mContextStack.size(); ++i) + { + delete mContextStack[i]; + } +} + +void MacroExpander::lex(Token* token) +{ + while (true) + { + getToken(token); + + if (token->type != Token::IDENTIFIER) + break; + + if (token->expansionDisabled()) + break; + + MacroSet::const_iterator iter = mMacroSet->find(token->text); + if (iter == mMacroSet->end()) + break; + + const Macro& macro = iter->second; + if (macro.disabled) + { + // If a particular token is not expanded, it is never expanded. + token->setExpansionDisabled(true); + break; + } + if ((macro.type == Macro::kTypeFunc) && !isNextTokenLeftParen()) + { + // If the token immediately after the macro name is not a '(', + // this macro should not be expanded. + break; + } + + pushMacro(macro, *token); + } +} + +void MacroExpander::getToken(Token* token) +{ + if (mReserveToken.get()) + { + *token = *mReserveToken; + mReserveToken.reset(); + return; + } + + // First pop all empty macro contexts. + while (!mContextStack.empty() && mContextStack.back()->empty()) + { + popMacro(); + } + + if (!mContextStack.empty()) + { + *token = mContextStack.back()->get(); + } + else + { + mLexer->lex(token); + } +} + +void MacroExpander::ungetToken(const Token& token) +{ + if (!mContextStack.empty()) + { + MacroContext* context = mContextStack.back(); + context->unget(); + assert(context->replacements[context->index] == token); + } + else + { + assert(!mReserveToken.get()); + mReserveToken.reset(new Token(token)); + } +} + +bool MacroExpander::isNextTokenLeftParen() +{ + Token token; + getToken(&token); + + bool lparen = token.type == '('; + ungetToken(token); + + return lparen; +} + +bool MacroExpander::pushMacro(const Macro& macro, const Token& identifier) +{ + assert(!macro.disabled); + assert(!identifier.expansionDisabled()); + assert(identifier.type == Token::IDENTIFIER); + assert(identifier.text == macro.name); + + std::vector<Token> replacements; + if (!expandMacro(macro, identifier, &replacements)) + return false; + + // Macro is disabled for expansion until it is popped off the stack. + macro.disabled = true; + + MacroContext* context = new MacroContext; + context->macro = ¯o; + context->replacements.swap(replacements); + mContextStack.push_back(context); + return true; +} + +void MacroExpander::popMacro() +{ + assert(!mContextStack.empty()); + + MacroContext* context = mContextStack.back(); + mContextStack.pop_back(); + + assert(context->empty()); + assert(context->macro->disabled); + context->macro->disabled = false; + delete context; +} + +bool MacroExpander::expandMacro(const Macro& macro, + const Token& identifier, + std::vector<Token>* replacements) +{ + replacements->clear(); + if (macro.type == Macro::kTypeObj) + { + replacements->assign(macro.replacements.begin(), + macro.replacements.end()); + + if (macro.predefined) + { + static const std::string kLine = "__LINE__"; + static const std::string kFile = "__FILE__"; + + assert(replacements->size() == 1); + Token& repl = replacements->front(); + if (macro.name == kLine) + { + std::ostringstream stream; + stream << identifier.location.line; + repl.text = stream.str(); + } + else if (macro.name == kFile) + { + std::ostringstream stream; + stream << identifier.location.file; + repl.text = stream.str(); + } + } + } + else + { + assert(macro.type == Macro::kTypeFunc); + std::vector<MacroArg> args; + args.reserve(macro.parameters.size()); + if (!collectMacroArgs(macro, identifier, &args)) + return false; + + replaceMacroParams(macro, args, replacements); + } + + for (size_t i = 0; i < replacements->size(); ++i) + { + Token& repl = replacements->at(i); + if (i == 0) + { + // The first token in the replacement list inherits the padding + // properties of the identifier token. + repl.setAtStartOfLine(identifier.atStartOfLine()); + repl.setHasLeadingSpace(identifier.hasLeadingSpace()); + } + repl.location = identifier.location; + } + return true; +} + +bool MacroExpander::collectMacroArgs(const Macro& macro, + const Token& identifier, + std::vector<MacroArg>* args) +{ + Token token; + getToken(&token); + assert(token.type == '('); + + args->push_back(MacroArg()); + for (int openParens = 1; openParens != 0; ) + { + getToken(&token); + + if (token.type == Token::LAST) + { + mDiagnostics->report(Diagnostics::MACRO_UNTERMINATED_INVOCATION, + identifier.location, identifier.text); + // Do not lose EOF token. + ungetToken(token); + return false; + } + + bool isArg = false; // True if token is part of the current argument. + switch (token.type) + { + case '(': + ++openParens; + isArg = true; + break; + case ')': + --openParens; + isArg = openParens != 0; + break; + case ',': + // The individual arguments are separated by comma tokens, but + // the comma tokens between matching inner parentheses do not + // seperate arguments. + if (openParens == 1) args->push_back(MacroArg()); + isArg = openParens != 1; + break; + default: + isArg = true; + break; + } + if (isArg) + { + MacroArg& arg = args->back(); + // Initial whitespace is not part of the argument. + if (arg.empty()) token.setHasLeadingSpace(false); + arg.push_back(token); + } + } + + const Macro::Parameters& params = macro.parameters; + // If there is only one empty argument, it is equivalent to no argument. + if (params.empty() && (args->size() == 1) && args->front().empty()) + { + args->clear(); + } + // Validate the number of arguments. + if (args->size() != params.size()) + { + Diagnostics::ID id = args->size() < macro.parameters.size() ? + Diagnostics::MACRO_TOO_FEW_ARGS : + Diagnostics::MACRO_TOO_MANY_ARGS; + mDiagnostics->report(id, identifier.location, identifier.text); + return false; + } + + // Pre-expand each argument before substitution. + // This step expands each argument individually before they are + // inserted into the macro body. + for (size_t i = 0; i < args->size(); ++i) + { + MacroArg& arg = args->at(i); + TokenLexer lexer(&arg); + MacroExpander expander(&lexer, mMacroSet, mDiagnostics); + + arg.clear(); + expander.lex(&token); + while (token.type != Token::LAST) + { + arg.push_back(token); + expander.lex(&token); + } + } + return true; +} + +void MacroExpander::replaceMacroParams(const Macro& macro, + const std::vector<MacroArg>& args, + std::vector<Token>* replacements) +{ + for (size_t i = 0; i < macro.replacements.size(); ++i) + { + const Token& repl = macro.replacements[i]; + if (repl.type != Token::IDENTIFIER) + { + replacements->push_back(repl); + continue; + } + + // TODO(alokp): Optimize this. + // There is no need to search for macro params every time. + // The param index can be cached with the replacement token. + Macro::Parameters::const_iterator iter = std::find( + macro.parameters.begin(), macro.parameters.end(), repl.text); + if (iter == macro.parameters.end()) + { + replacements->push_back(repl); + continue; + } + + size_t iArg = std::distance(macro.parameters.begin(), iter); + const MacroArg& arg = args[iArg]; + if (arg.empty()) + { + continue; + } + size_t iRepl = replacements->size(); + replacements->insert(replacements->end(), arg.begin(), arg.end()); + // The replacement token inherits padding properties from + // macro replacement token. + replacements->at(iRepl).setHasLeadingSpace(repl.hasLeadingSpace()); + } +} + +} // namespace pp +
diff --git a/src/GLES2/compiler/preprocessor/MacroExpander.h b/src/GLES2/compiler/preprocessor/MacroExpander.h new file mode 100644 index 0000000..b10b01f --- /dev/null +++ b/src/GLES2/compiler/preprocessor/MacroExpander.h
@@ -0,0 +1,75 @@ +// +// Copyright (c) 2012 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. +// + +#ifndef COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_ +#define COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_ + +#include <cassert> +#include <memory> +#include <vector> + +#include "Lexer.h" +#include "Macro.h" +#include "pp_utils.h" + +namespace pp +{ + +class Diagnostics; + +class MacroExpander : public Lexer +{ + public: + MacroExpander(Lexer* lexer, MacroSet* macroSet, Diagnostics* diagnostics); + virtual ~MacroExpander(); + + virtual void lex(Token* token); + + private: + PP_DISALLOW_COPY_AND_ASSIGN(MacroExpander); + + void getToken(Token* token); + void ungetToken(const Token& token); + bool isNextTokenLeftParen(); + + bool pushMacro(const Macro& macro, const Token& identifier); + void popMacro(); + + bool expandMacro(const Macro& macro, + const Token& identifier, + std::vector<Token>* replacements); + + typedef std::vector<Token> MacroArg; + bool collectMacroArgs(const Macro& macro, + const Token& identifier, + std::vector<MacroArg>* args); + void replaceMacroParams(const Macro& macro, + const std::vector<MacroArg>& args, + std::vector<Token>* replacements); + + struct MacroContext + { + const Macro* macro; + size_t index; + std::vector<Token> replacements; + + MacroContext() : macro(0), index(0) { } + bool empty() const { return index == replacements.size(); } + const Token& get() { return replacements[index++]; } + void unget() { assert(index > 0); --index; } + }; + + Lexer* mLexer; + MacroSet* mMacroSet; + Diagnostics* mDiagnostics; + + std::auto_ptr<Token> mReserveToken; + std::vector<MacroContext*> mContextStack; +}; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_ +
diff --git a/src/GLES2/compiler/preprocessor/Preprocessor.cpp b/src/GLES2/compiler/preprocessor/Preprocessor.cpp new file mode 100644 index 0000000..296c8aa --- /dev/null +++ b/src/GLES2/compiler/preprocessor/Preprocessor.cpp
@@ -0,0 +1,142 @@ +// +// Copyright (c) 2011 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 "Preprocessor.h" + +#include <cassert> +#include <sstream> + +#include "Diagnostics.h" +#include "DirectiveParser.h" +#include "Macro.h" +#include "MacroExpander.h" +#include "Token.h" +#include "Tokenizer.h" + +namespace pp +{ + +struct PreprocessorImpl +{ + Diagnostics* diagnostics; + MacroSet macroSet; + Tokenizer tokenizer; + DirectiveParser directiveParser; + MacroExpander macroExpander; + + PreprocessorImpl(Diagnostics* diag, + DirectiveHandler* directiveHandler) : + diagnostics(diag), + tokenizer(diag), + directiveParser(&tokenizer, ¯oSet, diag, directiveHandler), + macroExpander(&directiveParser, ¯oSet, diag) + { + } +}; + +Preprocessor::Preprocessor(Diagnostics* diagnostics, + DirectiveHandler* directiveHandler) +{ + mImpl = new PreprocessorImpl(diagnostics, directiveHandler); +} + +Preprocessor::~Preprocessor() +{ + delete mImpl; +} + +bool Preprocessor::init(int count, + const char* const string[], + const int length[]) +{ + static const int kGLSLVersion = 100; + + // Add standard pre-defined macros. + predefineMacro("__LINE__", 0); + predefineMacro("__FILE__", 0); + predefineMacro("__VERSION__", kGLSLVersion); + predefineMacro("GL_ES", 1); + + return mImpl->tokenizer.init(count, string, length); +} + +void Preprocessor::predefineMacro(const char* name, int value) +{ + std::ostringstream stream; + stream << value; + + Token token; + token.type = Token::CONST_INT; + token.text = stream.str(); + + Macro macro; + macro.predefined = true; + macro.type = Macro::kTypeObj; + macro.name = name; + macro.replacements.push_back(token); + + mImpl->macroSet[name] = macro; +} + +void Preprocessor::lex(Token* token) +{ + bool validToken = false; + while (!validToken) + { + mImpl->macroExpander.lex(token); + switch (token->type) + { + // We should not be returning internal preprocessing tokens. + // Convert preprocessing tokens to compiler tokens or report + // diagnostics. + case Token::PP_HASH: + assert(false); + break; + case Token::CONST_INT: + { + int val = 0; + if (!token->iValue(&val)) + { + // Do not mark the token as invalid. + // Just emit the diagnostic and reset value to 0. + mImpl->diagnostics->report(Diagnostics::INTEGER_OVERFLOW, + token->location, token->text); + token->text.assign("0"); + } + validToken = true; + break; + } + case Token::CONST_FLOAT: + { + float val = 0; + if (!token->fValue(&val)) + { + // Do not mark the token as invalid. + // Just emit the diagnostic and reset value to 0.0. + mImpl->diagnostics->report(Diagnostics::FLOAT_OVERFLOW, + token->location, token->text); + token->text.assign("0.0"); + } + validToken = true; + break; + } + case Token::PP_NUMBER: + mImpl->diagnostics->report(Diagnostics::INVALID_NUMBER, + token->location, token->text); + break; + case Token::PP_OTHER: + mImpl->diagnostics->report(Diagnostics::INVALID_CHARACTER, + token->location, token->text); + break; + default: + validToken = true; + break; + } + } +} + +} // namespace pp +
diff --git a/src/GLES2/compiler/preprocessor/Preprocessor.h b/src/GLES2/compiler/preprocessor/Preprocessor.h new file mode 100644 index 0000000..7a54da0 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/Preprocessor.h
@@ -0,0 +1,49 @@ +// +// Copyright (c) 2011 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. +// + +#ifndef COMPILER_PREPROCESSOR_PREPROCESSOR_H_ +#define COMPILER_PREPROCESSOR_PREPROCESSOR_H_ + +#include "pp_utils.h" + +namespace pp +{ + +class Diagnostics; +class DirectiveHandler; +struct PreprocessorImpl; +struct Token; + +class Preprocessor +{ + public: + Preprocessor(Diagnostics* diagnostics, DirectiveHandler* directiveHandler); + ~Preprocessor(); + + // count: specifies the number of elements in the string and length arrays. + // string: specifies an array of pointers to strings. + // length: specifies an array of string lengths. + // If length is NULL, each string is assumed to be null terminated. + // If length is a value other than NULL, it points to an array containing + // a string length for each of the corresponding elements of string. + // Each element in the length array may contain the length of the + // corresponding string or a value less than 0 to indicate that the string + // is null terminated. + bool init(int count, const char* const string[], const int length[]); + // Adds a pre-defined macro. + void predefineMacro(const char* name, int value); + + void lex(Token* token); + + private: + PP_DISALLOW_COPY_AND_ASSIGN(Preprocessor); + + PreprocessorImpl* mImpl; +}; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_PREPROCESSOR_H_ +
diff --git a/src/GLES2/compiler/preprocessor/SourceLocation.h b/src/GLES2/compiler/preprocessor/SourceLocation.h new file mode 100644 index 0000000..9c0d1d3 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/SourceLocation.h
@@ -0,0 +1,38 @@ +// +// Copyright (c) 2012 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. +// + +#ifndef COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_ +#define COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_ + +namespace pp +{ + +struct SourceLocation +{ + SourceLocation() : file(0), line(0) { } + SourceLocation(int f, int l) : file(f), line(l) { } + + bool equals(const SourceLocation& other) const + { + return (file == other.file) && (line == other.line); + } + + int file; + int line; +}; + +inline bool operator==(const SourceLocation& lhs, const SourceLocation& rhs) +{ + return lhs.equals(rhs); +} + +inline bool operator!=(const SourceLocation& lhs, const SourceLocation& rhs) +{ + return !lhs.equals(rhs); +} + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_
diff --git a/src/GLES2/compiler/preprocessor/Token.cpp b/src/GLES2/compiler/preprocessor/Token.cpp new file mode 100644 index 0000000..a465aa1 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/Token.cpp
@@ -0,0 +1,83 @@ +// +// Copyright (c) 2011 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 "Token.h" + +#include <cassert> + +#include "numeric_lex.h" + +namespace pp +{ + +void Token::reset() +{ + type = 0; + flags = 0; + location = SourceLocation(); + text.clear(); +} + +bool Token::equals(const Token& other) const +{ + return (type == other.type) && + (flags == other.flags) && + (location == other.location) && + (text == other.text); +} + +void Token::setAtStartOfLine(bool start) +{ + if (start) + flags |= AT_START_OF_LINE; + else + flags &= ~AT_START_OF_LINE; +} + +void Token::setHasLeadingSpace(bool space) +{ + if (space) + flags |= HAS_LEADING_SPACE; + else + flags &= ~HAS_LEADING_SPACE; +} + +void Token::setExpansionDisabled(bool disable) +{ + if (disable) + flags |= EXPANSION_DISABLED; + else + flags &= ~EXPANSION_DISABLED; +} + +bool Token::iValue(int* value) const +{ + assert(type == CONST_INT); + return numeric_lex_int(text, value); +} + +bool Token::uValue(unsigned int* value) const +{ + assert(type == CONST_INT); + return numeric_lex_int(text, value); +} + +bool Token::fValue(float* value) const +{ + assert(type == CONST_FLOAT); + return numeric_lex_float(text, value); +} + +std::ostream& operator<<(std::ostream& out, const Token& token) +{ + if (token.hasLeadingSpace()) + out << " "; + + out << token.text; + return out; +} + +} // namespace pp
diff --git a/src/GLES2/compiler/preprocessor/Token.h b/src/GLES2/compiler/preprocessor/Token.h new file mode 100644 index 0000000..45b1129 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/Token.h
@@ -0,0 +1,106 @@ +// +// Copyright (c) 2011 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. +// + +#ifndef COMPILER_PREPROCESSOR_TOKEN_H_ +#define COMPILER_PREPROCESSOR_TOKEN_H_ + +#include <ostream> +#include <string> + +#include "SourceLocation.h" + +namespace pp +{ + +struct Token +{ + enum Type + { + LAST = 0, // EOF. + + IDENTIFIER = 258, + + CONST_INT, + CONST_FLOAT, + + OP_INC, + OP_DEC, + OP_LEFT, + OP_RIGHT, + OP_LE, + OP_GE, + OP_EQ, + OP_NE, + OP_AND, + OP_XOR, + OP_OR, + OP_ADD_ASSIGN, + OP_SUB_ASSIGN, + OP_MUL_ASSIGN, + OP_DIV_ASSIGN, + OP_MOD_ASSIGN, + OP_LEFT_ASSIGN, + OP_RIGHT_ASSIGN, + OP_AND_ASSIGN, + OP_XOR_ASSIGN, + OP_OR_ASSIGN, + + // Preprocessing token types. + // These types are used by the preprocessor internally. + // Preprocessor clients must not depend or check for them. + PP_HASH, + PP_NUMBER, + PP_OTHER + }; + enum Flags + { + AT_START_OF_LINE = 1 << 0, + HAS_LEADING_SPACE = 1 << 1, + EXPANSION_DISABLED = 1 << 2 + }; + + Token() : type(0), flags(0) { } + + void reset(); + bool equals(const Token& other) const; + + // Returns true if this is the first token on line. + // It disregards any leading whitespace. + bool atStartOfLine() const { return (flags & AT_START_OF_LINE) != 0; } + void setAtStartOfLine(bool start); + + bool hasLeadingSpace() const { return (flags & HAS_LEADING_SPACE) != 0; } + void setHasLeadingSpace(bool space); + + bool expansionDisabled() const { return (flags & EXPANSION_DISABLED) != 0; } + void setExpansionDisabled(bool disable); + + // Converts text into numeric value for CONST_INT and CONST_FLOAT token. + // Returns false if the parsed value cannot fit into an int or float. + bool iValue(int* value) const; + bool uValue(unsigned int* value) const; + bool fValue(float* value) const; + + int type; + unsigned int flags; + SourceLocation location; + std::string text; +}; + +inline bool operator==(const Token& lhs, const Token& rhs) +{ + return lhs.equals(rhs); +} + +inline bool operator!=(const Token& lhs, const Token& rhs) +{ + return !lhs.equals(rhs); +} + +extern std::ostream& operator<<(std::ostream& out, const Token& token); + +} // namepsace pp +#endif // COMPILER_PREPROCESSOR_TOKEN_H_
diff --git a/src/GLES2/compiler/preprocessor/Tokenizer.cpp b/src/GLES2/compiler/preprocessor/Tokenizer.cpp new file mode 100644 index 0000000..aecc06c --- /dev/null +++ b/src/GLES2/compiler/preprocessor/Tokenizer.cpp
@@ -0,0 +1,2370 @@ +#line 16 "./Tokenizer.l" +// +// Copyright (c) 2011 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. +// + +// This file is auto-generated by generate_parser.sh. DO NOT EDIT! + + + +#line 13 "./Tokenizer.cpp" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE pprestart(yyin ,yyscanner ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via pprestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void pprestart (FILE *input_file ,yyscan_t yyscanner ); +void pp_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE pp_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void pp_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void pp_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void pppush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void pppop_buffer_state (yyscan_t yyscanner ); + +static void ppensure_buffer_stack (yyscan_t yyscanner ); +static void pp_load_buffer_state (yyscan_t yyscanner ); +static void pp_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); + +#define YY_FLUSH_BUFFER pp_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) + +YY_BUFFER_STATE pp_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE pp_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE pp_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); + +void *ppalloc (yy_size_t ,yyscan_t yyscanner ); +void *pprealloc (void *,yy_size_t ,yyscan_t yyscanner ); +void ppfree (void * ,yyscan_t yyscanner ); + +#define yy_new_buffer pp_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + ppensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + pp_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + ppensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + pp_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define ppwrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); +static int yy_get_next_buffer (yyscan_t yyscanner ); +static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 37 +#define YY_END_OF_BUFFER 38 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[84] = + { 0, + 0, 0, 0, 0, 38, 36, 34, 35, 35, 33, + 7, 33, 33, 33, 33, 33, 33, 33, 33, 9, + 9, 33, 33, 33, 8, 33, 33, 3, 5, 5, + 4, 34, 35, 19, 27, 20, 30, 25, 12, 23, + 13, 24, 10, 2, 1, 26, 10, 9, 11, 11, + 11, 11, 9, 14, 16, 18, 17, 15, 8, 31, + 21, 32, 22, 3, 5, 6, 11, 10, 11, 1, + 10, 11, 0, 10, 9, 28, 29, 0, 10, 10, + 10, 10, 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 2, 2, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 5, 1, 6, 1, 7, 8, 1, 9, + 9, 10, 11, 9, 12, 13, 14, 15, 16, 16, + 16, 16, 16, 16, 16, 17, 17, 9, 9, 18, + 19, 20, 9, 1, 21, 21, 21, 21, 22, 21, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 24, 23, 23, + 9, 1, 9, 25, 23, 1, 21, 21, 21, 21, + + 22, 21, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, + 23, 23, 9, 26, 9, 9, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[27] = + { 0, + 1, 1, 2, 2, 1, 1, 1, 1, 1, 3, + 1, 1, 4, 1, 5, 5, 5, 1, 1, 1, + 5, 5, 5, 5, 1, 1 + } ; + +static yyconst flex_int16_t yy_base[89] = + { 0, + 0, 0, 24, 26, 158, 159, 150, 159, 145, 128, + 159, 112, 23, 159, 111, 21, 25, 30, 29, 36, + 46, 36, 100, 45, 0, 16, 47, 0, 159, 84, + 65, 73, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 61, 159, 0, 159, 73, 32, 56, 83, + 95, 68, 0, 31, 159, 159, 159, 19, 0, 159, + 159, 159, 159, 0, 159, 159, 98, 0, 110, 0, + 0, 117, 52, 90, 80, 159, 159, 101, 97, 112, + 120, 123, 159, 140, 28, 145, 150, 152 + } ; + +static yyconst flex_int16_t yy_def[89] = + { 0, + 83, 1, 84, 84, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 20, 83, 83, 83, 85, 83, 83, 86, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 87, 83, 83, 20, 20, 47, + 50, 88, 21, 83, 83, 83, 83, 83, 85, 83, + 83, 83, 83, 86, 83, 83, 43, 43, 67, 87, + 47, 50, 83, 51, 88, 83, 83, 83, 69, 72, + 83, 83, 0, 83, 83, 83, 83, 83 + } ; + +static yyconst flex_int16_t yy_nxt[186] = + { 0, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 21, 22, 23, 24, + 25, 25, 25, 25, 26, 27, 29, 30, 29, 30, + 36, 39, 59, 31, 60, 31, 41, 77, 44, 40, + 61, 37, 45, 42, 43, 43, 43, 46, 47, 76, + 48, 48, 49, 54, 55, 50, 50, 51, 50, 52, + 53, 53, 53, 57, 58, 62, 81, 81, 81, 50, + 49, 49, 63, 67, 32, 68, 68, 68, 66, 50, + 50, 67, 69, 67, 67, 50, 65, 71, 71, 71, + 50, 50, 50, 50, 72, 50, 50, 50, 50, 50, + + 83, 83, 50, 50, 50, 73, 73, 83, 83, 74, + 74, 74, 67, 67, 67, 82, 82, 82, 56, 67, + 78, 78, 83, 83, 79, 79, 79, 78, 78, 38, + 35, 80, 80, 80, 81, 81, 81, 82, 82, 82, + 28, 28, 28, 28, 28, 64, 34, 33, 64, 64, + 70, 32, 70, 70, 70, 75, 75, 83, 5, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83 + } ; + +static yyconst flex_int16_t yy_chk[186] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 3, 4, 4, + 13, 16, 85, 3, 26, 4, 17, 58, 19, 16, + 26, 13, 19, 17, 18, 18, 18, 19, 20, 54, + 20, 20, 20, 22, 22, 48, 20, 20, 20, 20, + 21, 21, 21, 24, 24, 27, 73, 73, 73, 21, + 49, 49, 27, 43, 32, 43, 43, 43, 31, 49, + 52, 43, 43, 43, 43, 47, 30, 47, 47, 47, + 52, 52, 75, 47, 47, 47, 47, 50, 50, 50, + + 74, 74, 75, 75, 50, 51, 51, 79, 79, 51, + 51, 51, 67, 67, 67, 78, 78, 78, 23, 67, + 69, 69, 80, 80, 69, 69, 69, 72, 72, 15, + 12, 72, 72, 72, 81, 81, 81, 82, 82, 82, + 84, 84, 84, 84, 84, 86, 10, 9, 86, 86, + 87, 7, 87, 87, 87, 88, 88, 5, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83 + } ; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +/* +// +// Copyright (c) 2002-2011 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. +// + +This file contains the Lex specification for GLSL ES preprocessor. +Based on Microsoft Visual Studio 2010 Preprocessor Grammar: +http://msdn.microsoft.com/en-us/library/2scxys89.aspx + +IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh. +*/ + +#include "Tokenizer.h" + +#include "Diagnostics.h" +#include "Token.h" + +#if defined(__GNUC__) +// Triggered by the auto-generated yy_fatal_error function. +#pragma GCC diagnostic ignored "-Wmissing-noreturn" +#endif + +typedef std::string YYSTYPE; +typedef pp::SourceLocation YYLTYPE; + +// Use the unused yycolumn variable to track file (string) number. +#define yyfileno yycolumn + +#define YY_USER_INIT \ + do { \ + yyfileno = 0; \ + yylineno = 1; \ + yyextra->leadingSpace = false; \ + yyextra->lineStart = true; \ + } while(0); + +#define YY_USER_ACTION \ + do \ + { \ + pp::Input* input = &yyextra->input; \ + pp::Input::Location* scanLoc = &yyextra->scanLoc; \ + while ((scanLoc->sIndex < input->count()) && \ + (scanLoc->cIndex >= input->length(scanLoc->sIndex))) \ + { \ + scanLoc->cIndex -= input->length(scanLoc->sIndex++); \ + ++yyfileno; yylineno = 1; \ + } \ + yylloc->file = yyfileno; \ + yylloc->line = yylineno; \ + scanLoc->cIndex += yyleng; \ + } while(0); + +#define YY_INPUT(buf, result, maxSize) \ + result = yyextra->input.read(buf, maxSize); + +#define INITIAL 0 +#define COMMENT 1 + +#define YY_EXTRA_TYPE pp::Tokenizer::Context* + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + YYLTYPE * yylloc_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals (yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + + # define yylloc yyg->yylloc_r + +int pplex_init (yyscan_t* scanner); + +int pplex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int pplex_destroy (yyscan_t yyscanner ); + +int ppget_debug (yyscan_t yyscanner ); + +void ppset_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE ppget_extra (yyscan_t yyscanner ); + +void ppset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *ppget_in (yyscan_t yyscanner ); + +void ppset_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *ppget_out (yyscan_t yyscanner ); + +void ppset_out (FILE * out_str ,yyscan_t yyscanner ); + +int ppget_leng (yyscan_t yyscanner ); + +char *ppget_text (yyscan_t yyscanner ); + +int ppget_lineno (yyscan_t yyscanner ); + +void ppset_lineno (int line_number ,yyscan_t yyscanner ); + +YYSTYPE * ppget_lval (yyscan_t yyscanner ); + +void ppset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); + + YYLTYPE *ppget_lloc (yyscan_t yyscanner ); + + void ppset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int ppwrap (yyscan_t yyscanner ); +#else +extern int ppwrap (yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (yyscan_t yyscanner ); +#else +static int input (yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int pplex \ + (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner); + +#define YY_DECL int pplex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Line comment */ + + yylval = yylval_param; + + yylloc = yylloc_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + ppensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + pp_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + pp_load_buffer_state(yyscanner ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 84 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_current_state != 83 ); + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP + + YY_BREAK +/* Block comment */ +/* Line breaks are just counted - not returned. */ +/* The comment is replaced by a single space. */ +case 2: +YY_RULE_SETUP +{ BEGIN(COMMENT); } + YY_BREAK +case 3: +YY_RULE_SETUP + + YY_BREAK +case 4: +YY_RULE_SETUP + + YY_BREAK +case 5: +/* rule 5 can match eol */ +YY_RULE_SETUP +{ ++yylineno; } + YY_BREAK +case 6: +YY_RULE_SETUP +{ + yyextra->leadingSpace = true; + BEGIN(INITIAL); +} + YY_BREAK +case 7: +YY_RULE_SETUP +{ + // # is only valid at start of line for preprocessor directives. + yylval->assign(1, yytext[0]); + return yyextra->lineStart ? pp::Token::PP_HASH : pp::Token::PP_OTHER; +} + YY_BREAK +case 8: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::IDENTIFIER; +} + YY_BREAK +case 9: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::CONST_INT; +} + YY_BREAK +case 10: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::CONST_FLOAT; +} + YY_BREAK +/* Anything that starts with a {DIGIT} or .{DIGIT} must be a number. */ +/* Rule to catch all invalid integers and floats. */ +case 11: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::PP_NUMBER; +} + YY_BREAK +case 12: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_INC; +} + YY_BREAK +case 13: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_DEC; +} + YY_BREAK +case 14: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_LEFT; +} + YY_BREAK +case 15: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_RIGHT; +} + YY_BREAK +case 16: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_LE; +} + YY_BREAK +case 17: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_GE; +} + YY_BREAK +case 18: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_EQ; +} + YY_BREAK +case 19: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_NE; +} + YY_BREAK +case 20: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_AND; +} + YY_BREAK +case 21: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_XOR; +} + YY_BREAK +case 22: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_OR; +} + YY_BREAK +case 23: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_ADD_ASSIGN; +} + YY_BREAK +case 24: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_SUB_ASSIGN; +} + YY_BREAK +case 25: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_MUL_ASSIGN; +} + YY_BREAK +case 26: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_DIV_ASSIGN; +} + YY_BREAK +case 27: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_MOD_ASSIGN; +} + YY_BREAK +case 28: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_LEFT_ASSIGN; +} + YY_BREAK +case 29: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_RIGHT_ASSIGN; +} + YY_BREAK +case 30: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_AND_ASSIGN; +} + YY_BREAK +case 31: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_XOR_ASSIGN; +} + YY_BREAK +case 32: +YY_RULE_SETUP +{ + yylval->assign(yytext, yyleng); + return pp::Token::OP_OR_ASSIGN; +} + YY_BREAK +case 33: +YY_RULE_SETUP +{ + yylval->assign(1, yytext[0]); + return yytext[0]; +} + YY_BREAK +case 34: +YY_RULE_SETUP +{ yyextra->leadingSpace = true; } + YY_BREAK +case 35: +/* rule 35 can match eol */ +YY_RULE_SETUP +{ + ++yylineno; + yylval->assign(1, '\n'); + return '\n'; +} + YY_BREAK +case 36: +YY_RULE_SETUP +{ + yylval->assign(1, yytext[0]); + return pp::Token::PP_OTHER; +} + YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(COMMENT): +{ + // YY_USER_ACTION is not invoked for handling EOF. + // Set the location for EOF token manually. + pp::Input* input = &yyextra->input; + pp::Input::Location* scanLoc = &yyextra->scanLoc; + int sIndexMax = std::max(0, input->count() - 1); + if (scanLoc->sIndex != sIndexMax) + { + // We can only reach here if there are empty strings at the + // end of the input. + scanLoc->sIndex = sIndexMax; scanLoc->cIndex = 0; + yyfileno = sIndexMax; yylineno = 1; + } + yylloc->file = yyfileno; + yylloc->line = yylineno; + yylval->clear(); + + if (YY_START == COMMENT) + { + yyextra->diagnostics->report(pp::Diagnostics::EOF_IN_COMMENT, + pp::SourceLocation(yyfileno, yylineno), + ""); + } + yyterminate(); +} + YY_BREAK +case 37: +YY_RULE_SETUP +ECHO; + YY_BREAK + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * pplex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( ppwrap(yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of pplex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = yyg->yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + pprealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + pprestart(yyin ,yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) pprealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 84 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + register int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + register char *yy_cp = yyg->yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 84 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 83); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + pprestart(yyin ,yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( ppwrap(yyscanner ) ) + return EOF; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void pprestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + ppensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + pp_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + pp_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); + pp_load_buffer_state(yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void pp_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * pppop_buffer_state(); + * pppush_buffer_state(new_buffer); + */ + ppensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + pp_load_buffer_state(yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (ppwrap()) processing, but the only time this flag + * is looked at is after ppwrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void pp_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE pp_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) ppalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in pp_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) ppalloc(b->yy_buf_size + 2 ,yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in pp_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + pp_init_buffer(b,file ,yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with pp_create_buffer() + * @param yyscanner The scanner object. + */ + void pp_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + ppfree((void *) b->yy_ch_buf ,yyscanner ); + + ppfree((void *) b ,yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a pprestart() or at EOF. + */ + static void pp_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + pp_flush_buffer(b ,yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then pp_init_buffer was _probably_ + * called from pprestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void pp_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + pp_load_buffer_state(yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void pppush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + ppensure_buffer_stack(yyscanner); + + /* This block is copied from pp_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from pp_switch_to_buffer. */ + pp_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void pppop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + pp_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + pp_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void ppensure_buffer_stack (yyscan_t yyscanner) +{ + int num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + yyg->yy_buffer_stack = (struct yy_buffer_state**)ppalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in ppensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)pprealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in ppensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE pp_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) ppalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in pp_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + pp_switch_to_buffer(b ,yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to pplex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * pp_scan_bytes() instead. + */ +YY_BUFFER_STATE pp_scan_string (yyconst char * yystr , yyscan_t yyscanner) +{ + + return pp_scan_bytes(yystr,strlen(yystr) ,yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to pplex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE pp_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) ppalloc(n ,yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in pp_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = pp_scan_buffer(buf,n ,yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in pp_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE ppget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int ppget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int ppget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *ppget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *ppget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int ppget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *ppget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void ppset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param line_number + * @param yyscanner The scanner object. + */ +void ppset_lineno (int line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "ppset_lineno called with no buffer" , yyscanner); + + yylineno = line_number; +} + +/** Set the current column. + * @param line_number + * @param yyscanner The scanner object. + */ +void ppset_column (int column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "ppset_column called with no buffer" , yyscanner); + + yycolumn = column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * @param yyscanner The scanner object. + * @see pp_switch_to_buffer + */ +void ppset_in (FILE * in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = in_str ; +} + +void ppset_out (FILE * out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = out_str ; +} + +int ppget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void ppset_debug (int bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * ppget_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void ppset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +YYLTYPE *ppget_lloc (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylloc; +} + +void ppset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylloc = yylloc_param; +} + +/* User-visible API */ + +/* pplex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ + +int pplex_init(yyscan_t* ptr_yy_globals) + +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) ppalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* pplex_init_extra has the same functionality as pplex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to ppalloc in + * the yyextra field. + */ + +int pplex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) + +{ + struct yyguts_t dummy_yyguts; + + ppset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) ppalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + ppset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from pplex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = 0; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = (char *) 0; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * pplex_init() + */ + return 0; +} + +/* pplex_destroy is for both reentrant and non-reentrant scanners. */ +int pplex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + pp_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + pppop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + ppfree(yyg->yy_buffer_stack ,yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + ppfree(yyg->yy_start_stack ,yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * pplex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + ppfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *ppalloc (yy_size_t size , yyscan_t yyscanner) +{ + return (void *) malloc( size ); +} + +void *pprealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void ppfree (void * ptr , yyscan_t yyscanner) +{ + free( (char *) ptr ); /* see pprealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +namespace pp { + +// TODO(alokp): Maximum token length should ideally be specified by +// the preprocessor client, i.e., the compiler. +const size_t Tokenizer::kMaxTokenLength = 256; + +Tokenizer::Tokenizer(Diagnostics* diagnostics) : mHandle(0) +{ + mContext.diagnostics = diagnostics; +} + +Tokenizer::~Tokenizer() +{ + destroyScanner(); +} + +bool Tokenizer::init(int count, const char* const string[], const int length[]) +{ + if (count < 0) return false; + if ((count > 0) && (string == 0)) return false; + + mContext.input = Input(count, string, length); + return initScanner(); +} + +void Tokenizer::setFileNumber(int file) +{ + // We use column number as file number. + // See macro yyfileno. + ppset_column(file,mHandle); +} + +void Tokenizer::setLineNumber(int line) +{ + ppset_lineno(line,mHandle); +} + +void Tokenizer::lex(Token* token) +{ + token->type = pplex(&token->text,&token->location,mHandle); + if (token->text.size() > kMaxTokenLength) + { + mContext.diagnostics->report(Diagnostics::TOKEN_TOO_LONG, + token->location, token->text); + token->text.erase(kMaxTokenLength); + } + + token->flags = 0; + + token->setAtStartOfLine(mContext.lineStart); + mContext.lineStart = token->type == '\n'; + + token->setHasLeadingSpace(mContext.leadingSpace); + mContext.leadingSpace = false; +} + +bool Tokenizer::initScanner() +{ + if ((mHandle == NULL) && pplex_init_extra(&mContext,&mHandle)) + return false; + + pprestart(0,mHandle); + return true; +} + +void Tokenizer::destroyScanner() +{ + if (mHandle == NULL) + return; + + pplex_destroy(mHandle); + mHandle = NULL; +} + +} // namespace pp +
diff --git a/src/GLES2/compiler/preprocessor/Tokenizer.h b/src/GLES2/compiler/preprocessor/Tokenizer.h new file mode 100644 index 0000000..4dbfff2 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/Tokenizer.h
@@ -0,0 +1,58 @@ +// +// Copyright (c) 2012 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. +// + +#ifndef COMPILER_PREPROCESSOR_TOKENIZER_H_ +#define COMPILER_PREPROCESSOR_TOKENIZER_H_ + +#include "Input.h" +#include "Lexer.h" +#include "pp_utils.h" + +namespace pp +{ + +class Diagnostics; + +class Tokenizer : public Lexer +{ + public: + struct Context + { + Diagnostics* diagnostics; + + Input input; + // The location where yytext points to. Token location should track + // scanLoc instead of Input::mReadLoc because they may not be the same + // if text is buffered up in the scanner input buffer. + Input::Location scanLoc; + + bool leadingSpace; + bool lineStart; + }; + static const size_t kMaxTokenLength; + + Tokenizer(Diagnostics* diagnostics); + ~Tokenizer(); + + bool init(int count, const char* const string[], const int length[]); + + void setFileNumber(int file); + void setLineNumber(int line); + + virtual void lex(Token* token); + + private: + PP_DISALLOW_COPY_AND_ASSIGN(Tokenizer); + bool initScanner(); + void destroyScanner(); + + void* mHandle; // Scanner handle. + Context mContext; // Scanner extra. +}; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_TOKENIZER_H_ +
diff --git a/src/GLES2/compiler/preprocessor/Tokenizer.l b/src/GLES2/compiler/preprocessor/Tokenizer.l new file mode 100644 index 0000000..a641707 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/Tokenizer.l
@@ -0,0 +1,340 @@ +/* +// +// Copyright (c) 2002-2011 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. +// + +This file contains the Lex specification for GLSL ES preprocessor. +Based on Microsoft Visual Studio 2010 Preprocessor Grammar: +http://msdn.microsoft.com/en-us/library/2scxys89.aspx + +IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh. +*/ + +%top{ +// +// Copyright (c) 2011 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. +// + +// This file is auto-generated by generate_parser.sh. DO NOT EDIT! +} + +%{ +#include "Tokenizer.h" + +#include "Diagnostics.h" +#include "Token.h" + +#if defined(__GNUC__) +// Triggered by the auto-generated yy_fatal_error function. +#pragma GCC diagnostic ignored "-Wmissing-noreturn" +#endif + +typedef std::string YYSTYPE; +typedef pp::SourceLocation YYLTYPE; + +// Use the unused yycolumn variable to track file (string) number. +#define yyfileno yycolumn + +#define YY_USER_INIT \ + do { \ + yyfileno = 0; \ + yylineno = 1; \ + yyextra->leadingSpace = false; \ + yyextra->lineStart = true; \ + } while(0); + +#define YY_USER_ACTION \ + do \ + { \ + pp::Input* input = &yyextra->input; \ + pp::Input::Location* scanLoc = &yyextra->scanLoc; \ + while ((scanLoc->sIndex < input->count()) && \ + (scanLoc->cIndex >= input->length(scanLoc->sIndex))) \ + { \ + scanLoc->cIndex -= input->length(scanLoc->sIndex++); \ + ++yyfileno; yylineno = 1; \ + } \ + yylloc->file = yyfileno; \ + yylloc->line = yylineno; \ + scanLoc->cIndex += yyleng; \ + } while(0); + +#define YY_INPUT(buf, result, maxSize) \ + result = yyextra->input.read(buf, maxSize); + +%} + +%option noyywrap nounput never-interactive +%option reentrant bison-bridge bison-locations +%option prefix="pp" +%option extra-type="pp::Tokenizer::Context*" +%x COMMENT + +NEWLINE \n|\r|\r\n +IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]* +PUNCTUATOR [][<>(){}.+-/*%^|&~=!:;,?] + +DECIMAL_CONSTANT [1-9][0-9]* +OCTAL_CONSTANT 0[0-7]* +HEXADECIMAL_CONSTANT 0[xX][0-9a-fA-F]+ + +DIGIT [0-9] +EXPONENT_PART [eE][+-]?{DIGIT}+ +FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") + +%% + + /* Line comment */ +"//"[^\r\n]* + + /* Block comment */ + /* Line breaks are just counted - not returned. */ + /* The comment is replaced by a single space. */ +"/*" { BEGIN(COMMENT); } +<COMMENT>[^*\r\n]+ +<COMMENT>"*" +<COMMENT>{NEWLINE} { ++yylineno; } +<COMMENT>"*/" { + yyextra->leadingSpace = true; + BEGIN(INITIAL); +} + +# { + // # is only valid at start of line for preprocessor directives. + yylval->assign(1, yytext[0]); + return yyextra->lineStart ? pp::Token::PP_HASH : pp::Token::PP_OTHER; +} + +{IDENTIFIER} { + yylval->assign(yytext, yyleng); + return pp::Token::IDENTIFIER; +} + +{DECIMAL_CONSTANT}|{OCTAL_CONSTANT}|{HEXADECIMAL_CONSTANT} { + yylval->assign(yytext, yyleng); + return pp::Token::CONST_INT; +} + +({DIGIT}+{EXPONENT_PART})|({FRACTIONAL_CONSTANT}{EXPONENT_PART}?) { + yylval->assign(yytext, yyleng); + return pp::Token::CONST_FLOAT; +} + + /* Anything that starts with a {DIGIT} or .{DIGIT} must be a number. */ + /* Rule to catch all invalid integers and floats. */ +({DIGIT}+[_a-zA-Z0-9.]*)|("."{DIGIT}+[_a-zA-Z0-9.]*) { + yylval->assign(yytext, yyleng); + return pp::Token::PP_NUMBER; +} + +"++" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_INC; +} +"--" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_DEC; +} +"<<" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_LEFT; +} +">>" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_RIGHT; +} +"<=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_LE; +} +">=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_GE; +} +"==" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_EQ; +} +"!=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_NE; +} +"&&" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_AND; +} +"^^" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_XOR; +} +"||" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_OR; +} +"+=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_ADD_ASSIGN; +} +"-=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_SUB_ASSIGN; +} +"*=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_MUL_ASSIGN; +} +"/=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_DIV_ASSIGN; +} +"%=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_MOD_ASSIGN; +} +"<<=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_LEFT_ASSIGN; +} +">>=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_RIGHT_ASSIGN; +} +"&=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_AND_ASSIGN; +} +"^=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_XOR_ASSIGN; +} +"|=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_OR_ASSIGN; +} + +{PUNCTUATOR} { + yylval->assign(1, yytext[0]); + return yytext[0]; +} + +[ \t\v\f]+ { yyextra->leadingSpace = true; } + +{NEWLINE} { + ++yylineno; + yylval->assign(1, '\n'); + return '\n'; +} + +. { + yylval->assign(1, yytext[0]); + return pp::Token::PP_OTHER; +} + +<*><<EOF>> { + // YY_USER_ACTION is not invoked for handling EOF. + // Set the location for EOF token manually. + pp::Input* input = &yyextra->input; + pp::Input::Location* scanLoc = &yyextra->scanLoc; + int sIndexMax = std::max(0, input->count() - 1); + if (scanLoc->sIndex != sIndexMax) + { + // We can only reach here if there are empty strings at the + // end of the input. + scanLoc->sIndex = sIndexMax; scanLoc->cIndex = 0; + yyfileno = sIndexMax; yylineno = 1; + } + yylloc->file = yyfileno; + yylloc->line = yylineno; + yylval->clear(); + + if (YY_START == COMMENT) + { + yyextra->diagnostics->report(pp::Diagnostics::EOF_IN_COMMENT, + pp::SourceLocation(yyfileno, yylineno), + ""); + } + yyterminate(); +} + +%% + +namespace pp { + +// TODO(alokp): Maximum token length should ideally be specified by +// the preprocessor client, i.e., the compiler. +const size_t Tokenizer::kMaxTokenLength = 256; + +Tokenizer::Tokenizer(Diagnostics* diagnostics) : mHandle(0) +{ + mContext.diagnostics = diagnostics; +} + +Tokenizer::~Tokenizer() +{ + destroyScanner(); +} + +bool Tokenizer::init(int count, const char* const string[], const int length[]) +{ + if (count < 0) return false; + if ((count > 0) && (string == 0)) return false; + + mContext.input = Input(count, string, length); + return initScanner(); +} + +void Tokenizer::setFileNumber(int file) +{ + // We use column number as file number. + // See macro yyfileno. + yyset_column(file, mHandle); +} + +void Tokenizer::setLineNumber(int line) +{ + yyset_lineno(line, mHandle); +} + +void Tokenizer::lex(Token* token) +{ + token->type = yylex(&token->text, &token->location, mHandle); + if (token->text.size() > kMaxTokenLength) + { + mContext.diagnostics->report(Diagnostics::TOKEN_TOO_LONG, + token->location, token->text); + token->text.erase(kMaxTokenLength); + } + + token->flags = 0; + + token->setAtStartOfLine(mContext.lineStart); + mContext.lineStart = token->type == '\n'; + + token->setHasLeadingSpace(mContext.leadingSpace); + mContext.leadingSpace = false; +} + +bool Tokenizer::initScanner() +{ + if ((mHandle == NULL) && yylex_init_extra(&mContext, &mHandle)) + return false; + + yyrestart(0, mHandle); + return true; +} + +void Tokenizer::destroyScanner() +{ + if (mHandle == NULL) + return; + + yylex_destroy(mHandle); + mHandle = NULL; +} + +} // namespace pp +
diff --git a/src/GLES2/compiler/preprocessor/generate_parser.sh b/src/GLES2/compiler/preprocessor/generate_parser.sh new file mode 100644 index 0000000..8ffe0e5 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/generate_parser.sh
@@ -0,0 +1,26 @@ +#!/bin/bash +# Copyright (c) 2012 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. + +# Generates various components of GLSL ES preprocessor. + +run_flex() +{ +input_file=$script_dir/$1 +output_source=$script_dir/$2 +flex --noline --nounistd --outfile=$output_source $input_file +} + +run_bison() +{ +input_file=$script_dir/$1 +output_source=$script_dir/$2 +bison --no-lines --skeleton=yacc.c --output=$output_source $input_file +} + +script_dir=$(dirname $0) + +# Generate preprocessor +run_flex Tokenizer.l Tokenizer.cpp +run_bison ExpressionParser.y ExpressionParser.cpp
diff --git a/src/GLES2/compiler/preprocessor/length_limits.h b/src/GLES2/compiler/preprocessor/length_limits.h new file mode 100644 index 0000000..889d468 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/length_limits.h
@@ -0,0 +1,21 @@ +// +// Copyright (c) 2011 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. +// + +// +// length_limits.h +// + +#if !defined(__LENGTH_LIMITS_H) +#define __LENGTH_LIMITS_H 1 + +// These constants are factored out from the rest of the headers to +// make it easier to reference them from the compiler sources. + +// These lengths do not include the NULL terminator. +#define MAX_SYMBOL_NAME_LEN 256 +#define MAX_STRING_LEN 511 + +#endif // !(defined(__LENGTH_LIMITS_H)
diff --git a/src/GLES2/compiler/preprocessor/numeric_lex.h b/src/GLES2/compiler/preprocessor/numeric_lex.h new file mode 100644 index 0000000..3cdf71f --- /dev/null +++ b/src/GLES2/compiler/preprocessor/numeric_lex.h
@@ -0,0 +1,61 @@ +// +// Copyright (c) 2012 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. +// + +// numeric_lex.h: Functions to extract numeric values from string. + +#ifndef COMPILER_PREPROCESSOR_NUMERIC_LEX_H_ +#define COMPILER_PREPROCESSOR_NUMERIC_LEX_H_ + +#include <sstream> + +namespace pp { + +inline std::ios::fmtflags numeric_base_int(const std::string& str) +{ + if ((str.size() >= 2) && + (str[0] == '0') && + (str[1] == 'x' || str[1] == 'X')) + { + return std::ios::hex; + } + else if ((str.size() >= 1) && (str[0] == '0')) + { + return std::ios::oct; + } + return std::ios::dec; +} + +// The following functions parse the given string to extract a numerical +// value of the given type. These functions assume that the string is +// of the correct form. They can only fail if the parsed value is too big, +// in which case false is returned. + +template<typename IntType> +bool numeric_lex_int(const std::string& str, IntType* value) +{ + std::istringstream stream(str); + // This should not be necessary, but MSVS has a buggy implementation. + // It returns incorrect results if the base is not specified. + stream.setf(numeric_base_int(str), std::ios::basefield); + + stream >> (*value); + return !stream.fail(); +} + +template<typename FloatType> +bool numeric_lex_float(const std::string& str, FloatType* value) +{ + std::istringstream stream(str); + // Force "C" locale so that decimal character is always '.', and + // not dependent on the current locale. + stream.imbue(std::locale::classic()); + + stream >> (*value); + return !stream.fail(); +} + +} // namespace pp. +#endif // COMPILER_PREPROCESSOR_NUMERIC_LEX_H_
diff --git a/src/GLES2/compiler/preprocessor/pp_utils.h b/src/GLES2/compiler/preprocessor/pp_utils.h new file mode 100644 index 0000000..9fed659 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/pp_utils.h
@@ -0,0 +1,18 @@ +// +// Copyright (c) 2012 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. +// + +// pp_utils.h: Common preprocessor utilities + +#ifndef COMPILER_PREPROCESSOR_PPUTILS_H_ +#define COMPILER_PREPROCESSOR_PPUTILS_H_ + +// A macro to disallow the copy constructor and operator= functions +// This must be used in the private: declarations for a class. +#define PP_DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +#endif // COMPILER_PREPROCESSOR_PPUTILS_H_
diff --git a/src/GLES2/compiler/preprocessor/preprocessor.vcxproj b/src/GLES2/compiler/preprocessor/preprocessor.vcxproj new file mode 100644 index 0000000..2afb4fe --- /dev/null +++ b/src/GLES2/compiler/preprocessor/preprocessor.vcxproj
@@ -0,0 +1,101 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{92940255-AB4B-42FB-A2C4-0FAB19C3C48A}</ProjectGuid> + <RootNamespace>preprocessor</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <CharacterSet>NotSet</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>NotSet</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup /> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <Link> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClInclude Include="Diagnostics.h" /> + <ClInclude Include="DirectiveHandler.h" /> + <ClInclude Include="DirectiveParser.h" /> + <ClInclude Include="ExpressionParser.h" /> + <ClInclude Include="Input.h" /> + <ClInclude Include="length_limits.h" /> + <ClInclude Include="Lexer.h" /> + <ClInclude Include="Macro.h" /> + <ClInclude Include="MacroExpander.h" /> + <ClInclude Include="numeric_lex.h" /> + <ClInclude Include="pp_utils.h" /> + <ClInclude Include="Preprocessor.h" /> + <ClInclude Include="SourceLocation.h" /> + <ClInclude Include="Token.h" /> + <ClInclude Include="Tokenizer.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="Diagnostics.cpp" /> + <ClCompile Include="DirectiveHandler.cpp" /> + <ClCompile Include="DirectiveParser.cpp" /> + <ClCompile Include="ExpressionParser.cpp" /> + <ClCompile Include="Input.cpp" /> + <ClCompile Include="Lexer.cpp" /> + <ClCompile Include="Macro.cpp" /> + <ClCompile Include="MacroExpander.cpp" /> + <ClCompile Include="Preprocessor.cpp" /> + <ClCompile Include="Token.cpp" /> + <ClCompile Include="Tokenizer.cpp" /> + </ItemGroup> + <ItemGroup> + <None Include="ExpressionParser.y" /> + <None Include="Tokenizer.l" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
diff --git a/src/GLES2/compiler/preprocessor/preprocessor.vcxproj.filters b/src/GLES2/compiler/preprocessor/preprocessor.vcxproj.filters new file mode 100644 index 0000000..d68cbe2 --- /dev/null +++ b/src/GLES2/compiler/preprocessor/preprocessor.vcxproj.filters
@@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="Diagnostics.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="DirectiveHandler.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="DirectiveParser.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="ExpressionParser.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Input.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="length_limits.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Lexer.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Macro.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="MacroExpander.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="numeric_lex.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="pp_utils.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Preprocessor.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="SourceLocation.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Token.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Tokenizer.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="Diagnostics.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="DirectiveHandler.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="DirectiveParser.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ExpressionParser.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Input.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Lexer.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Macro.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="MacroExpander.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Preprocessor.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Token.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Tokenizer.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <None Include="Tokenizer.l" /> + <None Include="ExpressionParser.y" /> + </ItemGroup> +</Project>
diff --git a/src/GLES2/compiler/util.cpp b/src/GLES2/compiler/util.cpp new file mode 100644 index 0000000..b46e4d0 --- /dev/null +++ b/src/GLES2/compiler/util.cpp
@@ -0,0 +1,33 @@ +// +// Copyright (c) 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 <math.h> +#include <stdlib.h> + +#include "util.h" + +#ifdef _MSC_VER + #include <locale.h> +#else + #include <sstream> +#endif + +double atof_dot(const char *str) +{ +#ifdef _MSC_VER + _locale_t l = _create_locale(LC_NUMERIC, "C"); + double result = _atof_l(str, l); + _free_locale(l); + return result; +#else + double result; + std::istringstream s(str); + std::locale l("C"); + s.imbue(l); + s >> result; + return result; +#endif +}
diff --git a/src/GLES2/compiler/util.h b/src/GLES2/compiler/util.h new file mode 100644 index 0000000..35288b7 --- /dev/null +++ b/src/GLES2/compiler/util.h
@@ -0,0 +1,21 @@ +// +// 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. +// + +#ifndef COMPILER_UTIL_H +#define COMPILER_UTIL_H + +#ifdef __cplusplus +extern "C" { +#endif + +// atof_dot is like atof but forcing C locale, i.e. forcing '.' as decimal point. +double atof_dot(const char *str); + +#ifdef __cplusplus +} // end extern "C" +#endif + +#endif // COMPILER_UTIL_H