From a0af473a8bedbff4df6152bc6732ed6548a96150 Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Wed, 12 Dec 2012 21:15:54 +0000 Subject: [PATCH] Create a base GLSL front-end from the 3Dlabs glslang front-end from 20-Sep-2005. git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@19944 e7fa87d3-cd2b-0410-9028-fcbf551c1848 --- BuildLinux.sh | 13 + OGLCompilersDLL/InitializeDll.cpp | 149 ++ OGLCompilersDLL/InitializeDll.h | 47 + OGLCompilersDLL/Makefile | 53 + README.txt | 337 +++ StandAlone.sln | 28 + StandAlone.vcproj | 145 ++ StandAlone/Makefile | 40 + StandAlone/StandAlone.cpp | 366 +++ StandAlone/sample.frag | 40 + StandAlone/sample.frag.out | 15 + StandAlone/sample.vert | 42 + StandAlone/sample.vert.out | 20 + glslang.vcproj | 436 ++++ glslang/GenericCodeGen/CodeGen.cpp | 75 + glslang/GenericCodeGen/Link.cpp | 91 + glslang/GenericCodeGen/Makefile | 34 + glslang/Include/BaseTypes.h | 137 + glslang/Include/Common.h | 192 ++ glslang/Include/ConstantUnion.h | 315 +++ glslang/Include/InfoSink.h | 137 + glslang/Include/InitializeGlobals.h | 43 + glslang/Include/InitializeParseContext.h | 45 + glslang/Include/PoolAlloc.h | 349 +++ glslang/Include/ResourceLimits.h | 52 + glslang/Include/ShHandle.h | 169 ++ glslang/Include/Types.h | 322 +++ glslang/Include/intermediate.h | 522 ++++ glslang/MachineIndependent/InfoSink.cpp | 107 + glslang/MachineIndependent/Initialize.cpp | 962 +++++++ glslang/MachineIndependent/Initialize.h | 63 + glslang/MachineIndependent/IntermTraverse.cpp | 243 ++ glslang/MachineIndependent/Intermediate.cpp | 1514 +++++++++++ glslang/MachineIndependent/MMap.h | 84 + glslang/MachineIndependent/Makefile | 161 ++ glslang/MachineIndependent/ParseHelper.cpp | 1494 +++++++++++ glslang/MachineIndependent/ParseHelper.h | 150 ++ glslang/MachineIndependent/PoolAlloc.cpp | 342 +++ glslang/MachineIndependent/QualifierAlive.cpp | 91 + glslang/MachineIndependent/QualifierAlive.h | 35 + glslang/MachineIndependent/RemoveTree.cpp | 98 + glslang/MachineIndependent/RemoveTree.h | 35 + glslang/MachineIndependent/ShaderLang.cpp | 586 +++++ glslang/MachineIndependent/SymbolTable.cpp | 245 ++ glslang/MachineIndependent/SymbolTable.h | 318 +++ glslang/MachineIndependent/glslang.l | 637 +++++ glslang/MachineIndependent/glslang.y | 2317 +++++++++++++++++ glslang/MachineIndependent/intermOut.cpp | 491 ++++ .../MachineIndependent/localintermediate.h | 86 + glslang/MachineIndependent/parseConst.cpp | 266 ++ .../MachineIndependent/preprocessor/Makefile | 38 + .../MachineIndependent/preprocessor/atom.c | 768 ++++++ .../MachineIndependent/preprocessor/atom.h | 96 + .../MachineIndependent/preprocessor/compile.h | 132 + glslang/MachineIndependent/preprocessor/cpp.c | 1037 ++++++++ glslang/MachineIndependent/preprocessor/cpp.h | 119 + .../preprocessor/cppstruct.c | 185 ++ .../MachineIndependent/preprocessor/memory.c | 191 ++ .../MachineIndependent/preprocessor/memory.h | 89 + .../MachineIndependent/preprocessor/parser.h | 126 + .../preprocessor/preprocess.h | 84 + .../MachineIndependent/preprocessor/scanner.c | 794 ++++++ .../MachineIndependent/preprocessor/scanner.h | 118 + .../preprocessor/slglobals.h | 115 + .../MachineIndependent/preprocessor/symbols.c | 318 +++ .../MachineIndependent/preprocessor/symbols.h | 145 ++ .../MachineIndependent/preprocessor/tokens.c | 472 ++++ .../MachineIndependent/preprocessor/tokens.h | 122 + glslang/MachineIndependent/unistd.h | 1 + glslang/OSDependent/Linux/Makefile | 62 + glslang/OSDependent/Linux/osinclude.h | 78 + glslang/OSDependent/Linux/ossource.cpp | 141 + glslang/OSDependent/Windows/main.cpp | 69 + glslang/OSDependent/Windows/osinclude.h | 69 + glslang/OSDependent/Windows/ossource.cpp | 85 + glslang/Public/ShaderLang.h | 212 ++ tools/bison.exe | Bin 0 -> 196096 bytes tools/bison.hairy | 334 +++ tools/bison.simple | 699 +++++ tools/flex.exe | Bin 0 -> 181248 bytes 80 files changed, 21238 insertions(+) create mode 100755 BuildLinux.sh create mode 100644 OGLCompilersDLL/InitializeDll.cpp create mode 100644 OGLCompilersDLL/InitializeDll.h create mode 100644 OGLCompilersDLL/Makefile create mode 100644 README.txt create mode 100644 StandAlone.sln create mode 100644 StandAlone.vcproj create mode 100644 StandAlone/Makefile create mode 100644 StandAlone/StandAlone.cpp create mode 100644 StandAlone/sample.frag create mode 100644 StandAlone/sample.frag.out create mode 100644 StandAlone/sample.vert create mode 100644 StandAlone/sample.vert.out create mode 100644 glslang.vcproj create mode 100644 glslang/GenericCodeGen/CodeGen.cpp create mode 100644 glslang/GenericCodeGen/Link.cpp create mode 100644 glslang/GenericCodeGen/Makefile create mode 100644 glslang/Include/BaseTypes.h create mode 100644 glslang/Include/Common.h create mode 100644 glslang/Include/ConstantUnion.h create mode 100644 glslang/Include/InfoSink.h create mode 100644 glslang/Include/InitializeGlobals.h create mode 100644 glslang/Include/InitializeParseContext.h create mode 100644 glslang/Include/PoolAlloc.h create mode 100644 glslang/Include/ResourceLimits.h create mode 100644 glslang/Include/ShHandle.h create mode 100644 glslang/Include/Types.h create mode 100644 glslang/Include/intermediate.h create mode 100644 glslang/MachineIndependent/InfoSink.cpp create mode 100644 glslang/MachineIndependent/Initialize.cpp create mode 100644 glslang/MachineIndependent/Initialize.h create mode 100644 glslang/MachineIndependent/IntermTraverse.cpp create mode 100644 glslang/MachineIndependent/Intermediate.cpp create mode 100644 glslang/MachineIndependent/MMap.h create mode 100644 glslang/MachineIndependent/Makefile create mode 100644 glslang/MachineIndependent/ParseHelper.cpp create mode 100644 glslang/MachineIndependent/ParseHelper.h create mode 100644 glslang/MachineIndependent/PoolAlloc.cpp create mode 100644 glslang/MachineIndependent/QualifierAlive.cpp create mode 100644 glslang/MachineIndependent/QualifierAlive.h create mode 100644 glslang/MachineIndependent/RemoveTree.cpp create mode 100644 glslang/MachineIndependent/RemoveTree.h create mode 100644 glslang/MachineIndependent/ShaderLang.cpp create mode 100644 glslang/MachineIndependent/SymbolTable.cpp create mode 100644 glslang/MachineIndependent/SymbolTable.h create mode 100644 glslang/MachineIndependent/glslang.l create mode 100644 glslang/MachineIndependent/glslang.y create mode 100644 glslang/MachineIndependent/intermOut.cpp create mode 100644 glslang/MachineIndependent/localintermediate.h create mode 100644 glslang/MachineIndependent/parseConst.cpp create mode 100644 glslang/MachineIndependent/preprocessor/Makefile create mode 100644 glslang/MachineIndependent/preprocessor/atom.c create mode 100644 glslang/MachineIndependent/preprocessor/atom.h create mode 100644 glslang/MachineIndependent/preprocessor/compile.h create mode 100644 glslang/MachineIndependent/preprocessor/cpp.c create mode 100644 glslang/MachineIndependent/preprocessor/cpp.h create mode 100644 glslang/MachineIndependent/preprocessor/cppstruct.c create mode 100644 glslang/MachineIndependent/preprocessor/memory.c create mode 100644 glslang/MachineIndependent/preprocessor/memory.h create mode 100644 glslang/MachineIndependent/preprocessor/parser.h create mode 100644 glslang/MachineIndependent/preprocessor/preprocess.h create mode 100644 glslang/MachineIndependent/preprocessor/scanner.c create mode 100644 glslang/MachineIndependent/preprocessor/scanner.h create mode 100644 glslang/MachineIndependent/preprocessor/slglobals.h create mode 100644 glslang/MachineIndependent/preprocessor/symbols.c create mode 100644 glslang/MachineIndependent/preprocessor/symbols.h create mode 100644 glslang/MachineIndependent/preprocessor/tokens.c create mode 100644 glslang/MachineIndependent/preprocessor/tokens.h create mode 100644 glslang/MachineIndependent/unistd.h create mode 100644 glslang/OSDependent/Linux/Makefile create mode 100644 glslang/OSDependent/Linux/osinclude.h create mode 100644 glslang/OSDependent/Linux/ossource.cpp create mode 100644 glslang/OSDependent/Windows/main.cpp create mode 100644 glslang/OSDependent/Windows/osinclude.h create mode 100644 glslang/OSDependent/Windows/ossource.cpp create mode 100644 glslang/Public/ShaderLang.h create mode 100644 tools/bison.exe create mode 100644 tools/bison.hairy create mode 100644 tools/bison.simple create mode 100644 tools/flex.exe diff --git a/BuildLinux.sh b/BuildLinux.sh new file mode 100755 index 00000000..1abd9c5c --- /dev/null +++ b/BuildLinux.sh @@ -0,0 +1,13 @@ +#! /bin/bash + +# build the StandAlone app and all it's dependencies +make -C StandAlone + +# so we can find the shared library +LD_LIBRARY_PATH=`pwd`/glslang/MachineIndependent/lib:${LD_LIBRARY_PATH} +export LD_LIBRARY_PATH + +# run using test data +cd StandAlone +./StandAlone -i sample.vert sample.frag + diff --git a/OGLCompilersDLL/InitializeDll.cpp b/OGLCompilersDLL/InitializeDll.cpp new file mode 100644 index 00000000..8804ae85 --- /dev/null +++ b/OGLCompilersDLL/InitializeDll.cpp @@ -0,0 +1,149 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#define SH_EXPORTING + +#include "InitializeDll.h" +#include "Include/InitializeGlobals.h" +#include "Include/InitializeParseContext.h" + +#include "Public/ShaderLang.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; + } + + InitThread(); + return true; +} + + +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; + } + + FreeGlobalPools(); + + if (!FreeParseContext()) + success = false; + } + + return success; +} + +bool DetachProcess() +{ + bool success = true; + + if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) + return true; + + ShFinalize(); + + success = DetachThread(); + + FreePoolIndex(); + + if (!FreeParseContextIndex()) + success = false; + + OS_FreeTLSIndex(ThreadInitializeIndex); + ThreadInitializeIndex = OS_INVALID_TLS_INDEX; + + return success; +} diff --git a/OGLCompilersDLL/InitializeDll.h b/OGLCompilersDLL/InitializeDll.h new file mode 100644 index 00000000..f1ea567f --- /dev/null +++ b/OGLCompilersDLL/InitializeDll.h @@ -0,0 +1,47 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +#ifndef __INITIALIZEDLL_H +#define __INITIALIZEDLL_H + + +#include "osinclude.h" + + +bool InitProcess(); +bool InitThread(); +bool DetachThread(); +bool DetachProcess(); + +#endif // __INITIALIZEDLL_H + diff --git a/OGLCompilersDLL/Makefile b/OGLCompilersDLL/Makefile new file mode 100644 index 00000000..f45495bd --- /dev/null +++ b/OGLCompilersDLL/Makefile @@ -0,0 +1,53 @@ +INCLUDE = -I. -I../glslang -I../glslang/Include -I../glslang/OSDependent/Linux -I../glslang/MachineIndependent +WARNINGS = -Wall -Wwrite-strings -Wpointer-arith -Wcast-align -Wstrict-prototypes \ + -Wnested-externs +DEFINE = -Dlinux -D__i386__ + +CPP = g++ +CPPOPTIONS = -O3 -Wno-deprecated -D_ALT_NS=1 +CPPOPTIONS = -g -Wno-deprecated -D_ALT_NS=1 +CPPFLAGS = $(CPPOPTIONS) $(DEFINE) $(INCLUDE) + +# +# Linking related +# +AR = ar +STATIC_OPTION = rcs + +# +# Misc +# +export PERL = perl +export RM = rm -f +export MV = mv -f +export DEPEND = g++ -M + +# +# Object file variables are defined here. +# +OSSRCS = InitializeDll.cpp +OSOBJS = InitializeDll.o + +LIBNAME = libInitializeDll.a + +all : $(LIBNAME) + +$(LIBNAME) : $(OSOBJS) + $(AR) $(STATIC_OPTION) $(LIBNAME) $(OSOBJS) + +%.o : %.cpp + $(CPP) $(CPPFLAGS) -c $< + +# +# Dependency +# +depend : $(OSSRCS) + $(DEPEND) $(CPPFLAGS) $(OSSRCS) > depend +include depend + +# +# Cleanup +# +.PHONY : clean +clean : + $(RM) *.o *.a diff --git a/README.txt b/README.txt new file mode 100644 index 00000000..b7ab72f9 --- /dev/null +++ b/README.txt @@ -0,0 +1,337 @@ +OpenGL Shading Language source readme for Window and Linux + +Version: Sept 20, 2005 + + +Source Copyright +---------------- + + +Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + Neither the name of 3Dlabs Inc. Ltd. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +Changes since June 2005 Release +------------------------------- +- Some infrastructure is simplified, improved, and cleaned up. Details follow. + +- TPublicType is easier to setup and extend. + +- Constant values know their own types. Methods are added to set the +constant values as the data members are now protected instead of public. +Lots of code was cleaned up because of that. + +- Added support for an array object extension. Array constructors are +allowed. Constant arrays can be declared and parse time constant folding +and propagation is done through array objects. Extension GL_3DL_array_objects +must be enabled to use the array objects. + +- Arrays and structures are handled more uniformly. Sizing is simplified and improved. + +- Changed the implementation of the way constants values were stored in +the parse tree. Constants are now always flattened out. Constructors with +constant values are represented with constant values directly. Example mat2(1) +is stored as a constant node with values 1.0, 0.0, 0.0, 1.0. Earlier this +was stored as an aggregate node with correct operator and a single constant +value 1.0. This change caused a lot of code to be cleaned up and simplified. + +- Renamed ARB texture rectangle functions to match the final version of the specification. + + +Changes since Feb 2005 Release +------------------------------ +- Source now compiles on gcc 3.4.4. +- Fixed constant folding for ternary operator. +- Non-dereferenced arrays not allowed in constructors. Other semantic +error checking on arrays such as ++array, array1 = array2. +- Max allowed index for gl_TexCoord is gl_MaxTextureCoords - 1. +- Raise an error when one of the string passed to the parser is a NULL +pointer. +- Parser code tested to be portable on STLport stl. +- Detect error when preprocessor directives does not begin at the start +of the line. + +Please feel free to submit any fixes to the parser code. + + +Changes since Jan 2005 Release +------------------------------ +- Relaxed grammar rules for ?: (ternary operator) to allow assignment +expressions after the ':'. +- Fixed the correct parsing of empty shader source string. +- No longer raise an error when gl_Position is not written in a vertex +shader. This is link time functionality. +- Added some basic support for MSVC++6.0 to the extent that C++ standards +are not violated. + + +Changes since Sept 2004 Release +------------------------------- +- Memory usage by builtIn symbol table level is reduced to 1/4th of what +was used earlier. +- Built In symbol table level is split into two, the first level contains +symbols that do not change and the second level is constructed per compile, +based on the resource values specified by the driver. This required ShCompile +method to take in a pointer to the resource values. +- Correct handling of pragmas. +- Fixed defects such as comma operator folding, swizzling allowed only with +offsets from same set, texture look up functions appropriately split between +vertex and fragment shaders, ternary operator type checking, preprocessor +directives etc. +- Linux build now use flex version 2.5.4 that comes with Redhat 9.0 + + +Changes since July 2004 Release +------------------------------- +- Structures when initialized both as a constant and a non constant were broken. + + +Changes Since Apr 2004 Release +------------------------------- +- Added support for #extension and #version preprocessor directives. +- Removed printf statements and instead dump messages on InfoSink. +- Most of the source code is now thread safe except for some of the +preprocessor code. Also For Linux, the per thread data clean up is yet to be +implemented as it is not exactly known when the thread exits. +- Fixed comma operator when used with constant initializer. +- Added folding when constructors are called with constant values. +- Correctly updated builtIn names for texture functions from +texture{1|2}DShadow[Proj][Lod] to shadow{1|2}D[Proj][Lod]. +- Updated the built-in constant names as per latest GL2 specs. +- Portable across more platforms. + + +Changes Since Oct 2003 Release +------------------------------- +- Added new reserved keywords. Also reserved %=. +- Fixed some bugs and memory leaks in the preprocessor. +- Fixed name mangling for function names. Names also now include array sizes. +- Fixed implementation of unsized arrays. +- Constructors: Disallow matrices constructed from matrices, and unused +arguments. + Also fixed some cases like float(vec2) that were not working right. +- TILDA -> TILDE. +- Fixed structure qualifier semantics: they apply to variables declared, +not the structure definition. + + +Changes since May 2003 Release +------------------------------- + +- Corrected some bugs in preprocessor. +- Keeping track of maximum size of the array used in the source code. +- Parameter passing during function call and keeping track of inout and out +parameters. +- Added some more built in functions. +- Portability to Linux + + +Changes Since April 2002 Release +-------------------------------- + +* Semantic changes to bring the implementation and spec closer together, + and support issue resolution. + +* Some minor functionality completeness. + + - User function calls are more complete, + - added the ^^ operator (logical exclusive or) + - fixed variable scoping in if-else + - no declarations in if-conditions + - improved typing of field selectors + - removed suffixes from literal constants + - many smaller semantic changes to be in line with the current spec + - added preprocessor + - added non-scalar constants + - added structures + + +Changes since July 2002 Release +------------------------------- + +Brought up to date with version 1.051 of the OpenGL Shading Language +Specification. It is now almost complete. The list of detailed +changes would be long, as the specification has changed extensively, +and all missing functionality has been added. + + +Procedure to Build on Windows +----------------------------- + +Put this project in a path name without spaces. + +procedure To build using MS visual studio .Net. + +It has two projects. +The glslang project must be compiled first, followed by the +StandAlone project. + +1. The solution is StandAlone.sln. The two necessary +projects are glslang.vcproj and StandAlone.vcproj, +which devstudio will automatically open. + +2. You may have a missing header file, unistd.h. Create an empty one in +some standard devstudio or SDK system include directory. (Bison/flex +generate a #include , this makes them happy.) + +3. Build the glslang project (in devstudio, right click the glslang project +and build). This creates the glslang.dll and glslang.lib files needed to +make the StandAlone compiler run. It leaves them in the StandAlone +directory. + +4. Build the StandAlone project if you want to run the tests or run the +compiler stand-alone. + + +Running Stand Alone on Windows +------------------------------ + +The build process should create glslang.dll and StandAlone.exe. glslang.dll +has an interface suitable for integration with an ICD. StandAlone.exe uses +this interface to create a version of the compiler that can run outside +the ICD environment. + +The stand-alone compiler is a Win32 console application, best executed +from a command prompt. + +“cd” into the StandAlone directory, or a directory you've installed +StandAlone.exe, the OglBuiltIns subdirectory, and glslang.dll into. + +The normal case will be to compile and link a pair of shaders like this: + + StandAlone -i .vert .frag + + where the following command line options are possible for StandAlone: + i - dump parse tree + m - dump linker output (nothing dumped in the source code provided) + a - dump assembly code (nothing dumped in the source code provided) + +The applied compilation-language is based on the file extension. +Give the full name of the files containing the shader source code. +The output from running this will contain compile and link errors, as +well as a textual version of the intermediate representation. + + +Procedure to build and run on Linux +----------------------------------- + +A simple bash script "BuildLinux.sh" is provided to do the build and run the test +cases, or you may run the steps manually as described below: + +"cd" into StandAlone directory and run make. It will build all the dependency +directories also. You can also go to the specific directories and do a make for each +directory individually. Make sure that there exists a lib directory at the given +path: glslang/MachineIndependent/lib where libglslang.so is stored. + +To compile glslang.l, flex version 2.5.31 is required. An executable of flex is +provided in tools directory. To compile glslang.y, bison version 1.35 or higher is +required. Most versions of Red Hat comes with bison 1.35. + +Once the executable is generated, it needs to be dynamically linked with the +shared object created in lib directory. To achieve that, we need to "cd" to +StandAlone directory to update the LD_LIBRARY_PATH as follows + +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./../glslang/MachineIndependent/lib + +You can also update LD_LIBRARY_PATH in the .cshrc or .bashrc file, depending on +the shell you are using. You will need to give the complete path of "lib" directory +in .cshrc or .bashrc files. + +The normal case will be to compile and link a pair of shaders like this: + + ./StandAlone -i .vert .frag + + where the following command line options are possible for StandAlone: + i - dump parse tree + m - dump linker output (nothing dumped in the source code provided) + a - dump assembly code (nothing dumped in the source code provided) + +The applied compilation-language is based on the file extension. +Give the full name of the files containing the shader source code. +The output from running this will contain compile and link errors, as +well as a textual version of the intermediate representation. + +To generate the dependencies, you can run "make depend". +This step has already been done and need not be done again by the user. + +To clean the ".o"s, ".a"s and ".so" generated by make, you can use "make clean". + + +Notes for Understanding/Modifying the Code +------------------------------------------ + +* This is completely machine independent code. We have a working + back-end card-specific compiler that is not present. Instead, a trivial + back-end compiler is in the directory GenericCodeGen. + +* The main directory for parsing and intermediate representation is + MachineIndependent. + +* Header files shared between machine independent parsing and the + machine dependent compiling and linking are in include. + +* Header files shared between the compiler and an ICD are in public. + +* Merging with future updates will be easiest if initially you confine + your changes to the GenericCodeGen directory. + +* To write a back-end compiler, see the next section on Basic Design. + + +Basic Design +------------ + +1. Code is parsed by flex/bison, with the aid of a symbol table and an + intermediate representation. The symbol table is not passed on to + the back-end; the intermediate representation stands on its own. + +2. The intermediate representation is very high-level, and represented + as an in-memory tree. This serves to lose no information from the + original program, and to have efficient transfer of the result from + parsing to the back-end. In the intermediate representation, + constants are propogated and folded, and some dead code is eliminated. + +3. The primary algorithm of the back-end compiler is to traverse the + tree (high-level intermediate representation), and create an internal + object code representation. There is a query in the compiler interface + to the ICD for retrieval of this object code. + +4. Reduction of the tree to a linear byte-code style low-level intermediate + representation is likely a good way to generate fully optimized code. + There is some possibility of standardizing such a byte code. + +See these files to get started: + +* IntermOut.cpp: this shows traversing the tree to generate output. +* CodeGen.cpp: this shows the basic interface to the back-end compiler. +* Link.cpp: this shows the basic interface to the linker. +* Intermediate.h: to see the data structures backing the tree. + diff --git a/StandAlone.sln b/StandAlone.sln new file mode 100644 index 00000000..b2f325ab --- /dev/null +++ b/StandAlone.sln @@ -0,0 +1,28 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tests - StandAlone", "StandAlone.vcproj", "{660D0A05-69A9-4F09-9664-02FBEB08FAE2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Targets - glslang (generic)", "glslang.vcproj", "{3B146CC5-B2B8-4573-9D46-6139E2EDFEA3}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = UserM_Debug + ConfigName.1 = UserM_Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + {660D0A05-69A9-4F09-9664-02FBEB08FAE2}.0 = {3B146CC5-B2B8-4573-9D46-6139E2EDFEA3} + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {660D0A05-69A9-4F09-9664-02FBEB08FAE2}.UserM_Debug.ActiveCfg = UserM_Debug|Win32 + {660D0A05-69A9-4F09-9664-02FBEB08FAE2}.UserM_Debug.Build.0 = UserM_Debug|Win32 + {660D0A05-69A9-4F09-9664-02FBEB08FAE2}.UserM_Release.ActiveCfg = UserM_Release|Win32 + {660D0A05-69A9-4F09-9664-02FBEB08FAE2}.UserM_Release.Build.0 = UserM_Release|Win32 + {3B146CC5-B2B8-4573-9D46-6139E2EDFEA3}.UserM_Debug.ActiveCfg = UserM_Debug|Win32 + {3B146CC5-B2B8-4573-9D46-6139E2EDFEA3}.UserM_Debug.Build.0 = UserM_Debug|Win32 + {3B146CC5-B2B8-4573-9D46-6139E2EDFEA3}.UserM_Release.ActiveCfg = UserM_Release|Win32 + {3B146CC5-B2B8-4573-9D46-6139E2EDFEA3}.UserM_Release.Build.0 = UserM_Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/StandAlone.vcproj b/StandAlone.vcproj new file mode 100644 index 00000000..411a83c8 --- /dev/null +++ b/StandAlone.vcproj @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/StandAlone/Makefile b/StandAlone/Makefile new file mode 100644 index 00000000..80023b1d --- /dev/null +++ b/StandAlone/Makefile @@ -0,0 +1,40 @@ +CC=g++ +OBJECTPATH=./../glslang/MachineIndependent +LIBPATH=./../glslang/MachineIndependent/lib +SRCS=StandAlone.cpp + +TARGETOBJECT=StandAlone.o + +default: all + +all: StandAlone + +StandAlone: $(TARGETOBJECT) SHAREDOBJECT + $(CC) -g -o $@ $(TARGETOBJECT) -L $(LIBPATH) -lglslang -lpthread \ + -lm -lstdc++ + +SHAREDOBJECT: + cd $(OBJECTPATH); make all + +%.o : %.cpp + $(CC) -c $< + +# +# Cleanup +# +.PHONY : clean +clean : + $(RM) *.o StandAlone + cd $(OBJECTPATH); make clean + +depend: + cd $(OBJECTPATH); make depend + makedepend -Y -- $(SRCS) +# DO NOT DELETE + +StandAlone.o: ./../glslang/Include/ShHandle.h +StandAlone.o: ./../glslang/Public/ShaderLang.h +StandAlone.o: ./../glslang/Include/InfoSink.h ./../glslang/Include/Common.h +StandAlone.o: ./../glslang/Include/PoolAlloc.h +StandAlone.o: ./../glslang/Public/ShaderLang.h + diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp new file mode 100644 index 00000000..e970185b --- /dev/null +++ b/StandAlone/StandAlone.cpp @@ -0,0 +1,366 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +#include "./../glslang/Include/ShHandle.h" +#include "./../glslang/Public/ShaderLang.h" +#include +#include + +#ifdef _WIN32 + #include + #include +#endif + +extern "C" { + SH_IMPORT_EXPORT void ShOutputHtml(); +} + +//#define MEASURE_MEMORY + +// +// Return codes from main. +// +enum TFailCode { + ESuccess = 0, + EFailUsage, + EFailCompile, + EFailLink, + EFailCompilerCreate, + EFailLinkerCreate +}; + +// +// Just placeholders for testing purposes. The stand-alone environment +// can't actually do a full link without something specifying real +// attribute bindings. +// +ShBinding FixedAttributeBindings[] = { + { "gl_Vertex", 15 }, + { "gl_Color", 10 }, + { "gl_Normal", 7 }, +}; + +ShBindingTable FixedAttributeTable = { 3, FixedAttributeBindings }; + +static EShLanguage FindLanguage(char *lang); +bool CompileFile(char *fileName, ShHandle, int, const TBuiltInResource*); +void usage(); +void FreeFileData(char **data); +char** ReadFileData(char *fileName); +void InfoLogMsg(char* msg, const char* name, const int num); +int ShOutputMultipleStrings(char ** ); +//Added to accomodate the multiple strings. +int OutputMultipleStrings = 1; + +// +// Set up the per compile resources +// +void GenerateResources(TBuiltInResource& resources) +{ + resources.maxLights = 32; + resources.maxClipPlanes = 6; + resources.maxTextureUnits = 32; + resources.maxTextureCoords = 32; + resources.maxVertexAttribs = 64; + resources.maxVertexUniformComponents = 4096; + resources.maxVaryingFloats = 64; + resources.maxVertexTextureImageUnits = 32; + resources.maxCombinedTextureImageUnits = 32; + resources.maxTextureImageUnits = 32; + resources.maxFragmentUniformComponents = 4096; + resources.maxDrawBuffers = 32; +} + +int C_DECL main(int argc, char* argv[]) +{ + bool delay = false; + int numCompilers = 0; + bool compileFailed = false; + bool linkFailed = false; + int debugOptions = 0; + int i; + + ShHandle linker = 0; + ShHandle uniformMap = 0; + ShHandle compilers[EShLangCount]; + + ShInitialize(); + +#ifdef _WIN32 + __try { +#endif + argc--; + argv++; + for (; argc >= 1; argc--, argv++) { + if (argv[0][0] == '-' || argv[0][0] == '/') { + switch (argv[0][1]) { + case 'd': delay = true; break; + +#ifdef MEASURE_MEMORY + case 'i': break; + case 'a': break; + case 'h': break; +#else + case 'i': debugOptions |= EDebugOpIntermediate; break; + case 'a': debugOptions |= EDebugOpAssembly; break; +#endif + case 'c': if(!ShOutputMultipleStrings(++argv)) + return EFailUsage; + --argc; break; + case 'm': debugOptions |= EDebugOpLinkMaps; break; + default: usage(); return EFailUsage; + } + } else { + compilers[numCompilers] = ShConstructCompiler(FindLanguage(argv[0]), debugOptions); + if (compilers[numCompilers] == 0) + return EFailCompilerCreate; + ++numCompilers; + + TBuiltInResource resources; + GenerateResources(resources); + if (! CompileFile(argv[0], compilers[numCompilers-1], debugOptions, &resources)) + compileFailed = true; + } + } + + if (!numCompilers) { + usage(); + return EFailUsage; + } + + linker = ShConstructLinker(EShExVertexFragment, debugOptions); + if (linker == 0) + return EFailLinkerCreate; + + uniformMap = ShConstructUniformMap(); + if (uniformMap == 0) + return EFailLinkerCreate; + + if (numCompilers > 0) { + ShSetFixedAttributeBindings(linker, &FixedAttributeTable); + if (! ShLink(linker, compilers, numCompilers, uniformMap, 0, 0)) + linkFailed = true; + } + + for (i = 0; i < numCompilers; ++i) { + InfoLogMsg("BEGIN", "COMPILER", i); + puts(ShGetInfoLog(compilers[i])); + InfoLogMsg("END", "COMPILER", i); + } + + InfoLogMsg("BEGIN", "LINKER", -1); + puts(ShGetInfoLog(linker)); + InfoLogMsg("END", "LINKER", -1); + +#ifdef _WIN32 + } __finally { +#endif + for (i = 0; i < numCompilers; ++i) + ShDestruct(compilers[i]); + + ShDestruct(linker); + ShDestruct(uniformMap); + +#ifdef _WIN32 + if (delay) + Sleep(1000000); + + } +#endif + + if (compileFailed) + return EFailCompile; + if (linkFailed) + return EFailLink; + + return 0; +} + +// +// Deduce the language from the filename. Files must end in one of the +// following extensions: +// +// .frag* = fragment programs +// .vert* = vertex programs +// .pack* = pack programs +// .unpa* = unpack pragrams +// +static EShLanguage FindLanguage(char *name) +{ + if (!name) + return EShLangFragment; + + char *ext = strrchr(name, '.'); + + if (ext && strcmp(ext, ".sl") == 0) + for (; ext > name && ext[0] != '.'; ext--); + + if (ext = strrchr(name, '.')) { + if (strncmp(ext, ".frag", 4) == 0) return EShLangFragment; + if (strncmp(ext, ".vert", 4) == 0) return EShLangVertex; + if (strncmp(ext, ".pack", 4) == 0) return EShLangPack; + if (strncmp(ext, ".unpa", 4) == 0) return EShLangUnpack; + } + + return EShLangFragment; +} + + +// +// Read a file's data into a string, and compile it using ShCompile +// +bool CompileFile(char *fileName, ShHandle compiler, int debugOptions, const TBuiltInResource *resources) +{ + int ret; + char **data = ReadFileData(fileName); + +#ifdef MEASURE_MEMORY + PROCESS_MEMORY_COUNTERS counters; +#endif + + if (!data) + return false; + +#ifdef MEASURE_MEMORY + for (int i = 0; i < 1000; ++i) { + for (int j = 0; j < 100; ++j) +#endif + ret = ShCompile(compiler, data, OutputMultipleStrings, EShOptNone, resources, debugOptions); +#ifdef MEASURE_MEMORY + + GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters)); + } +#endif + + FreeFileData(data); + + return ret ? true : false; +} + + +// +// print usage to stdout +// +void usage() +{ + printf("Usage: standalone [-i -a -c -m -d -h] file1 file2 ...\n" + "Where: filename = filename ending in .frag* or .vert*\n"); +} + + +// +// Malloc a string of sufficient size and read a string into it. +// +# define MAX_SOURCE_STRINGS 5 +char** ReadFileData(char *fileName) +{ + FILE *in = fopen(fileName, "r"); + char *fdata; + int count = 0; + char**return_data=(char**)malloc(MAX_SOURCE_STRINGS+1); + + //return_data[MAX_SOURCE_STRINGS]=NULL; + if (!in) { + printf("Error: unable to open input file: %s\n", fileName); + return 0; + } + + while (fgetc(in) != EOF) + count++; + + fseek(in, 0, SEEK_SET); + + + if (!(fdata = (char *)malloc(count+2))) { + printf("Error allocating memory\n"); + return 0; + } + if (fread(fdata,1,count, in)!=count) { + printf("Error reading input file: %s\n", fileName); + return 0; + } + fdata[count] = '\0'; + fclose(in); + if(count==0){ + return_data[0]=(char*)malloc(count+2); + return_data[0][0]='\0'; + OutputMultipleStrings=0; + return return_data; + } + + int len = (int)(ceil)((float)count/(float)OutputMultipleStrings); + int ptr_len=0,i=0; + while(count>0){ + return_data[i]=(char*)malloc(len+2); + memcpy(return_data[i],fdata+ptr_len,len); + return_data[i][len]='\0'; + count-=(len); + ptr_len+=(len); + if(count= 0 ? "#### %s %s %d INFO LOG ####\n" : + "#### %s %s INFO LOG ####\n", msg, name, num); +} + +int ShOutputMultipleStrings(char **argv) +{ + if(!(abs(OutputMultipleStrings = atoi(*argv)))||((OutputMultipleStrings >5 || OutputMultipleStrings < 1)? 1:0)){ + printf("Invalid Command Line Argument after -c option.\n" + "Usage: -c where integer =[1,5]\n" + "This option must be specified before the input file path\n"); + return 0; + } + return 1; +} diff --git a/StandAlone/sample.frag b/StandAlone/sample.frag new file mode 100644 index 00000000..0d11cb2e --- /dev/null +++ b/StandAlone/sample.frag @@ -0,0 +1,40 @@ +// +//Copyright (C) 2002-2004 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +varying vec3 color; + +void main() +{ + gl_FragColor = vec4(color, 1.0); +} diff --git a/StandAlone/sample.frag.out b/StandAlone/sample.frag.out new file mode 100644 index 00000000..5af223e4 --- /dev/null +++ b/StandAlone/sample.frag.out @@ -0,0 +1,15 @@ +#### BEGIN COMPILER 0 INFO LOG #### +0:? Sequence +0:37 Function Definition: main( (void) +0:37 Function Parameters: +0:39 Sequence +0:39 move second child to first child (4-component vector of float) +0:39 'gl_FragColor' (FragColor 4-component vector of float) +0:39 Construct vec4 (4-component vector of float) +0:39 'color' (varying 3-component vector of float) +0:39 1.000000 (const float) + +#### END COMPILER 0 INFO LOG #### +#### BEGIN LINKER INFO LOG #### + +#### END LINKER INFO LOG #### diff --git a/StandAlone/sample.vert b/StandAlone/sample.vert new file mode 100644 index 00000000..0ecaf2c3 --- /dev/null +++ b/StandAlone/sample.vert @@ -0,0 +1,42 @@ +// +//Copyright (C) 2002-2004 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +varying vec3 color; + +void main() +{ + color = vec3(1.0, 1.0, 1.0); + + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; +} diff --git a/StandAlone/sample.vert.out b/StandAlone/sample.vert.out new file mode 100644 index 00000000..2d50a828 --- /dev/null +++ b/StandAlone/sample.vert.out @@ -0,0 +1,20 @@ +#### BEGIN COMPILER 0 INFO LOG #### +0:? Sequence +0:37 Function Definition: main( (void) +0:37 Function Parameters: +0:39 Sequence +0:39 move second child to first child (3-component vector of float) +0:39 'color' (varying 3-component vector of float) +0:39 1.000000 (const float) +0:39 1.000000 (const float) +0:39 1.000000 (const float) +0:41 move second child to first child (4-component vector of float) +0:41 'gl_Position' (Position 4-component vector of float) +0:41 matrix-times-vector (4-component vector of float) +0:41 'gl_ModelViewProjectionMatrix' (uniform 4X4 matrix of float) +0:41 'gl_Vertex' (attribute 4-component vector of float) + +#### END COMPILER 0 INFO LOG #### +#### BEGIN LINKER INFO LOG #### + +#### END LINKER INFO LOG #### diff --git a/glslang.vcproj b/glslang.vcproj new file mode 100644 index 00000000..a1fdc9a6 --- /dev/null +++ b/glslang.vcproj @@ -0,0 +1,436 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/glslang/GenericCodeGen/CodeGen.cpp b/glslang/GenericCodeGen/CodeGen.cpp new file mode 100644 index 00000000..89394ba5 --- /dev/null +++ b/glslang/GenericCodeGen/CodeGen.cpp @@ -0,0 +1,75 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#include "../Include/Common.h" +#include "../Include/ShHandle.h" + +// +// Here is where real machine specific high-level data would be defined. +// +class TGenericCompiler : public TCompiler { +public: + TGenericCompiler(EShLanguage l, int dOptions) : TCompiler(l, infoSink), debugOptions(dOptions) { } + virtual bool compile(TIntermNode* root); + TInfoSink infoSink; + int debugOptions; +}; + +// +// This function must be provided to create the actual +// compile object used by higher level code. It returns +// a subclass of TCompiler. +// +TCompiler* ConstructCompiler(EShLanguage language, int debugOptions) +{ + return new TGenericCompiler(language, debugOptions); +} + +// +// Delete the compiler made by ConstructCompiler +// +void DeleteCompiler(TCompiler* compiler) +{ + delete compiler; +} + +// +// Generate code from the given parse tree +// +bool TGenericCompiler::compile(TIntermNode *root) +{ + haveValidObjectCode = true; + + return haveValidObjectCode; +} diff --git a/glslang/GenericCodeGen/Link.cpp b/glslang/GenericCodeGen/Link.cpp new file mode 100644 index 00000000..60762d8e --- /dev/null +++ b/glslang/GenericCodeGen/Link.cpp @@ -0,0 +1,91 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +// +// The top level algorithms for linking multiple +// shaders together. +// +#include "../Include/Common.h" +#include "../Include/ShHandle.h" + +// +// Actual link object, derived from the shader handle base classes. +// +class TGenericLinker : public TLinker { +public: + TGenericLinker(EShExecutable e, int dOptions) : TLinker(e, infoSink), debugOptions(dOptions) { } + bool link(TCompilerList&, TUniformMap*) { return true; } + void getAttributeBindings(ShBindingTable const **t) const { } + TInfoSink infoSink; + int debugOptions; +}; + +// +// The internal view of a uniform/float object exchanged with the driver. +// +class TUniformLinkedMap : public TUniformMap { +public: + TUniformLinkedMap() { } + virtual int getLocation(const char* name) { return 0; } +}; + +TShHandleBase* ConstructLinker(EShExecutable executable, int debugOptions) +{ + return new TGenericLinker(executable, debugOptions); +} + +void DeleteLinker(TShHandleBase* linker) +{ + delete linker; +} + +TUniformMap* ConstructUniformMap() +{ + return new TUniformLinkedMap(); +} + +void DeleteUniformMap(TUniformMap* map) +{ + delete map; +} + +TShHandleBase* ConstructBindings() +{ + return 0; +} + +void DeleteBindingList(TShHandleBase* bindingList) +{ + delete bindingList; +} diff --git a/glslang/GenericCodeGen/Makefile b/glslang/GenericCodeGen/Makefile new file mode 100644 index 00000000..2a2f62a1 --- /dev/null +++ b/glslang/GenericCodeGen/Makefile @@ -0,0 +1,34 @@ +CC = g++ + +OBJECTS = CodeGen.o Link.o +AR=ar + +SRCS=CodeGen.cpp Link.cpp + +default : all +all : libCodeGen.a + +libCodeGen.a : $(OBJECTS) + $(AR) rvu $@ $(OBJECTS) + ranlib $@ + +%.o : %.cpp + $(CC) -c $< + +# +# Cleanup +# +.PHONY : clean +clean : + $(RM) *.o *.a + +depend: + makedepend -- $(CFLAGS) -- $(SRCS) +# DO NOT DELETE + +CodeGen.o: ../Include/Common.h ../Include/PoolAlloc.h ../Include/ShHandle.h +CodeGen.o: ../Public/ShaderLang.h +CodeGen.o: ../Include/InfoSink.h +Link.o: ../Include/Common.h ../Include/PoolAlloc.h ../Include/ShHandle.h +Link.o: ../Public/ShaderLang.h +Link.o: ../Include/InfoSink.h diff --git a/glslang/Include/BaseTypes.h b/glslang/Include/BaseTypes.h new file mode 100644 index 00000000..1249cde4 --- /dev/null +++ b/glslang/Include/BaseTypes.h @@ -0,0 +1,137 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef _BASICTYPES_INCLUDED_ +#define _BASICTYPES_INCLUDED_ + +// +// Basic type. Arrays, vectors, etc., are orthogonal to this. +// +enum TBasicType { + EbtVoid, + EbtFloat, + EbtInt, + EbtBool, + EbtGuardSamplerBegin, // non type: see implementation of IsSampler() + EbtSampler1D, + EbtSampler2D, + EbtSampler3D, + EbtSamplerCube, + EbtSampler1DShadow, + EbtSampler2DShadow, + EbtSamplerRect, // ARB_texture_rectangle + EbtSamplerRectShadow, // ARB_texture_rectangle + EbtGuardSamplerEnd, // non type: see implementation of IsSampler() + EbtStruct, + EbtAddress, // should be deprecated?? +}; + +__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 + 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, + EvqClipVertex, + + // built-ins read by fragment shader + EvqFace, + EvqFragCoord, + + // built-ins written by fragment shader + EvqFragColor, + EvqFragDepth, + + // 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 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 EvqClipVertex: return "ClipVertex"; break; + case EvqFace: return "Face"; break; + case EvqFragCoord: return "FragCoord"; break; + case EvqFragColor: return "FragColor"; break; + case EvqFragDepth: return "FragDepth"; break; + default: return "unknown qualifier"; + } +} + +#endif // _BASICTYPES_INCLUDED_ diff --git a/glslang/Include/Common.h b/glslang/Include/Common.h new file mode 100644 index 00000000..9f20ed2f --- /dev/null +++ b/glslang/Include/Common.h @@ -0,0 +1,192 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef _COMMON_INCLUDED_ +#define _COMMON_INCLUDED_ + +#ifdef _WIN32 + #include +#elif defined (solaris) + #include + #define UINT_PTR uintptr_t +#else + #include + #define UINT_PTR uintptr_t +#endif + +/* windows only pragma */ +#ifdef _MSC_VER + #pragma warning(disable : 4786) // Don't warn about too long identifiers + #pragma warning(disable : 4514) // unused inline method + #pragma warning(disable : 4201) // nameless union +#endif + +// +// Doing the push and pop below for warnings does not leave the warning state +// the way it was. This seems like a defect in the compiler. We would like +// to do this, but since it does not work correctly right now, it is turned +// off. +// +//??#pragma warning(push, 3) + + #include + #include + #include + #include + #include + #include + +//??#pragma warning(pop) + +typedef int TSourceLoc; + + #include + +#include "PoolAlloc.h" + +// +// 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 *) { } + +#define TBaseMap std::map +#define TBaseList std::list +#define TBaseSet std::set + +// +// Pool version of string. +// +typedef pool_allocator TStringAllocator; +typedef std::basic_string , TStringAllocator > TString; +inline TString* NewPoolTString(const char* s) +{ + void* memory = GlobalPoolAllocator.allocate(sizeof(TString)); + return new(memory) TString(s); +} + +// +// Pool allocator versions of vectors, lists, and maps +// +template class TVector : public std::vector > { +public: + typedef typename std::vector >::size_type size_type; + TVector() : std::vector >() {} + TVector(const pool_allocator& a) : std::vector >(a) {} + TVector(size_type i): std::vector >(i) {} +}; + +template class TList : public TBaseList > { +public: + typedef typename TBaseList >::size_type size_type; + TList() : TBaseList >() {} + TList(const pool_allocator& a) : TBaseList >(a) {} + TList(size_type i): TBaseList >(i) {} +}; + +// This is called TStlSet, because TSet is taken by an existing compiler class. +template class TStlSet : public std::set > { + // No pool allocator versions of constructors in std::set. +}; + + +template > +class TMap : public TBaseMap > > { +public: + typedef pool_allocator > tAllocator; + + TMap() : TBaseMap() {} + // use correct two-stage name lookup supported in gcc 3.4 and above + TMap(const tAllocator& a) : TBaseMap(TBaseMap::key_compare(), a) {} +}; + +// +// Persistent string memory. Should only be used for strings that survive +// across compiles/links. +// +typedef std::basic_string TPersistString; + +// +// templatized min and max functions. +// +template T Min(const T a, const T b) { return a < b ? a : b; } +template T Max(const T a, const T b) { return a > b ? a : b; } + +// +// Create a TString object from an integer. +// +inline const TString String(const int i, const int base = 10) +{ + char text[16]; // 32 bit ints are at most 10 digits in base 10 + + #ifdef _WIN32 + itoa(i, text, base); + #else + // we assume base 10 for all cases + sprintf(text, "%d", i); + #endif + + return text; +} + +const unsigned int SourceLocLineMask = 0xffff; +const unsigned int SourceLocStringShift = 16; + +__inline TPersistString FormatSourceLoc(const TSourceLoc loc) +{ + char locText[64]; + + int string = loc >> SourceLocStringShift; + int line = loc & SourceLocLineMask; + + if (line) + sprintf(locText, "%d:%d", string, line); + else + sprintf(locText, "%d:? ", string); + + return TPersistString(locText); +} + + +typedef TMap TPragmaTable; +typedef TMap::tAllocator TPragmaTableAllocator; + +#endif // _COMMON_INCLUDED_ diff --git a/glslang/Include/ConstantUnion.h b/glslang/Include/ConstantUnion.h new file mode 100644 index 00000000..31167965 --- /dev/null +++ b/glslang/Include/ConstantUnion.h @@ -0,0 +1,315 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef _CONSTANT_UNION_INCLUDED_ +#define _CONSTANT_UNION_INCLUDED_ + + +class constUnion { +public: + + 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; } + + bool operator==(const int i) const + { + if (i == iConst) + return true; + + return false; + } + + bool operator==(const float f) const + { + if (f == fConst) + return true; + + return false; + } + + bool operator==(const bool b) const + { + if (b == bConst) + return true; + + return false; + } + + bool operator==(const constUnion& constant) const + { + if (constant.type != type) + return false; + + switch (type) { + case EbtInt: + if (constant.iConst == iConst) + return true; + + break; + case EbtFloat: + if (constant.fConst == fConst) + return true; + + break; + case EbtBool: + if (constant.bConst == bConst) + return true; + + break; + } + + 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 constUnion& constant) const + { + return !operator==(constant); + } + + bool operator>(const constUnion& constant) const + { + assert(type == constant.type); + switch (type) { + case EbtInt: + if (iConst > constant.iConst) + return true; + + return false; + case EbtFloat: + if (fConst > constant.fConst) + return true; + + return false; + default: + assert(false && "Default missing"); + return false; + } + + return false; + } + + bool operator<(const constUnion& constant) const + { + assert(type == constant.type); + switch (type) { + case EbtInt: + if (iConst < constant.iConst) + return true; + + return false; + case EbtFloat: + if (fConst < constant.fConst) + return true; + + return false; + default: + assert(false && "Default missing"); + return false; + } + + return false; + } + + constUnion operator+(const constUnion& constant) const + { + constUnion 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; + } + + constUnion operator-(const constUnion& constant) const + { + constUnion 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; + } + + constUnion operator*(const constUnion& constant) const + { + constUnion 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; + } + + constUnion operator%(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst % constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + constUnion operator>>(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + constUnion operator<<(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst << constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + constUnion operator&(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst & constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + constUnion operator|(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst | constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + constUnion operator^(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + constUnion operator&&(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtBool: returnValue.setBConst(bConst && constant.bConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + constUnion operator||(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtBool: returnValue.setBConst(bConst || constant.bConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + TBasicType getType() { 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/glslang/Include/InfoSink.h b/glslang/Include/InfoSink.h new file mode 100644 index 00000000..debe9bbd --- /dev/null +++ b/glslang/Include/InfoSink.h @@ -0,0 +1,137 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef _INFOSINK_INCLUDED_ +#define _INFOSINK_INCLUDED_ + +#include "../Include/Common.h" +#include + +// +// TPrefixType is used to centralize how info log messages start. +// See below. +// +enum TPrefixType { + EPrefixNone, + EPrefixWarning, + EPrefixError, + EPrefixInternalError, + EPrefixUnimplemented, + EPrefixNote +}; + +enum TOutputStream { + ENull = 0, + EDebugger = 0x01, + EStdOut = 0x02, + EString = 0x04, +}; +// +// 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() : outputStream(4) {} + void erase() { sink.erase(); } + TInfoSinkBase& operator<<(const TPersistString& t) { append(t); return *this; } + TInfoSinkBase& operator<<(char c) { append(1, c); return *this; } + TInfoSinkBase& operator<<(const char* s) { append(s); return *this; } + TInfoSinkBase& operator<<(int n) { append(String(n)); return *this; } + TInfoSinkBase& operator<<(const unsigned int n) { append(String(n)); return *this; } + TInfoSinkBase& operator<<(float n) { char buf[40]; + sprintf(buf, (fabs(n) > 1e-8 && fabs(n) < 1e8) || n == 0.0f ? + "%f" : "%g", n); + append(buf); + return *this; } + TInfoSinkBase& operator+(const TPersistString& t) { append(t); return *this; } + TInfoSinkBase& operator+(const TString& t) { append(t); return *this; } + TInfoSinkBase& operator<<(const TString& t) { append(t); return *this; } + TInfoSinkBase& operator+(const char* s) { append(s); return *this; } + const char* c_str() const { return sink.c_str(); } + void prefix(TPrefixType message) { + switch(message) { + case EPrefixNone: break; + case EPrefixWarning: append("WARNING: "); break; + case EPrefixError: append("ERROR: "); break; + case EPrefixInternalError: append("INTERNAL ERROR: "); break; + case EPrefixUnimplemented: append("UNIMPLEMENTED: "); break; + case EPrefixNote: append("NOTE: "); break; + default: append("UNKOWN ERROR: "); break; + } + } + void location(TSourceLoc loc) { + append(FormatSourceLoc(loc).c_str()); + append(": "); + } + void message(TPrefixType message, const char* s) { + prefix(message); + append(s); + append("\n"); + } + void message(TPrefixType message, const char* s, TSourceLoc loc) { + prefix(message); + location(loc); + append(s); + append("\n"); + } + + void setOutputStream(int output = 4) + { + outputStream = output; + } + +protected: + void append(const char *s); + + void append(int count, char c); + void append(const TPersistString& t); + void append(const TString& t); + + void checkMem(size_t growth) { if (sink.capacity() < sink.size() + growth + 2) + sink.reserve(sink.capacity() + sink.capacity() / 2); } + void appendToStream(const char* s); + TPersistString sink; + int outputStream; +}; + +class TInfoSink { +public: + TInfoSinkBase info; + TInfoSinkBase debug; +}; + +#endif // _INFOSINK_INCLUDED_ diff --git a/glslang/Include/InitializeGlobals.h b/glslang/Include/InitializeGlobals.h new file mode 100644 index 00000000..dc1ef91e --- /dev/null +++ b/glslang/Include/InitializeGlobals.h @@ -0,0 +1,43 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef __INITIALIZE_GLOBALS_INCLUDED_ +#define __INITIALIZE_GLOBALS_INCLUDED_ + +void InitializeGlobalPools(); +void FreeGlobalPools(); +bool InitializePoolIndex(); +void FreePoolIndex(); + +#endif // __INITIALIZE_GLOBALS_INCLUDED_ diff --git a/glslang/Include/InitializeParseContext.h b/glslang/Include/InitializeParseContext.h new file mode 100644 index 00000000..4d369e8a --- /dev/null +++ b/glslang/Include/InitializeParseContext.h @@ -0,0 +1,45 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef __INITIALIZE_PARSE_CONTEXT_INCLUDED_ +#define __INITIALIZE_PARSE_CONTEXT_INCLUDED_ +#include "osinclude.h" + +bool InitializeParseContextIndex(); +bool InitializeGlobalParseContext(); +bool FreeParseContext(); +bool FreeParseContextIndex(); + + +#endif // __INITIALIZE_PARSE_CONTEXT_INCLUDED_ diff --git a/glslang/Include/PoolAlloc.h b/glslang/Include/PoolAlloc.h new file mode 100644 index 00000000..14c59851 --- /dev/null +++ b/glslang/Include/PoolAlloc.h @@ -0,0 +1,349 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#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 +#include + +// 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, 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(bool global = false, 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) : +#ifdef GUARD_BLOCKS + lastAllocation(0), +#endif + nextPage(nextPage), pageCount(pageCount) { } + + ~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 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(memory); +# endif + + // This is optimized entirely away if GUARD_BLOCKS is not defined. + return TAllocation::offsetAllocation(memory); + } + + bool global; // should be true if this object is globally scoped + 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. +// +typedef TPoolAllocator* PoolAllocatorPointer; +extern TPoolAllocator& GetGlobalPoolAllocator(); +#define GlobalPoolAllocator GetGlobalPoolAllocator() + + +struct TThreadGlobalPools +{ + TPoolAllocator* globalPoolAllocator; +}; + +void SetGlobalPoolAllocatorPtr(TPoolAllocator* poolAllocator); + +// +// 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 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 + struct rebind { + typedef pool_allocator other; + }; + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } + +#ifdef USING_SGI_STL + pool_allocator() { } +#else + pool_allocator() : allocator(GlobalPoolAllocator) { } + pool_allocator(TPoolAllocator& a) : allocator(a) { } + pool_allocator(const pool_allocator& p) : allocator(p.allocator) { } +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1300 + template +#ifdef USING_SGI_STL + pool_allocator(const pool_allocator& p) /*: allocator(p.getAllocator())*/ { } +#else + pool_allocator(const pool_allocator& p) : allocator(p.getAllocator()) { } +#endif +#endif + +#ifndef _WIN32 + template + pool_allocator(const pool_allocator& p) : allocator(p.getAllocator()) { } +#endif + +#ifdef USING_SGI_STL + static pointer allocate(size_type n) { + return reinterpret_cast(getAllocator().allocate(n)); } + pointer allocate(size_type n, const void*) { + return reinterpret_cast(getAllocator().allocate(n)); } + + static void deallocate(void*, size_type) { } + static void deallocate(pointer, size_type) { } +#else + pointer allocate(size_type n) { + return reinterpret_cast(getAllocator().allocate(n * sizeof(T))); } + pointer allocate(size_type n, const void*) { + return reinterpret_cast(getAllocator().allocate(n * sizeof(T))); } + + void deallocate(void*, size_type) { } + void deallocate(pointer, size_type) { } +#endif + + pointer _Charalloc(size_t n) { + return reinterpret_cast(getAllocator().allocate(n)); } + + 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(-1) / sizeof(T); } + size_type max_size(int size) const { return static_cast(-1) / size; } + +#ifdef USING_SGI_STL + //void setAllocator(TPoolAllocator* a) { allocator = a; } + static TPoolAllocator& getAllocator() { return GlobalPoolAllocator; } +#else + void setAllocator(TPoolAllocator* a) { allocator = *a; } + TPoolAllocator& getAllocator() const { return allocator; } + +protected: + TPoolAllocator& allocator; +#endif +}; + +#endif // _POOLALLOC_INCLUDED_ diff --git a/glslang/Include/ResourceLimits.h b/glslang/Include/ResourceLimits.h new file mode 100644 index 00000000..f3d1a531 --- /dev/null +++ b/glslang/Include/ResourceLimits.h @@ -0,0 +1,52 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef _RESOURCE_LIMITS_INCLUDED_ +#define _RESOURCE_LIMITS_INCLUDED_ + +struct TBuiltInResource { + int maxLights; + int maxClipPlanes; + int maxTextureUnits; + int maxTextureCoords; + int maxVertexAttribs; + int maxVertexUniformComponents; + int maxVaryingFloats; + int maxVertexTextureImageUnits; + int maxCombinedTextureImageUnits; + int maxTextureImageUnits; + int maxFragmentUniformComponents; + int maxDrawBuffers; +}; +#endif // _RESOURCE_LIMITS_INCLUDED_ diff --git a/glslang/Include/ShHandle.h b/glslang/Include/ShHandle.h new file mode 100644 index 00000000..0bde67b6 --- /dev/null +++ b/glslang/Include/ShHandle.h @@ -0,0 +1,169 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#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. +// + + +#define SH_EXPORTING +#include "../Public/ShaderLang.h" + +#include "InfoSink.h" + +class TCompiler; +class TLinker; +class TUniformMap; + + +// +// The base class used to back handles returned to the driver. +// +class TShHandleBase { +public: + TShHandleBase() { } + virtual ~TShHandleBase() { } + virtual TCompiler* getAsCompiler() { return 0; } + virtual TLinker* getAsLinker() { return 0; } + virtual TUniformMap* getAsUniformMap() { return 0; } +}; + +// +// The base class for the machine dependent linker to derive from +// for managing where uniforms live. +// +class TUniformMap : public TShHandleBase { +public: + TUniformMap() { } + virtual ~TUniformMap() { } + virtual TUniformMap* getAsUniformMap() { return this; } + virtual int getLocation(const char* name) = 0; + virtual TInfoSink& getInfoSink() { return infoSink; } + TInfoSink infoSink; +}; +class TIntermNode; + +// +// The base class for the machine dependent compiler to derive from +// for managing object code from the compile. +// +class TCompiler : public TShHandleBase { +public: + TCompiler(EShLanguage l, TInfoSink& sink) : infoSink(sink) , language(l), haveValidObjectCode(false) { } + virtual ~TCompiler() { } + EShLanguage getLanguage() { return language; } + virtual TInfoSink& getInfoSink() { return infoSink; } + + virtual bool compile(TIntermNode* root) = 0; + + virtual TCompiler* getAsCompiler() { return this; } + virtual bool linkable() { return haveValidObjectCode; } + + TInfoSink& infoSink; +protected: + EShLanguage language; + bool haveValidObjectCode; +}; + +// +// Link operations are base on a list of compile results... +// +typedef TVector TCompilerList; +typedef TVector THandleList; + +// +// The base class for the machine dependent linker to derive from +// to manage the resulting executable. +// + +class TLinker : public TShHandleBase { +public: + TLinker(EShExecutable e, TInfoSink& iSink) : + infoSink(iSink), + executable(e), + haveReturnableObjectCode(false), + appAttributeBindings(0), + fixedAttributeBindings(0), + excludedAttributes(0), + excludedCount(0), + uniformBindings(0) { } + virtual TLinker* getAsLinker() { return this; } + virtual ~TLinker() { } + virtual bool link(TCompilerList&, TUniformMap*) = 0; + virtual bool link(THandleList&) { return false; } + virtual void setAppAttributeBindings(const ShBindingTable* t) { appAttributeBindings = t; } + virtual void setFixedAttributeBindings(const ShBindingTable* t) { fixedAttributeBindings = t; } + virtual void getAttributeBindings(ShBindingTable const **t) const = 0; + virtual void setExcludedAttributes(const int* attributes, int count) { excludedAttributes = attributes; excludedCount = count; } + virtual ShBindingTable* getUniformBindings() const { return uniformBindings; } + virtual const void* getObjectCode() const { return 0; } // a real compiler would be returning object code here + virtual TInfoSink& getInfoSink() { return infoSink; } + TInfoSink& infoSink; +protected: + EShExecutable executable; + bool haveReturnableObjectCode; // true when objectCode is acceptable to send to driver + + const ShBindingTable* appAttributeBindings; + const ShBindingTable* fixedAttributeBindings; + const int* excludedAttributes; + int excludedCount; + ShBindingTable* uniformBindings; // created by the linker +}; + +// +// 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(EShLanguage, int); + +TShHandleBase* ConstructLinker(EShExecutable, int); +void DeleteLinker(TShHandleBase*); + +TUniformMap* ConstructUniformMap(); +void DeleteCompiler(TCompiler*); + +void DeleteUniformMap(TUniformMap*); + +#endif // _SHHANDLE_INCLUDED_ diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h new file mode 100644 index 00000000..3db8d3a6 --- /dev/null +++ b/glslang/Include/Types.h @@ -0,0 +1,322 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef _TYPES_INCLUDED +#define _TYPES_INCLUDED + +#include "../Include/Common.h" +#include "../Include/BaseTypes.h" + +// +// Need to have association of line numbers to types in a list for building structs. +// +class TType; +struct TTypeLine { + TType* type; + int line; +}; +typedef TVector TTypeList; + +inline TTypeList* NewPoolTTypeList() +{ + void* memory = GlobalPoolAllocator.allocate(sizeof(TTypeList)); + return new(memory) TTypeList; +} + +// +// 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. +// +class TPublicType { +public: + TBasicType type; + TQualifier qualifier; + 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; + 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; + } +}; + +typedef std::map TStructureMap; +typedef std::map::iterator TStructureMapIterator; +// +// Base class for things that have a type. +// +class TType { +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + explicit TType(TBasicType t, TQualifier q = EvqTemporary, int s = 1, bool m = false, bool a = false) : + type(t), qualifier(q), size(s), matrix(m), array(a), arraySize(0), + structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0), typeName(0) + { } + explicit TType(const TPublicType &p) : + type(p.type), qualifier(p.qualifier), size(p.size), matrix(p.matrix), array(p.array), arraySize(p.arraySize), + structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0), typeName(0) + { + if (p.userDef) { + structure = p.userDef->getStruct(); + typeName = NewPoolTString(p.userDef->getTypeName().c_str()); + } + } + explicit TType(TTypeList* userDef, const TString& n) : + type(EbtStruct), qualifier(EvqTemporary), size(1), matrix(false), array(false), arraySize(0), + structure(userDef), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0) { + typeName = NewPoolTString(n.c_str()); + } + explicit TType() {} + virtual ~TType() {} + + TType(const TType& type) { *this = type; } + + void copyType(const TType& copyOf, TStructureMap& remapper) + { + type = copyOf.type; + 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; + 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; + } + + virtual void setType(TBasicType t, int s, bool m, bool a, int aS = 0) + { type = t; size = s; matrix = m; array = a; arraySize = aS; } + virtual void setType(TBasicType t, int s, bool m, TType* userDef = 0) + { type = t; + size = s; + matrix = m; + if (userDef) + structure = userDef->getStruct(); + // leave array information intact. + } + virtual void setTypeName(const TString& n) { typeName = NewPoolTString(n.c_str()); } + virtual void setFieldName(const TString& n) { fieldName = NewPoolTString(n.c_str()); } + virtual const TString& getTypeName() const + { + assert(typeName); + return *typeName; + } + + virtual const TString& getFieldName() const + { + assert(fieldName); + return *fieldName; + } + + virtual TBasicType getBasicType() const { return type; } + virtual TQualifier getQualifier() const { return qualifier; } + virtual void changeQualifier(TQualifier q) { qualifier = q; } + + // One-dimensional size of single instance type + virtual int getNominalSize() const { return size; } + + // Full-dimensional size of single instance of type + virtual int getInstanceSize() const + { + if (matrix) + return size * size; + else + return size; + } + + virtual bool isMatrix() const { return matrix ? true : false; } + virtual bool isArray() const { return array ? true : false; } + int getArraySize() const { return arraySize; } + void setArraySize(int s) { array = true; arraySize = s; } + void setMaxArraySize (int s) { maxArraySize = s; } + int getMaxArraySize () const { return maxArraySize; } + void clearArrayness() { array = false; arraySize = 0; maxArraySize = 0; } + void setArrayInformationType(TType* t) { arrayInformationType = t; } + TType* getArrayInformationType() { return arrayInformationType; } + virtual bool isVector() const { return size > 1 && !matrix; } + static 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 EbtSampler1D: return "sampler1D"; break; + case EbtSampler2D: return "sampler2D"; break; + case EbtSampler3D: return "sampler3D"; break; + case EbtSamplerCube: return "samplerCube"; break; + case EbtSampler1DShadow: return "sampler1DShadow"; break; + case EbtSampler2DShadow: return "sampler2DShadow"; break; + case EbtSamplerRect: return "samplerRect"; break; // ARB_texture_rectangle + case EbtSamplerRectShadow: return "samplerRectShadow"; break; // ARB_texture_rectangle + case EbtStruct: return "structure"; break; + default: return "unknown type"; + } + } + const char* getBasicString() const { return TType::getBasicString(type); } + const char* getQualifierString() const { return ::getQualifierString(qualifier); } + TTypeList* getStruct() { return structure; } + + int getObjectSize() const + { + int totalSize; + + if (getBasicType() == EbtStruct) + totalSize = getStructSize(); + else if (matrix) + totalSize = size * size; + else + totalSize = size; + + if (isArray()) + totalSize *= Max(getArraySize(), getMaxArraySize()); + + return totalSize; + } + + TTypeList* getStruct() const { return structure; } + 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); + } + TString getCompleteString() const; + +protected: + void buildMangledName(TString&); + int getStructSize() const; + + TBasicType type : 6; + 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; + + TTypeList* structure; // 0 unless this is a struct + mutable int structureSize; + int maxArraySize; + TType* arrayInformationType; + TString *fieldName; // for structure field names + TString *mangled; + TString *typeName; // for structure field type name +}; + +#endif // _TYPES_INCLUDED_ diff --git a/glslang/Include/intermediate.h b/glslang/Include/intermediate.h new file mode 100644 index 00000000..336e43c1 --- /dev/null +++ b/glslang/Include/intermediate.h @@ -0,0 +1,522 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +// +// 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 "../Include/Common.h" +#include "../Include/Types.h" +#include "../Include/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 + + // + // Unary operators + // + + EOpNegative, + EOpLogicalNot, + EOpVectorLogicalNot, + EOpBitwiseNot, + + EOpPostIncrement, + EOpPostDecrement, + EOpPreIncrement, + EOpPreDecrement, + + EOpConvIntToBool, + EOpConvFloatToBool, + EOpConvBoolToFloat, + EOpConvIntToFloat, + EOpConvFloatToInt, + EOpConvBoolToInt, + + // + // binary operations + // + + EOpAdd, + EOpSub, + EOpMul, + EOpDiv, + EOpMod, + EOpRightShift, + EOpLeftShift, + EOpAnd, + EOpInclusiveOr, + EOpExclusiveOr, + 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, + EOpMin, + EOpMax, + EOpClamp, + EOpMix, + EOpStep, + EOpSmoothStep, + + EOpLength, + EOpDistance, + EOpDot, + EOpCross, + EOpNormalize, + EOpFaceForward, + EOpReflect, + EOpRefract, + + EOpDPdx, // Fragment only + EOpDPdy, // Fragment only + EOpFwidth, // Fragment only + + EOpMatrixTimesMatrix, + + EOpAny, + EOpAll, + + EOpItof, // pack/unpack only + EOpFtoi, // pack/unpack only + EOpSkipPixels, // pack/unpack only + EOpReadInput, // unpack only + EOpWritePixel, // unpack only + EOpBitmapLsb, // unpack only + EOpBitmapMsb, // unpack only + EOpWriteOutput, // pack only + EOpReadPixel, // pack only + + // + // 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, + EOpAddAssign, + EOpSubAssign, + EOpMulAssign, + EOpVectorTimesMatrixAssign, + EOpVectorTimesScalarAssign, + EOpMatrixTimesScalarAssign, + EOpMatrixTimesMatrixAssign, + EOpDivAssign, + EOpModAssign, + EOpAndAssign, + EOpInclusiveOrAssign, + EOpExclusiveOrAssign, + EOpLeftShiftAssign, + EOpRightShiftAssign, + + // + // Array operators + // + + EOpArrayLength, +}; + +class TIntermTraverser; +class TIntermAggregate; +class TIntermBinary; +class TIntermConstantUnion; +class TIntermSelection; +class TIntermTyped; +class TIntermSymbol; +class TInfoSink; + +// +// Base class for the tree nodes +// +class TIntermNode { +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + + TIntermNode() : line(0) {} + virtual TSourceLoc getLine() const { return line; } + virtual 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 TIntermSelection* getAsSelectionNode() { return 0; } + virtual TIntermSymbol* getAsSymbolNode() { return 0; } + virtual ~TIntermNode() { } +protected: + TSourceLoc line; +}; + +// +// This is just to help yacc. +// +struct TIntermNodePair { + TIntermNode* node1; + TIntermNode* node2; +}; + +class TIntermSymbol; +class TIntermBinary; + +// +// Intermediate class for nodes that have a type. +// +class TIntermTyped : public TIntermNode { +public: + TIntermTyped(const TType& t) : type(t) { } + virtual TIntermTyped* getAsTyped() { return this; } + virtual void setType(const TType& t) { type = t; } + virtual TType getType() const { return type; } + virtual TType* getTypePointer() { return &type; } + + virtual TBasicType getBasicType() const { return type.getBasicType(); } + virtual TQualifier getQualifier() const { return type.getQualifier(); } + virtual int getNominalSize() const { return type.getNominalSize(); } + virtual int getSize() const { return type.getInstanceSize(); } + virtual bool isMatrix() const { return type.isMatrix(); } + virtual bool isArray() const { return type.isArray(); } + virtual bool isVector() const { return type.isVector(); } + const char* getBasicString() const { return type.getBasicString(); } + const char* getQualifierString() const { return type.getQualifierString(); } + TString getCompleteString() const { return type.getCompleteString(); } + +protected: + TType type; +}; + +// +// Handle for, do-while, and while loops. +// +class TIntermLoop : public TIntermNode { +public: + TIntermLoop(TIntermNode* aBody, TIntermTyped* aTest, TIntermTyped* aTerminal, bool testFirst) : + body(aBody), + test(aTest), + terminal(aTerminal), + first(testFirst) { } + virtual void traverse(TIntermTraverser*); + TIntermNode* getBody() { return body; } + TIntermTyped* getTest() { return test; } + TIntermTyped* getTerminal() { return terminal; } + bool testFirst() { return first; } +protected: + TIntermNode* body; // code to loop over + TIntermTyped* test; // exit condition associated with loop, could be 0 for 'for' loops + TIntermTyped* terminal; // exists for for-loops + bool first; // true for while and for, not for do-while +}; + +// +// Handle break, continue, return, and kill. +// +class TIntermBranch : public TIntermNode { +public: + TIntermBranch(TOperator op, TIntermTyped* e) : + flowOp(op), + expression(e) { } + 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;} + virtual int getId() const { return id; } + virtual const TString& getSymbol() const { return symbol; } + virtual void traverse(TIntermTraverser*); + virtual TIntermSymbol* getAsSymbolNode() { return this; } +protected: + int id; + TString symbol; +}; + +class TIntermConstantUnion : public TIntermTyped { +public: + TIntermConstantUnion(constUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { } + constUnion* getUnionArrayPointer() const { return unionArrayPointer; } + void setUnionArrayPointer(constUnion *c) { unionArrayPointer = c; } + virtual TIntermConstantUnion* getAsConstantUnion() { return this; } + virtual void traverse(TIntermTraverser* ); + virtual TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&); +protected: + constUnion *unionArrayPointer; +}; + +// +// Intermediate class for node types that hold operators. +// +class TIntermOperator : public TIntermTyped { +public: + TOperator getOp() { return op; } + bool modifiesState() const; + bool isConstructor() const; + virtual bool promote(TInfoSink&) { return true; } +protected: + TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat)), 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 void traverse(TIntermTraverser*); + virtual void setLeft(TIntermTyped* n) { left = n; } + virtual void setRight(TIntermTyped* n) { right = n; } + virtual TIntermTyped* getLeft() const { return left; } + virtual TIntermTyped* getRight() const { return right; } + virtual TIntermBinary* getAsBinaryNode() { return this; } + virtual 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 void setOperand(TIntermTyped* o) { operand = o; } + virtual TIntermTyped* getOperand() { return operand; } + virtual bool promote(TInfoSink&); +protected: + TIntermTyped* operand; +}; + +typedef TVector TIntermSequence; +typedef TVector TQualifierList; +// +// Nodes that operate on an arbitrary sized set of children. +// +class TIntermAggregate : public TIntermOperator { +public: + TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), pragmaTable(0) { } + TIntermAggregate(TOperator o) : TIntermOperator(o), pragmaTable(0) { } + ~TIntermAggregate() { delete pragmaTable; } + virtual TIntermAggregate* getAsAggregate() { return this; } + virtual void setOperator(TOperator o) { op = o; } + virtual TIntermSequence& getSequence() { return sequence; } + virtual void setName(const TString& n) { name = n; } + virtual const TString& getName() const { return name; } + virtual void traverse(TIntermTraverser*); + virtual void setUserDefined() { userDefined = true; } + virtual bool isUserDefined() { return userDefined; } + virtual TQualifierList& getQualifier() { return qualifier; } + void setOptimize(bool o) { optimize = o; } + void setDebug(bool d) { debug = d; } + bool getOptimize() { return optimize; } + bool getDebug() { return debug; } + void addToPragmaTable(const TPragmaTable& pTable); + const TPragmaTable& getPragmaTable() const { return *pragmaTable; } +protected: + TIntermAggregate(const TIntermAggregate&); // disallow copy constructor + TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator + TIntermSequence sequence; + TQualifierList qualifier; + TString name; + bool userDefined; // used for user defined function names + bool optimize; + bool debug; + TPragmaTable *pragmaTable; +}; + +// +// 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)), condition(cond), trueBlock(trueB), falseBlock(falseB) {} + TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) : + TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {} + virtual void traverse(TIntermTraverser*); + virtual TIntermNode* getCondition() const { return condition; } + virtual TIntermNode* getTrueBlock() const { return trueBlock; } + virtual TIntermNode* getFalseBlock() const { return falseBlock; } + virtual TIntermSelection* getAsSelectionNode() { return this; } +protected: + TIntermTyped* condition; + TIntermNode* trueBlock; + TIntermNode* falseBlock; +}; + +// +// 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() : + visitSymbol(0), + visitConstantUnion(0), + visitBinary(0), + visitUnary(0), + visitSelection(0), + visitAggregate(0), + visitLoop(0), + visitBranch(0), + depth(0), + preVisit(true), + postVisit(false), + rightToLeft(false) {} + + void (*visitSymbol)(TIntermSymbol*, TIntermTraverser*); + void (*visitConstantUnion)(TIntermConstantUnion*, TIntermTraverser*); + bool (*visitBinary)(bool preVisit, TIntermBinary*, TIntermTraverser*); + bool (*visitUnary)(bool preVisit, TIntermUnary*, TIntermTraverser*); + bool (*visitSelection)(bool preVisit, TIntermSelection*, TIntermTraverser*); + bool (*visitAggregate)(bool preVisit, TIntermAggregate*, TIntermTraverser*); + bool (*visitLoop)(bool preVisit, TIntermLoop*, TIntermTraverser*); + bool (*visitBranch)(bool preVisit, TIntermBranch*, TIntermTraverser*); + + int depth; + bool preVisit; + bool postVisit; + bool rightToLeft; +}; + +#endif // __INTERMEDIATE_H diff --git a/glslang/MachineIndependent/InfoSink.cpp b/glslang/MachineIndependent/InfoSink.cpp new file mode 100644 index 00000000..b8c1f5f0 --- /dev/null +++ b/glslang/MachineIndependent/InfoSink.cpp @@ -0,0 +1,107 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#include "Include/InfoSink.h" + +#ifdef _WIN32 + #include +#endif + +void TInfoSinkBase::append(const char *s) +{ + if (outputStream & EString) { + checkMem(strlen(s)); + sink.append(s); + } + +#ifdef _WIN32 + if (outputStream & EDebugger) + OutputDebugString(s); +#endif + + if (outputStream & EStdOut) + fprintf(stdout, "%s", s); +} + +void TInfoSinkBase::append(int count, char c) +{ + if (outputStream & EString) { + checkMem(count); + sink.append(count, c); + } + +#ifdef _WIN32 + if (outputStream & EDebugger) { + char str[2]; + str[0] = c; + str[1] = '\0'; + OutputDebugString(str); + } +#endif + + if (outputStream & EStdOut) + fprintf(stdout, "%c", c); +} + +void TInfoSinkBase::append(const TPersistString& t) +{ + if (outputStream & EString) { + checkMem(t.size()); + sink.append(t); + } + +#ifdef _WIN32 + if (outputStream & EDebugger) + OutputDebugString(t.c_str()); +#endif + + if (outputStream & EStdOut) + fprintf(stdout, "%s", t.c_str()); +} + +void TInfoSinkBase::append(const TString& t) +{ + if (outputStream & EString) { + checkMem(t.size()); + sink.append(t.c_str()); + } + +#ifdef _WIN32 + if (outputStream & EDebugger) + OutputDebugString(t.c_str()); +#endif + + if (outputStream & EStdOut) + fprintf(stdout, "%s", t.c_str()); +} diff --git a/glslang/MachineIndependent/Initialize.cpp b/glslang/MachineIndependent/Initialize.cpp new file mode 100644 index 00000000..3bb8a0cf --- /dev/null +++ b/glslang/MachineIndependent/Initialize.cpp @@ -0,0 +1,962 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +// +// 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 "../Include/intermediate.h" +#include "Initialize.h" + +void TBuiltIns::initialize() +{ + // + // Initialize all the built-in strings for parsing. + // + TString BuiltInFunctions; + TString BuiltInFunctionsVertex; + TString BuiltInFunctionsFragment; + TString StandardVertexVaryings; + TString StandardFragmentVaryings; + TString StandardVertexAttributes; + TString StandardUniforms; + + { + //============================================================================ + // + // Prototypes for built-in functions seen by both vertex and fragment shaders. + // + //============================================================================ + + TString& s = BuiltInFunctions; + + // + // 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 texture1D(sampler1D sampler, float coord);")); + s.append(TString("vec4 texture1DProj(sampler1D sampler, vec2 coord);")); + s.append(TString("vec4 texture1DProj(sampler1D sampler, vec4 coord);")); + + 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 texture3D(sampler3D sampler, vec3 coord);")); + s.append(TString("vec4 texture3DProj(sampler3D sampler, vec4 coord);")); + + s.append(TString("vec4 textureCube(samplerCube sampler, vec3 coord);")); + + s.append(TString("vec4 shadow1D(sampler1DShadow sampler, vec3 coord);")); + + s.append(TString("vec4 shadow2D(sampler2DShadow sampler, vec3 coord);")); + + s.append(TString("vec4 shadow1DProj(sampler1DShadow sampler, vec4 coord);")); + + s.append(TString("vec4 shadow2DProj(sampler2DShadow sampler, vec4 coord);")); + + // ARB_texture_rectangle + s.append(TString("vec4 texture2DRect(sampler2DRect sampler, vec2 coord);")); + s.append(TString("vec4 texture2DRectProj(sampler2DRect sampler, vec3 coord);")); + s.append(TString("vec4 texture2DRectProj(sampler2DRect sampler, vec4 coord);")); + s.append(TString("vec4 shadow2DRect(sampler2DRectShadow sampler, vec3 coord);")); + s.append(TString("vec4 shadow2DRectProj(sampler2DRectShadow sampler, vec4 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);")); + + s.append(TString("\n")); + } + { + //============================================================================ + // + // Prototypes for built-in functions seen by vertex shaders only. + // + //============================================================================ + + TString& s = BuiltInFunctionsVertex; + + // + // Geometric Functions. + // + s.append(TString("vec4 ftransform();")); + + // + // Texture Functions. + // + s.append(TString("vec4 texture1DLod(sampler1D sampler, float coord, float lod);")); + s.append(TString("vec4 texture1DProjLod(sampler1D sampler, vec2 coord, float lod);")); + s.append(TString("vec4 texture1DProjLod(sampler1D sampler, vec4 coord, float lod);")); + + 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 texture3DLod(sampler3D sampler, vec3 coord, float lod);")); + s.append(TString("vec4 texture3DProjLod(sampler3D sampler, vec4 coord, float lod);")); + s.append(TString("vec4 textureCubeLod(samplerCube sampler, vec3 coord, float lod);")); + + s.append(TString("vec4 shadow1DLod(sampler1DShadow sampler, vec3 coord, float lod);")); + s.append(TString("vec4 shadow2DLod(sampler2DShadow sampler, vec3 coord, float lod);")); + s.append(TString("vec4 shadow1DProjLod(sampler1DShadow sampler, vec4 coord, float lod);")); + s.append(TString("vec4 shadow2DProjLod(sampler2DShadow sampler, vec4 coord, float lod);")); + + s.append(TString("\n")); + } + { + //============================================================================ + // + // Prototypes for built-in functions seen by fragment shaders only. + // + //============================================================================ + + TString& s = BuiltInFunctionsFragment; + + // + // Texture Functions. + // + s.append(TString("vec4 texture1D(sampler1D sampler, float coord, float bias);")); + s.append(TString("vec4 texture1DProj(sampler1D sampler, vec2 coord, float bias);")); + s.append(TString("vec4 texture1DProj(sampler1D sampler, vec4 coord, float bias);")); + + 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 texture3D(sampler3D sampler, vec3 coord, float bias);")); + s.append(TString("vec4 texture3DProj(sampler3D sampler, vec4 coord, float bias);")); + s.append(TString("vec4 textureCube(samplerCube sampler, vec3 coord, float bias);")); + + s.append(TString("vec4 shadow1D(sampler1DShadow sampler, vec3 coord, float bias);")); + s.append(TString("vec4 shadow2D(sampler2DShadow sampler, vec3 coord, float bias);")); + s.append(TString("vec4 shadow1DProj(sampler1DShadow sampler, vec4 coord, float bias);")); + s.append(TString("vec4 shadow2DProj(sampler2DShadow sampler, vec4 coord, float bias);")); + + 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);")); + + s.append(TString("\n")); + } + { + //============================================================================ + // + // Standard Uniforms + // + //============================================================================ + + TString& s = StandardUniforms; + + + // + // OpenGL'uniform' state. Page numbers are in reference to version + // 1.4 of the OpenGL specification. + // + + // + // Matrix state. p. 31, 32, 37, 39, 40. + // + s.append(TString("uniform mat4 gl_ModelViewMatrix;")); + s.append(TString("uniform mat4 gl_ProjectionMatrix;")); + s.append(TString("uniform mat4 gl_ModelViewProjectionMatrix;")); + + // + // Derived matrix state that provides inverse and transposed versions + // of the matrices above. + // + s.append(TString("uniform mat3 gl_NormalMatrix;")); + + s.append(TString("uniform mat4 gl_ModelViewMatrixInverse;")); + s.append(TString("uniform mat4 gl_ProjectionMatrixInverse;")); + s.append(TString("uniform mat4 gl_ModelViewProjectionMatrixInverse;")); + + s.append(TString("uniform mat4 gl_ModelViewMatrixTranspose;")); + s.append(TString("uniform mat4 gl_ProjectionMatrixTranspose;")); + s.append(TString("uniform mat4 gl_ModelViewProjectionMatrixTranspose;")); + + s.append(TString("uniform mat4 gl_ModelViewMatrixInverseTranspose;")); + s.append(TString("uniform mat4 gl_ProjectionMatrixInverseTranspose;")); + s.append(TString("uniform mat4 gl_ModelViewProjectionMatrixInverseTranspose;")); + + // + // Normal scaling p. 39. + // + s.append(TString("uniform float gl_NormalScale;")); + + // + // Depth range in window coordinates, p. 33 + // + s.append(TString("struct gl_DepthRangeParameters {")); + s.append(TString(" float near;")); // n + s.append(TString(" float far;")); // f + s.append(TString(" float diff;")); // f - n + s.append(TString("};")); + s.append(TString("uniform gl_DepthRangeParameters gl_DepthRange;")); + + + // + // Point Size, p. 66, 67. + // + s.append(TString("struct gl_PointParameters {")); + s.append(TString(" float size;")); + s.append(TString(" float sizeMin;")); + s.append(TString(" float sizeMax;")); + s.append(TString(" float fadeThresholdSize;")); + s.append(TString(" float distanceConstantAttenuation;")); + s.append(TString(" float distanceLinearAttenuation;")); + s.append(TString(" float distanceQuadraticAttenuation;")); + s.append(TString("};")); + + s.append(TString("uniform gl_PointParameters gl_Point;")); + + // + // Material State p. 50, 55. + // + s.append(TString("struct gl_MaterialParameters {")); + s.append(TString(" vec4 emission;")); // Ecm + s.append(TString(" vec4 ambient;")); // Acm + s.append(TString(" vec4 diffuse;")); // Dcm + s.append(TString(" vec4 specular;")); // Scm + s.append(TString(" float shininess;")); // Srm + s.append(TString("};")); + s.append(TString("uniform gl_MaterialParameters gl_FrontMaterial;")); + s.append(TString("uniform gl_MaterialParameters gl_BackMaterial;")); + + // + // Light State p 50, 53, 55. + // + + s.append(TString("struct gl_LightSourceParameters {")); + s.append(TString(" vec4 ambient;")); // Acli + s.append(TString(" vec4 diffuse;")); // Dcli + s.append(TString(" vec4 specular;")); // Scli + s.append(TString(" vec4 position;")); // Ppli + s.append(TString(" vec4 halfVector;")); // Derived: Hi + s.append(TString(" vec3 spotDirection;")); // Sdli + s.append(TString(" float spotExponent;")); // Srli + s.append(TString(" float spotCutoff;")); // Crli + // (range: [0.0,90.0], 180.0) + s.append(TString(" float spotCosCutoff;")); // Derived: cos(Crli) + // (range: [1.0,0.0],-1.0) + s.append(TString(" float constantAttenuation;")); // K0 + s.append(TString(" float linearAttenuation;")); // K1 + s.append(TString(" float quadraticAttenuation;"));// K2 + s.append(TString("};")); + + + s.append(TString("struct gl_LightModelParameters {")); + s.append(TString(" vec4 ambient;")); // Acs + s.append(TString("};")); + + s.append(TString("uniform gl_LightModelParameters gl_LightModel;")); + + // + // Derived state from products of light and material. + // + + s.append(TString("struct gl_LightModelProducts {")); + s.append(TString(" vec4 sceneColor;")); // Derived. Ecm + Acm * Acs + s.append(TString("};")); + + s.append(TString("uniform gl_LightModelProducts gl_FrontLightModelProduct;")); + s.append(TString("uniform gl_LightModelProducts gl_BackLightModelProduct;")); + + s.append(TString("struct gl_LightProducts {")); + s.append(TString(" vec4 ambient;")); // Acm * Acli + s.append(TString(" vec4 diffuse;")); // Dcm * Dcli + s.append(TString(" vec4 specular;")); // Scm * Scli + s.append(TString("};")); + + + + + // + // Fog p. 161 + // + s.append(TString("struct gl_FogParameters {")); + s.append(TString(" vec4 color;")); + s.append(TString(" float density;")); + s.append(TString(" float start;")); + s.append(TString(" float end;")); + s.append(TString(" float scale;")); // 1 / (gl_FogEnd - gl_FogStart) + s.append(TString("};")); + + s.append(TString("uniform gl_FogParameters gl_Fog;")); + + s.append(TString("\n")); + } + { + //============================================================================ + // + // Vertex attributes, p. 19. + // + //============================================================================ + + TString& s = StandardVertexAttributes; + + s.append(TString("attribute vec4 gl_Color;")); + s.append(TString("attribute vec4 gl_SecondaryColor;")); + s.append(TString("attribute vec3 gl_Normal;")); + s.append(TString("attribute vec4 gl_Vertex;")); + s.append(TString("attribute vec4 gl_MultiTexCoord0;")); + s.append(TString("attribute vec4 gl_MultiTexCoord1;")); + s.append(TString("attribute vec4 gl_MultiTexCoord2;")); + s.append(TString("attribute vec4 gl_MultiTexCoord3;")); + s.append(TString("attribute vec4 gl_MultiTexCoord4;")); + s.append(TString("attribute vec4 gl_MultiTexCoord5;")); + s.append(TString("attribute vec4 gl_MultiTexCoord6;")); + s.append(TString("attribute vec4 gl_MultiTexCoord7;")); + s.append(TString("attribute float gl_FogCoord;")); + + s.append(TString("\n")); + } + { + //============================================================================ + // + // Define the output varying interface from the vertex shader. + // + //============================================================================ + + TString& s = StandardVertexVaryings; + + s.append(TString("varying vec4 gl_FrontColor;")); + s.append(TString("varying vec4 gl_BackColor;")); + s.append(TString("varying vec4 gl_FrontSecondaryColor;")); + s.append(TString("varying vec4 gl_BackSecondaryColor;")); + s.append(TString("varying vec4 gl_TexCoord[];")); + s.append(TString("varying float gl_FogFragCoord;")); + + s.append(TString("\n")); + } + { + //============================================================================ + // + // Define the input varying interface to the fragment shader. + // + //============================================================================ + + TString& s = StandardFragmentVaryings; + + s.append(TString("varying vec4 gl_Color;")); + s.append(TString("varying vec4 gl_SecondaryColor;")); + s.append(TString("varying vec4 gl_TexCoord[];")); + s.append(TString("varying float gl_FogFragCoord;")); + + s.append(TString("\n")); + } + + builtInStrings[EShLangFragment].push_back(BuiltInFunctions.c_str()); + builtInStrings[EShLangFragment].push_back(BuiltInFunctionsFragment); + builtInStrings[EShLangFragment].push_back(StandardUniforms); + builtInStrings[EShLangFragment].push_back(StandardFragmentVaryings); + + builtInStrings[EShLangVertex].push_back(BuiltInFunctions); + builtInStrings[EShLangVertex].push_back(BuiltInFunctionsVertex); + builtInStrings[EShLangVertex].push_back(StandardVertexVaryings); + builtInStrings[EShLangVertex].push_back(StandardVertexAttributes); + builtInStrings[EShLangVertex].push_back(StandardUniforms); +} + + +void TBuiltIns::initialize(const TBuiltInResource &resources) +{ + // + // Initialize all the built-in strings for parsing. + // + TString StandardUniforms; + + { + //============================================================================ + // + // Standard Uniforms + // + //============================================================================ + + TString& s = StandardUniforms; + + // + // Implementation dependent constants. The example values below + // are the minimum values allowed for these maximums. + // + char builtInConstant[80]; + sprintf(builtInConstant, "const int gl_MaxLights = %d;", resources.maxLights); // GL 1.0 + s.append(TString(builtInConstant)); + + sprintf(builtInConstant, "const int gl_MaxClipPlanes = %d;", resources.maxClipPlanes); // GL 1.0 + s.append(TString(builtInConstant)); + + sprintf(builtInConstant, "const int gl_MaxTextureUnits = %d;", resources.maxTextureUnits); // GL 1.2 + s.append(TString(builtInConstant)); + + sprintf(builtInConstant, "const int gl_MaxTextureCoords = %d;", resources.maxTextureCoords); // ARB_fragment_program + s.append(TString(builtInConstant)); + + sprintf(builtInConstant, "const int gl_MaxVertexAttribs = %d;", resources.maxVertexAttribs); // ARB_vertex_shader + s.append(TString(builtInConstant)); + + sprintf(builtInConstant, "const int gl_MaxVertexUniformComponents = %d;", resources.maxVertexUniformComponents); // ARB_vertex_shader + s.append(TString(builtInConstant)); + + sprintf(builtInConstant, "const int gl_MaxVaryingFloats = %d;", resources.maxVaryingFloats); // ARB_vertex_shader + s.append(TString(builtInConstant)); + + sprintf(builtInConstant, "const int gl_MaxVertexTextureImageUnits = %d;", resources.maxVertexTextureImageUnits); // ARB_vertex_shader + s.append(TString(builtInConstant)); + + sprintf(builtInConstant, "const int gl_MaxCombinedTextureImageUnits = %d;", resources.maxCombinedTextureImageUnits); // ARB_vertex_shader + s.append(TString(builtInConstant)); + + sprintf(builtInConstant, "const int gl_MaxTextureImageUnits = %d;", resources.maxTextureImageUnits); // ARB_fragment_shader + s.append(TString(builtInConstant)); + + sprintf(builtInConstant, "const int gl_MaxFragmentUniformComponents = %d;", resources.maxFragmentUniformComponents); // ARB_fragment_shader + s.append(TString(builtInConstant)); + + sprintf(builtInConstant, "const int gl_MaxDrawBuffers = %d;", resources.maxDrawBuffers); // proposed ARB_draw_buffers + s.append(TString(builtInConstant)); + + // + // OpenGL'uniform' state. Page numbers are in reference to version + // 1.4 of the OpenGL specification. + // + + // + // Matrix state. p. 31, 32, 37, 39, 40. + // + s.append(TString("uniform mat4 gl_TextureMatrix[gl_MaxTextureCoords];")); + + // + // Derived matrix state that provides inverse and transposed versions + // of the matrices above. + // + s.append(TString("uniform mat4 gl_TextureMatrixInverse[gl_MaxTextureCoords];")); + + s.append(TString("uniform mat4 gl_TextureMatrixTranspose[gl_MaxTextureCoords];")); + + s.append(TString("uniform mat4 gl_TextureMatrixInverseTranspose[gl_MaxTextureCoords];")); + + // + // Clip planes p. 42. + // + s.append(TString("uniform vec4 gl_ClipPlane[gl_MaxClipPlanes];")); + + // + // Light State p 50, 53, 55. + // + s.append(TString("uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights];")); + + // + // Derived state from products of light. + // + s.append(TString("uniform gl_LightProducts gl_FrontLightProduct[gl_MaxLights];")); + s.append(TString("uniform gl_LightProducts gl_BackLightProduct[gl_MaxLights];")); + + // + // Textureg Environment and Generation, p. 152, p. 40-42. + // + s.append(TString("uniform vec4 gl_TextureEnvColor[gl_MaxTextureImageUnits];")); + s.append(TString("uniform vec4 gl_EyePlaneS[gl_MaxTextureCoords];")); + s.append(TString("uniform vec4 gl_EyePlaneT[gl_MaxTextureCoords];")); + s.append(TString("uniform vec4 gl_EyePlaneR[gl_MaxTextureCoords];")); + s.append(TString("uniform vec4 gl_EyePlaneQ[gl_MaxTextureCoords];")); + s.append(TString("uniform vec4 gl_ObjectPlaneS[gl_MaxTextureCoords];")); + s.append(TString("uniform vec4 gl_ObjectPlaneT[gl_MaxTextureCoords];")); + s.append(TString("uniform vec4 gl_ObjectPlaneR[gl_MaxTextureCoords];")); + s.append(TString("uniform vec4 gl_ObjectPlaneQ[gl_MaxTextureCoords];")); + + s.append(TString("\n")); + } + + builtInStrings[EShLangFragment].push_back(StandardUniforms); + builtInStrings[EShLangVertex].push_back(StandardUniforms); +} + +void IdentifyBuiltIns(EShLanguage language, TSymbolTable& symbolTable) +{ + // + // First, insert some special built-in variables that are not in + // the built-in header files. + // + switch(language) { + + case EShLangFragment: { + symbolTable.insert(*new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool, EvqFace, 1))); + symbolTable.insert(*new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EvqFragCoord, 4))); + symbolTable.insert(*new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EvqFragColor, 4))); + symbolTable.insert(*new TVariable(NewPoolTString("gl_FragDepth"), TType(EbtFloat, EvqFragDepth, 1))); + + } + break; + + case EShLangVertex: + symbolTable.insert(*new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EvqPosition, 4))); + symbolTable.insert(*new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EvqPointSize, 1))); + symbolTable.insert(*new TVariable(NewPoolTString("gl_ClipVertex"), TType(EbtFloat, EvqClipVertex, 4))); + break; + default: break; + } + + // + // 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("mod", EOpMod); + + 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("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("forward", EOpFaceForward); + symbolTable.relateToOperator("reflect", EOpReflect); + symbolTable.relateToOperator("refract", EOpRefract); + + symbolTable.relateToOperator("any", EOpAny); + symbolTable.relateToOperator("all", EOpAll); + + switch(language) { + + case EShLangVertex: + break; + + case EShLangFragment: + symbolTable.relateToOperator("dFdx", EOpDPdx); + symbolTable.relateToOperator("dFdy", EOpDPdy); + symbolTable.relateToOperator("fwidth", EOpFwidth); + + break; + + case EShLangPack: + case EShLangUnpack: + symbolTable.relateToOperator("itof", EOpItof); + symbolTable.relateToOperator("ftoi", EOpFtoi); + symbolTable.relateToOperator("skipPixels", EOpSkipPixels); + symbolTable.relateToOperator("readInput", EOpReadInput); + symbolTable.relateToOperator("writePixel", EOpWritePixel); + symbolTable.relateToOperator("bitmapLSB", EOpBitmapLsb); + symbolTable.relateToOperator("bitmapMSB", EOpBitmapMsb); + symbolTable.relateToOperator("writeOutput", EOpWriteOutput); + symbolTable.relateToOperator("readPixel", EOpReadPixel); + break; + default: assert(false && "Language not supported"); + } +} + +void IdentifyBuiltIns(EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources) +{ + // + // First, insert some special built-in variables that are not in + // the built-in header files. + // + switch(language) { + + case EShLangFragment: { + // Set up gl_FragData. The array size. + TType fragData(EbtFloat, EvqFragColor, 4, false, true); + fragData.setArraySize(resources.maxDrawBuffers); + symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"), fragData)); + } + break; + + default: break; + } +} + +char* GetPreprocessorBuiltinString() +{ + static char *PreprocessorBuiltinString = "#define GL_ARB_texture_rectangle 1\n" + "#define GL_3DL_array_objects 1\n"; + + return PreprocessorBuiltinString; +} diff --git a/glslang/MachineIndependent/Initialize.h b/glslang/MachineIndependent/Initialize.h new file mode 100644 index 00000000..b4f4a03d --- /dev/null +++ b/glslang/MachineIndependent/Initialize.h @@ -0,0 +1,63 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef _INITIALIZE_INCLUDED_ +#define _INITIALIZE_INCLUDED_ + +#include "Include/ResourceLimits.h" +#include "../Include/Common.h" +#include "../Include/ShHandle.h" +#include "SymbolTable.h" + +typedef TVector TBuiltInStrings; + +class TBuiltIns { +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + void initialize(); + void initialize(const TBuiltInResource& resources); + TBuiltInStrings* getBuiltInStrings() { return builtInStrings; } +protected: + TBuiltInStrings builtInStrings[EShLangCount]; +}; + +void IdentifyBuiltIns(EShLanguage, TSymbolTable&); +void IdentifyBuiltIns(EShLanguage, TSymbolTable&, const TBuiltInResource &resources); +bool GenerateBuiltInSymbolTable(const TBuiltInResource* resources, TInfoSink&, TSymbolTable*, EShLanguage language = EShLangCount); +bool InitializeSymbolTable(TBuiltInStrings* BuiltInStrings, EShLanguage language, TInfoSink& infoSink, const TBuiltInResource *resources, TSymbolTable*); +char* GetPreprocessorBuiltinString(); +extern "C" int InitPreprocessor(void); +extern "C" int FinalizePreprocessor(void); + +#endif // _INITIALIZE_INCLUDED_ diff --git a/glslang/MachineIndependent/IntermTraverse.cpp b/glslang/MachineIndependent/IntermTraverse.cpp new file mode 100644 index 00000000..8b379dbe --- /dev/null +++ b/glslang/MachineIndependent/IntermTraverse.cpp @@ -0,0 +1,243 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#include "../Include/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) +{ + if (it->visitSymbol) + it->visitSymbol(this, it); +} + +void TIntermConstantUnion::traverse(TIntermTraverser* it) +{ + if (it->visitConstantUnion) + it->visitConstantUnion(this, it); +} + +// +// Traverse a binary node. +// +void TIntermBinary::traverse(TIntermTraverser* it) +{ + bool visit = true; + + // + // visit the node before children if pre-visiting. + // + if (it->preVisit && it->visitBinary) + visit = it->visitBinary(true, this, it); + + // + // Visit the children, in the right order. + // + if (visit) { + ++it->depth; + if (it->rightToLeft) { + if (right) + right->traverse(it); + if (left) + left->traverse(it); + } else { + if (left) + left->traverse(it); + if (right) + right->traverse(it); + } + --it->depth; + } + + // + // Visit the node after the children, if requested and the traversal + // hasn't been cancelled yet. + // + if (visit && it->postVisit && it->visitBinary) + it->visitBinary(false, this, it); +} + +// +// Traverse a unary node. Same comments in binary node apply here. +// +void TIntermUnary::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if (it->preVisit && it->visitUnary) + visit = it->visitUnary(true, this, it); + + if (visit) { + ++it->depth; + operand->traverse(it); + --it->depth; + } + + if (visit && it->postVisit && it->visitUnary) + it->visitUnary(false, this, it); +} + +// +// Traverse an aggregate node. Same comments in binary node apply here. +// +void TIntermAggregate::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if (it->preVisit && it->visitAggregate) + visit = it->visitAggregate(true, this, it); + + if (visit) { + ++it->depth; + + TIntermSequence::iterator sit; + if (it->rightToLeft) { + sit = sequence.end(); + while (sit != sequence.begin()) { + --sit; + (*sit)->traverse(it); + } + } else { + for (sit = sequence.begin(); sit != sequence.end(); ++sit) + (*sit)->traverse(it); + } + + --it->depth; + } + + if (visit && it->postVisit && it->visitAggregate) + it->visitAggregate(false, this, it); +} + +// +// Traverse a selection node. Same comments in binary node apply here. +// +void TIntermSelection::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if (it->preVisit && it->visitSelection) + visit = it->visitSelection(true, this, it); + + if (visit) { + ++it->depth; + 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->depth; + } + + if (visit && it->postVisit && it->visitSelection) + it->visitSelection(false, this, it); +} + +// +// Traverse a loop node. Same comments in binary node apply here. +// +void TIntermLoop::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if (it->preVisit && it->visitLoop) + visit = it->visitLoop(true, this, it); + + if (visit) { + ++it->depth; + if (it->rightToLeft) { + if (terminal) + terminal->traverse(it); + if (body) + body->traverse(it); + if (test) + test->traverse(it); + } else { + if (test) + test->traverse(it); + if (body) + body->traverse(it); + if (terminal) + terminal->traverse(it); + } + --it->depth; + } + + if (visit && it->postVisit && it->visitLoop) + it->visitLoop(false, this, it); +} + +// +// Traverse a branch node. Same comments in binary node apply here. +// +void TIntermBranch::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if (it->preVisit && it->visitBranch) + visit = it->visitBranch(true, this, it); + + if (visit && expression) { + ++it->depth; + expression->traverse(it); + --it->depth; + } + + if (visit && it->postVisit && it->visitBranch) + it->visitBranch(false, this, it); +} + diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp new file mode 100644 index 00000000..96c90747 --- /dev/null +++ b/glslang/MachineIndependent/Intermediate.cpp @@ -0,0 +1,1514 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +// +// Build the intermediate representation. +// + +#include "localintermediate.h" +#include "QualifierAlive.h" +#include "RemoveTree.h" +#include + +bool CompareStructure(const TType& leftNodeType, constUnion* rightUnionArray, constUnion* leftUnionArray); + +//////////////////////////////////////////////////////////////////////////// +// +// 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 EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + if (left->getType().isMatrix() || left->getType().isArray() || left->getType().isVector() || left->getType().getBasicType() == EbtStruct) { + return 0; + } + break; + case EOpLogicalOr: + case EOpLogicalXor: + case EOpLogicalAnd: + if (left->getType().getBasicType() != EbtBool || left->getType().isMatrix() || left->getType().isArray() || left->getType().isVector()) { + return 0; + } + break; + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpMul: + if (left->getType().getBasicType() == EbtStruct || left->getType().getBasicType() == EbtBool) + return 0; + default: break; + } + + // + // First try converting the children to compatible types. + // + + if (!(left->getType().getStruct() && right->getType().getStruct())) { + 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; + } + } else { + if (left->getType() != right->getType()) + 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; + + TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion(); + TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion(); + + if (leftTempConstant) + leftTempConstant = left->getAsConstantUnion(); + + if (rightTempConstant) + rightTempConstant = right->getAsConstantUnion(); + + // + // See if we can fold constants. + // + + TIntermTyped* typedReturnNode = 0; + 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, 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. +// +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->setOperator(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 EbtSampler1D: + case EbtSampler2D: + case EbtSampler3D: + case EbtSamplerCube: + case EbtSampler1DShadow: + case EbtSampler2DShadow: + case EbtSamplerRect: // ARB_texture_rectangle + case EbtSamplerRectShadow: // ARB_texture_rectangle + 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, 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()) + return nodePair.node1; + else + return nodePair.node2; + } + + 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()->setOperator(EOpComma); + commaAggregate->setType(right->getType()); + commaAggregate->getTypePointer()->changeQualifier(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->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(constUnion* 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(); + constUnion* unionArray; + + for (int i = 0; i < fields.num; i++) { + unionArray = new constUnion[1]; + unionArray->setIConst(fields.offsets[i]); + constIntNode = addConstantUnion(unionArray, TType(EbtInt, EvqConst), line); + sequenceVector.push_back(constIntNode); + } + + return node; +} + +// +// Create loop nodes. +// +TIntermNode* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, TSourceLoc line) +{ + TIntermNode* node = new TIntermLoop(body, test, terminal, testFirst); + 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, EShLanguage language) +{ + if (root == 0) + return true; + + // + // First, finish off the top level sequence, if any + // + TIntermAggregate* aggRoot = root->getAsAggregate(); + if (aggRoot && aggRoot->getOp() == EOpNull) + aggRoot->setOperator(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: + case EOpModAssign: + case EOpAndAssign: + case EOpInclusiveOrAssign: + case EOpExclusiveOrAssign: + case EOpLeftShiftAssign: + case EOpRightShiftAssign: + 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 EOpBitwiseNot: + if (operand->getBasicType() != EbtInt) + 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()); + + 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) +{ + int size = left->getNominalSize(); + if (right->getNominalSize() > size) + size = right->getNominalSize(); + + TBasicType type = left->getBasicType(); + + // + // Arrays have to be exact matches. + // + if ((left->isArray() || right->isArray()) && (left->getType() != right->getType())) + return false; + + // + // Base assumption: just make the type the same as the left + // operand. Then only deviations from this need be coded. + // + setType(TType(type, EvqTemporary, left->getNominalSize(), left->isMatrix())); + + // + // Array operations. + // + if (left->isArray()) { + + switch (op) { + + // + // Promote to conditional + // + case EOpEqual: + case EOpNotEqual: + setType(TType(EbtBool)); + break; + + // + // Set array information. + // + case EOpAssign: + getType().setArraySize(left->getType().getArraySize()); + getType().setArrayInformationType(left->getType().getArrayInformationType()); + break; + + default: + return false; + } + + return true; + } + + // + // 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)); + break; + + // + // And and Or operate on conditionals + // + case EOpLogicalAnd: + case EOpLogicalOr: + if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool) + return false; + setType(TType(EbtBool)); + break; + + // + // Check for integer only operands. + // + case EOpMod: + case EOpRightShift: + case EOpLeftShift: + case EOpAnd: + case EOpInclusiveOr: + case EOpExclusiveOr: + if (left->getBasicType() != EbtInt || right->getBasicType() != EbtInt) + return false; + break; + case EOpModAssign: + case EOpAndAssign: + case EOpInclusiveOrAssign: + case EOpExclusiveOrAssign: + case EOpLeftShiftAssign: + case EOpRightShiftAssign: + if (left->getBasicType() != EbtInt || right->getBasicType() != EbtInt) + return false; + // fall through + + // + // Everything else should have matching types + // + default: + if (left->getBasicType() != right->getBasicType() || + left->isMatrix() != right->isMatrix()) + return false; + } + + return true; + } + + // + // Are the sizes compatible? + // + if ( left->getNominalSize() != size && left->getNominalSize() != 1 || + right->getNominalSize() != size && right->getNominalSize() != 1) + return false; + + // + // Can these two operands be combined? + // + switch (op) { + case EOpMul: + if (!left->isMatrix() && right->isMatrix()) { + if (left->isVector()) + op = EOpVectorTimesMatrix; + else { + op = EOpMatrixTimesScalar; + setType(TType(type, EvqTemporary, size, true)); + } + } else if (left->isMatrix() && !right->isMatrix()) { + if (right->isVector()) { + op = EOpMatrixTimesVector; + setType(TType(type, 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(type, 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(type, EvqTemporary, size, false)); + } + } else { + infoSink.info.message(EPrefixInternalError, "Missing elses", getLine()); + return false; + } + break; + case EOpAssign: + if (left->getNominalSize() != right->getNominalSize()) + return false; + // fall through + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpMod: + case EOpAddAssign: + case EOpSubAssign: + case EOpDivAssign: + case EOpModAssign: + if (left->isMatrix() && right->isVector() || + left->isVector() && right->isMatrix() || + left->getBasicType() != right->getBasicType()) + return false; + setType(TType(type, 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() || + left->getBasicType() != right->getBasicType()) + return false; + setType(TType(EbtBool)); + break; + +default: + return false; + } + + // + // One more check for assignment. The Resulting type has to match the left operand. + // + switch (op) { + case EOpAssign: + case EOpAddAssign: + case EOpSubAssign: + case EOpMulAssign: + case EOpDivAssign: + case EOpModAssign: + case EOpAndAssign: + case EOpInclusiveOrAssign: + case EOpExclusiveOrAssign: + case EOpLeftShiftAssign: + case EOpRightShiftAssign: + if (getType() != left->getType()) + return false; + break; + default: + break; + } + + return true; +} + +bool CompareStruct(const TType& leftNodeType, constUnion* rightUnionArray, constUnion* leftUnionArray) +{ + 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, constUnion* rightUnionArray, constUnion* 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) +{ + constUnion *unionArray = getUnionArrayPointer(); + int objectSize = getType().getObjectSize(); + + if (constantNode) { // binary operations + TIntermConstantUnion *node = constantNode->getAsConstantUnion(); + constUnion *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 constUnion[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 constUnion[constantNode->getType().getObjectSize()]; + for (int i = 0; i < constantNode->getType().getObjectSize(); ++i) + unionArray[i] = *getUnionArrayPointer(); + returnType = node->getType(); + objectSize = constantNode->getType().getObjectSize(); + } + + constUnion* tempConstArray = 0; + TIntermConstantUnion *tempNode; + int index = 0; + bool boolNodeFlag = false; + switch(op) { + case EOpAdd: + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] + rightUnionArray[i]; + } + break; + case EOpSub: + tempConstArray = new constUnion[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 constUnion[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 constUnion[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 constUnion[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 constUnion[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 constUnion[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 EOpMod: + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] % rightUnionArray[i]; + } + break; + + case EOpRightShift: + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] >> rightUnionArray[i]; + } + break; + + case EOpLeftShift: + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] << rightUnionArray[i]; + } + break; + + case EOpAnd: + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] & rightUnionArray[i]; + } + break; + case EOpInclusiveOr: + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] | rightUnionArray[i]; + } + break; + case EOpExclusiveOr: + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] ^ rightUnionArray[i]; + } + break; + + case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently + tempConstArray = new constUnion[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 constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] || rightUnionArray[i]; + } + break; + + case EOpLogicalXor: + tempConstArray = new constUnion[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 constUnion[1]; + tempConstArray->setBConst(*unionArray < *rightUnionArray); + returnType = TType(EbtBool, EvqConst); + break; + case EOpGreaterThan: + assert(objectSize == 1); + tempConstArray = new constUnion[1]; + tempConstArray->setBConst(*unionArray > *rightUnionArray); + returnType = TType(EbtBool, EvqConst); + break; + case EOpLessThanEqual: + { + assert(objectSize == 1); + constUnion constant; + constant.setBConst(*unionArray > *rightUnionArray); + tempConstArray = new constUnion[1]; + tempConstArray->setBConst(!constant.getBConst()); + returnType = TType(EbtBool, EvqConst); + break; + } + case EOpGreaterThanEqual: + { + assert(objectSize == 1); + constUnion constant; + constant.setBConst(*unionArray < *rightUnionArray); + tempConstArray = new constUnion[1]; + tempConstArray->setBConst(!constant.getBConst()); + returnType = TType(EbtBool, 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 constUnion[1]; + if (!boolNodeFlag) { + tempConstArray->setBConst(true); + } + else { + tempConstArray->setBConst(false); + } + + tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, 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 constUnion[1]; + if (!boolNodeFlag) { + tempConstArray->setBConst(true); + } + else { + tempConstArray->setBConst(false); + } + + tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, 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; + constUnion* tempConstArray = new constUnion[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; + } + + return this; +} + +TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) +{ + constUnion *rightUnionArray = node->getUnionArrayPointer(); + int size = node->getType().getObjectSize(); + + constUnion *leftUnionArray = new constUnion[size]; + + for (int i=0; i < size; i++) { + + switch (promoteTo) { + case EbtFloat: + switch (node->getType().getBasicType()) { + case EbtInt: + leftUnionArray[i].setFConst(static_cast(rightUnionArray[i].getIConst())); + break; + case EbtBool: + leftUnionArray[i].setFConst(static_cast(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(rightUnionArray[i].getBConst())); + break; + case EbtFloat: + leftUnionArray[i].setIConst(static_cast(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.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine()); +} + +void TIntermAggregate::addToPragmaTable(const TPragmaTable& pTable) +{ + assert(!pragmaTable); + pragmaTable = new TPragmaTable(); + *pragmaTable = pTable; +} + diff --git a/glslang/MachineIndependent/MMap.h b/glslang/MachineIndependent/MMap.h new file mode 100644 index 00000000..82254f03 --- /dev/null +++ b/glslang/MachineIndependent/MMap.h @@ -0,0 +1,84 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#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/glslang/MachineIndependent/Makefile b/glslang/MachineIndependent/Makefile new file mode 100644 index 00000000..9704c803 --- /dev/null +++ b/glslang/MachineIndependent/Makefile @@ -0,0 +1,161 @@ +INCLUDE = -I. -I.. -I../.. -I../Include -I../Public -I../OSDependent/Linux -I../../OGLCompilersDLL +CC=g++ +INCPREPROCESSOR=./preprocessor +INCCODEGEN=./../GenericCodeGen +INCOSDEPENDENT=./../OSDependent/Linux/ +INCINITIALISATION=./../../OGLCompilersDLL/ +LIBPREPROCESSOR=./preprocessor/libPreprocessor.a +LIBOSDEPENDENT=./../OSDependent/Linux/libOssource.a +LIBINITIALISATION=./../../OGLCompilersDLL/libInitializeDll.a +LIBCODEGEN=./../GenericCodeGen/libCodeGen.a +OBJECTS= Initialize.o IntermTraverse.o \ + Intermediate.o ParseHelper.o PoolAlloc.o QualifierAlive.o \ + RemoveTree.o ShaderLang.o intermOut.o parseConst.o SymbolTable.o \ + InfoSink.o + +SRCS= Gen_glslang.cpp Gen_glslang_tab.cpp Initialize.cpp IntermTraverse.cpp \ + Intermediate.cpp ParseHelper.cpp PoolAlloc.cp QualifierAlive.cpp \ + RemoveTree.cpp ShaderLang.cpp SymbolTable.cpp intermOut.cpp \ + parseConst.cpp InfoSink.cpp +CPPFLAGS=$(DEFINE) $(INCLUDE) +SHAREDOBJECT=./lib/libglslang.so + +default: all + +all: $(SHAREDOBJECT) + +$(SHAREDOBJECT): Gen_glslang.o Gen_glslang_tab.o $(OBJECTS) \ + $(LIBPREPROCESSOR) $(LIBCODEGEN) $(LIBOSDEPENDENT) $(LIBINITIALISATION) + $(CC) -fPIC -shared -lc -o $@ $(OBJECTS) $(LIBPREPROCESSOR) $(LIBCODEGEN) $(LIBOSDEPENDENT) $(LIBINITIALISATION) Gen_glslang.o Gen_glslang_tab.o + +Gen_glslang.o : Gen_glslang.cpp glslang_tab.h + $(CC) -c $(INCLUDE) Gen_glslang.cpp -o $@ + +Gen_glslang_tab.o : Gen_glslang_tab.cpp + $(CC) -c $(INCLUDE) Gen_glslang_tab.cpp -o $@ + +Gen_glslang.cpp: glslang.l + @echo Generating Gen_glslang.cpp + @dos2unix glslang.l + flex glslang.l + +Gen_glslang_tab.cpp glslang_tab.h: glslang.y + @echo Generating Gen_glslang_tab.cpp + @dos2unix glslang.y + bison -t -v -d glslang.y + mv glslang.tab.c Gen_glslang_tab.cpp + mv glslang.tab.h glslang_tab.h + +%.o : %.cpp + $(CC) $(CPPFLAGS) -c $< + +$(LIBPREPROCESSOR): + cd $(INCPREPROCESSOR); make + +$(LIBCODEGEN): + cd $(INCCODEGEN); make + +$(LIBINITIALISATION): + cd $(INCINITIALISATION); make + +$(LIBOSDEPENDENT): + cd $(INCOSDEPENDENT); make + +depend: + cd $(INCPREPROCESSOR); make depend + cd $(INCCODEGEN); make depend + cd $(INCINITIALISATION); make depend + cd $(INCOSDEPENDENT); make depend + makedepend -Y -- $(CPPFLAGS) -- $(SRCS) +# +# Cleanup +# +.PHONY : clean +clean : + $(RM) *.o *.a Gen_glslang_tab.cpp Gen_glslang.cpp glslang_tab.h glslang.output + $(RM) ./lib/*.so + cd $(INCPREPROCESSOR); make clean + cd $(INCCODEGEN); make clean + cd $(INCINITIALISATION); make clean + cd $(INCOSDEPENDENT); make clean + +# DO NOT DELETE + +Gen_glslang.o: ParseHelper.h ../Include/ShHandle.h +Gen_glslang.o: ../Public/ShaderLang.h ../Include/InfoSink.h +Gen_glslang.o: ../Include/Common.h ../Include/PoolAlloc.h SymbolTable.h +Gen_glslang.o: ../Include/Common.h ../Include/intermediate.h +Gen_glslang.o: ../Include/Types.h ../Include/BaseTypes.h +Gen_glslang.o: ../Include/ConstantUnion.h ../Include/InfoSink.h +Gen_glslang.o: localintermediate.h ../Include/intermediate.h +Gen_glslang.o: ../Public/ShaderLang.h glslang_tab.h ./unistd.h +Gen_glslang.o: ./preprocessor/preprocess.h ./preprocessor/slglobals.h +Gen_glslang.o: ./preprocessor/memory.h ./preprocessor/atom.h +Gen_glslang.o: ./preprocessor/scanner.h ./preprocessor/parser.h +Gen_glslang.o: ./preprocessor/cpp.h ./preprocessor/tokens.h +Gen_glslang.o: ./preprocessor/symbols.h ./preprocessor/compile.h +Gen_glslang_tab.o: SymbolTable.h ../Include/Common.h +Gen_glslang_tab.o: ../Include/intermediate.h ../Include/Common.h +Gen_glslang_tab.o: ../Include/PoolAlloc.h ../Include/Types.h +Gen_glslang_tab.o: ../Include/BaseTypes.h ../Include/ConstantUnion.h +Gen_glslang_tab.o: ../Include/InfoSink.h ParseHelper.h ../Include/ShHandle.h +Gen_glslang_tab.o: ../Public/ShaderLang.h +Gen_glslang_tab.o: ../Include/InfoSink.h localintermediate.h +Gen_glslang_tab.o: ../Include/intermediate.h ../Public/ShaderLang.h +Initialize.o: ../Include/intermediate.h Initialize.h +Initialize.o: ../Include/ResourceLimits.h ../Include/Common.h +Initialize.o: ../Include/PoolAlloc.h ../Include/ShHandle.h +Initialize.o: ../Public/ShaderLang.h +Initialize.o: ../Include/InfoSink.h SymbolTable.h ../Include/Common.h +Initialize.o: ../Include/intermediate.h ../Include/Types.h +Initialize.o: ../Include/BaseTypes.h ../Include/ConstantUnion.h +Initialize.o: ../Include/InfoSink.h +IntermTraverse.o: ../Include/intermediate.h +Intermediate.o: ../Include/ShHandle.h +Intermediate.o: ../Public/ShaderLang.h ../Include/InfoSink.h +Intermediate.o: ../Include/Common.h ../Include/PoolAlloc.h +Intermediate.o: localintermediate.h ../Include/intermediate.h +Intermediate.o: ../Public/ShaderLang.h SymbolTable.h ../Include/Common.h +Intermediate.o: ../Include/intermediate.h ../Include/Types.h +Intermediate.o: ../Include/BaseTypes.h ../Include/ConstantUnion.h +Intermediate.o: ../Include/InfoSink.h QualifierAlive.h RemoveTree.h +ParseHelper.o: ParseHelper.h ../Include/ShHandle.h +ParseHelper.o: ../Public/ShaderLang.h ../Include/InfoSink.h +ParseHelper.o: ../Include/Common.h ../Include/PoolAlloc.h SymbolTable.h +ParseHelper.o: ../Include/Common.h ../Include/intermediate.h +ParseHelper.o: ../Include/Types.h ../Include/BaseTypes.h +ParseHelper.o: ../Include/ConstantUnion.h ../Include/InfoSink.h +ParseHelper.o: localintermediate.h ../Include/intermediate.h +ParseHelper.o: ../Public/ShaderLang.h ../Include/InitializeParseContext.h +ParseHelper.o: ../OSDependent/Linux/osinclude.h +ParseHelper.o: ../Include/InitializeGlobals.h ../Include/PoolAlloc.h +QualifierAlive.o: ../Include/intermediate.h +RemoveTree.o: ../Include/intermediate.h RemoveTree.h +ShaderLang.o: SymbolTable.h ../Include/Common.h ../Include/intermediate.h +ShaderLang.o: ../Include/Common.h ../Include/PoolAlloc.h ../Include/Types.h +ShaderLang.o: ../Include/BaseTypes.h ../Include/ConstantUnion.h +ShaderLang.o: ../Include/InfoSink.h ParseHelper.h ../Include/ShHandle.h +ShaderLang.o: ../Public/ShaderLang.h +ShaderLang.o: ../Include/InfoSink.h localintermediate.h +ShaderLang.o: ../Include/intermediate.h ../Public/ShaderLang.h +ShaderLang.o: ../Include/ResourceLimits.h Initialize.h +SymbolTable.o: SymbolTable.h ../Include/Common.h ../Include/intermediate.h +SymbolTable.o: ../Include/Common.h ../Include/PoolAlloc.h ../Include/Types.h +SymbolTable.o: ../Include/BaseTypes.h ../Include/ConstantUnion.h +SymbolTable.o: ../Include/InfoSink.h +intermOut.o: localintermediate.h ../Include/intermediate.h +intermOut.o: ../Public/ShaderLang.h SymbolTable.h ../Include/Common.h +intermOut.o: ../Include/intermediate.h ../Include/Common.h +intermOut.o: ../Include/PoolAlloc.h ../Include/Types.h ../Include/BaseTypes.h +intermOut.o: ../Include/ConstantUnion.h ../Include/InfoSink.h +intermOut.o: ../Include/ShHandle.h +intermOut.o: ../Public/ShaderLang.h ../Include/InfoSink.h +parseConst.o: ParseHelper.h ../Include/ShHandle.h +parseConst.o: ../Public/ShaderLang.h ../Include/InfoSink.h +parseConst.o: ../Include/Common.h ../Include/PoolAlloc.h SymbolTable.h +parseConst.o: ../Include/Common.h ../Include/intermediate.h +parseConst.o: ../Include/Types.h ../Include/BaseTypes.h +parseConst.o: ../Include/ConstantUnion.h ../Include/InfoSink.h +parseConst.o: localintermediate.h ../Include/intermediate.h +parseConst.o: ../Public/ShaderLang.h +InfoSink.o: ../Include/InfoSink.h diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp new file mode 100644 index 00000000..6088bdf7 --- /dev/null +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -0,0 +1,1494 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#include "ParseHelper.h" +#include "Include/InitializeParseContext.h" +#include "osinclude.h" +#include +/////////////////////////////////////////////////////////////////////// +// +// 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() +{ + recoveredFromError = true; +} + +// +// Used by flex/bison to output all syntax and parsing errors. +// +void C_DECL TParseContext::error(TSourceLoc nLine, const char *szReason, const char *szToken, + const char *szExtraInfoFormat, ...) +{ + char szExtraInfo[400]; + va_list marker; + + va_start(marker, szExtraInfoFormat); + + _vsnprintf(szExtraInfo, sizeof(szExtraInfo), szExtraInfoFormat, marker); + + /* VC++ format: file(linenum) : error #: 'token' : extrainfo */ + infoSink.info.prefix(EPrefixError); + infoSink.info.location(nLine); + infoSink.info << "'" << szToken << "' : " << szReason << " " << szExtraInfo << "\n"; + + va_end(marker); + + ++numErrors; +} + +// +// Same error message for all places assignments don't work. +// +void TParseContext::assignError(int line, const char* op, TString left, TString right) +{ + error(line, "", op, "cannot convert from '%s' to '%s'", + right.c_str(), left.c_str()); +} + +// +// Same error message for all places unary operations don't work. +// +void TParseContext::unaryOpError(int line, char* op, TString operand) +{ + error(line, " wrong operand type", op, + "no operation '%s' exists that takes an operand of type %s (or there is no acceptable conversion)", + op, operand.c_str()); +} + +// +// Same error message for all binary operations don't work. +// +void TParseContext::binaryOpError(int line, char* op, TString left, TString right) +{ + error(line, " wrong operand types ", op, + "no operation '%s' exists that takes a left-hand operand of type '%s' and " + "a right operand of type '%s' (or there is no acceptable conversion)", + op, left.c_str(), right.c_str()); +} + +// +// 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, 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(); + + 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 EvqFace: message = "can't modify gl_FrontFace"; break; + case EvqFragCoord: message = "can't modify gl_FragCoord"; break; + default: + + // + // Type that can't be written to? + // + switch (node->getBasicType()) { + case EbtSampler1D: + case EbtSampler2D: + case EbtSampler3D: + case EbtSamplerCube: + case EbtSampler1DShadow: + case EbtSampler2DShadow: + case EbtSamplerRect: // ARB_texture_rectangle + case EbtSamplerRectShadow: // ARB_texture_rectangle + 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) + error(line, " l-value required", op, "\"%s\" (%s)", symbol, message); + else + error(line, " l-value required", op, "(%s)", message); + + 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, 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, 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. +// +// Returns true if there was an error. +// +bool TParseContext::reservedErrorCheck(int line, const TString& identifier) +{ + if (!symbolTable.atBuiltInLevel()) { + if (identifier.substr(0, 3) == TString("gl_")) { + error(line, "reserved built-in name", "gl_", ""); + return true; + } + if (identifier.find("__") != TString::npos) { + //error(line, "Two consecutive underscores are reserved for future use.", identifier.c_str(), "", ""); + //return true; + infoSink.info.message(EPrefixWarning, "Two consecutive underscores are reserved for future use.", line); + return false; + } + } + + 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) { + size += function[i].type->getObjectSize(); + + if (constructingMatrix && function[i].type->isMatrix()) + matrixInMatrix = true; + if (full) + overFull = true; + if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize()) + full = true; + if (function[i].type->getQualifier() != EvqConst) + constType = false; + if (function[i].type->isArray()) + arrayArg = true; + } + + if (constType) + type->changeQualifier(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()) { + error(line, "constructing matrix from matrix", "constructor", "(reserved)"); + return true; + } + + if (overFull) { + error(line, "too many arguments", "constructor", ""); + return true; + } + + if (op == EOpConstructStruct && !type->isArray() && type->getStruct()->size() != function.getParamCount()) { + error(line, "Number of constructor parameters does not match the number of structure fields", "constructor", ""); + return true; + } + + 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->getAsTyped(); + 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, TType::getBasicString(pType.type), "(structure contains a sampler)"); + + return true; + } + + return false; + } else if (IsSampler(pType.type)) { + error(line, reason, TType::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; +} + +bool TParseContext::insertBuiltInArrayAtGlobalLevel() +{ + TString *name = NewPoolTString("gl_TexCoord"); + TSymbol* symbol = symbolTable.find(*name); + if (!symbol) { + error(0, "INTERNAL ERROR finding symbol", name->c_str(), ""); + return true; + } + TVariable* variable = static_cast(symbol); + + TVariable* newVariable = new TVariable(name, variable->getType()); + + if (! symbolTable.insert(*newVariable)) { + delete newVariable; + error(0, "INTERNAL ERROR inserting new symbol", name->c_str(), ""); + 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) { + error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str(), ""); + return true; + } + + if (type.qualifier == EvqConst && extensionErrorCheck(line, "GL_3DL_array_objects")) + 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(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(symbol); + + type->setArrayInformationType(variable->getArrayInformationType()); + variable->updateArrayInformationType(type); + + // special casing to test index value of gl_TexCoord. If the accessed index is >= gl_MaxTextureCoords + // its an error + if (node->getSymbol() == "gl_TexCoord") { + TSymbol* texCoord = symbolTable.find("gl_MaxTextureCoords", &builtIn); + if (texCoord == 0) { + infoSink.info.message(EPrefixInternalError, "gl_MaxTextureCoords not defined", line); + return true; + } + + int texCoordValue = static_cast(texCoord)->getConstPointer()[0].getIConst(); + if (texCoordValue <= size) { + error(line, "", "[", "gl_TexCoord can only have a max array size of up to gl_MaxTextureCoords", ""); + 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) +{ + // + // Make the qualifier make sense. + // + if (type.qualifier == EvqConst) { + type.qualifier = EvqTemporary; + 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) +{ + if (reservedErrorCheck(line, identifier)) + recover(); + + TVariable* variable = new TVariable(&identifier, TType(type)); + + if (! symbolTable.insert(*variable)) { + error(line, "redefinition", variable->getName().c_str(), ""); + delete variable; + 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->changeQualifier(EvqConstReadOnly); + else + type->changeQualifier(paramQualifier); + + return false; +} + +bool TParseContext::extensionErrorCheck(int line, const char* extension) +{ + if (extensionBehavior[extension] == EBhWarn) { + infoSink.info.message(EPrefixWarning, ("extension " + TString(extension) + " is being used").c_str(), line); + return false; + } + if (extensionBehavior[extension] == EBhDisable) { + error(line, "extension", extension, "is disabled"); + return true; + } + + return false; +} + +///////////////////////////////////////////////////////////////////////////////// +// +// 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) +{ + const TSymbol* 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; + } + + const TFunction* function = static_cast(symbol); + + return function; +} + +// +// 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()) { + error(line, " assigning non-constant to", "=", "'%s'", variable->getType().getCompleteString().c_str()); + variable->getType().changeQualifier(EvqTemporary); + return true; + } + if (type != initializer->getType()) { + error(line, " non-matching types for const initializer ", + variable->getType().getQualifierString(), ""); + variable->getType().changeQualifier(EvqTemporary); + return true; + } + if (initializer->getAsConstantUnion()) { + constUnion* 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(symbol); + + constUnion* constArray = tVar->getConstPointer(); + variable->shareConstPointer(constArray); + } else { + error(line, " cannot assign to", "=", "'%s'", variable->getType().getCompleteString().c_str()); + variable->getType().changeQualifier(EvqTemporary); + return true; + } + } + + if (qualifier != EvqConst) { + TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line); + intermNode = intermediate.addAssign(EOpAssign, intermSymbol, initializer, line); + if (intermNode == 0) { + assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString()); + return true; + } + } else + intermNode = 0; + + return false; +} + +bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode) +{ + 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 + if (aggrNode) { + TIntermSequence &childSequenceVector = aggrNode->getSequence() ; + for (TIntermSequence::iterator p = childSequenceVector.begin(); + p != childSequenceVector.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::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) { + sequenceVector.erase(p); + sequenceVector.insert(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; + constUnion* unionArray = new constUnion[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 { + error(line, "", "constructor", "cannot convert parameter %d from '%s' to '%s'", paramCount, + node->getAsTyped()->getType().getBasicString(), type->getBasicString()); + 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(); + + constUnion *unionArray; + if (tempConstantNode) { + unionArray = tempConstantNode->getUnionArrayPointer(); + + if (!unionArray) { // this error message should never be raised + infoSink.info.message(EPrefixInternalError, "constUnion not initialized in addConstVectorNode function", line); + recover(); + + 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; + } + + constUnion* constArray = new constUnion[fields.num]; + + for (int i = 0; i < fields.num; i++) { + if (fields.offsets[i] >= node->getType().getObjectSize()) { + error(line, "", "[", "vector field selection out of range '%d'", fields.offsets[i]); + 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()) { + error(line, "", "[", "matrix field selection out of range '%d'", index); + recover(); + index = 0; + } + + if (tempConstantNode) { + constUnion* 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(); + int arraySize = node->getType().getArraySize(); + TType arrayElementType = node->getType(); + arrayElementType.clearArrayness(); + + if (index >= node->getType().getArraySize()) { + error(line, "", "[", "array field selection out of range '%d'", index); + recover(); + index = 0; + } + + int arrayElementSize = arrayElementType.getObjectSize(); + + if (tempConstantNode) { + constUnion* 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) +{ + 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) { + constUnion* 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; +} + +// +// Initialize all supported extensions to disable +// +void TParseContext::initializeExtensionBehavior() +{ + // + // example code: extensionBehavior["test"] = EBhDisable; // where "test" is the name of + // supported extension + // + extensionBehavior["GL_ARB_texture_rectangle"] = EBhRequire; + extensionBehavior["GL_3DL_array_objects"] = EBhDisable; +} + +OS_TLSIndex GlobalParseContextIndex = OS_INVALID_TLS_INDEX; + +bool InitializeParseContextIndex() +{ + if (GlobalParseContextIndex != OS_INVALID_TLS_INDEX) { + assert(0 && "InitializeParseContextIndex(): Parse Context already initalised"); + return false; + } + + // + // Allocate a TLS index. + // + GlobalParseContextIndex = OS_AllocTLSIndex(); + + if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "InitializeParseContextIndex(): Parse Context already initalised"); + return false; + } + + return true; +} + +bool InitializeGlobalParseContext() +{ + if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "InitializeGlobalParseContext(): Parse Context index not initalised"); + return false; + } + + TThreadParseContext *lpParseContext = static_cast(OS_GetTLSValue(GlobalParseContextIndex)); + if (lpParseContext != 0) { + assert(0 && "InitializeParseContextIndex(): Parse Context already initalised"); + 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; +} + +TParseContextPointer& GetGlobalParseContext() +{ + // + // Minimal error checking for speed + // + + TThreadParseContext *lpParseContext = static_cast(OS_GetTLSValue(GlobalParseContextIndex)); + + return lpParseContext->lpGlobalParseContext; +} + +bool FreeParseContext() +{ + if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "FreeParseContext(): Parse Context index not initalised"); + return false; + } + + TThreadParseContext *lpParseContext = static_cast(OS_GetTLSValue(GlobalParseContextIndex)); + if (lpParseContext) + delete lpParseContext; + + return true; +} + +bool FreeParseContextIndex() +{ + OS_TLSIndex tlsiIndex = GlobalParseContextIndex; + + if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "FreeParseContextIndex(): Parse Context index not initalised"); + return false; + } + + GlobalParseContextIndex = OS_INVALID_TLS_INDEX; + + return OS_FreeTLSIndex(tlsiIndex); +} diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h new file mode 100644 index 00000000..ca153aec --- /dev/null +++ b/glslang/MachineIndependent/ParseHelper.h @@ -0,0 +1,150 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +#ifndef _PARSER_HELPER_INCLUDED_ +#define _PARSER_HELPER_INCLUDED_ + +#include "../Include/ShHandle.h" +#include "SymbolTable.h" +#include "localintermediate.h" + +struct TMatrixFields { + bool wholeRow; + bool wholeCol; + int row; + int col; +}; + +typedef enum { + EBhRequire, + EBhEnable, + EBhWarn, + EBhDisable +} TBehavior; + +struct TPragma { + TPragma(bool o, bool d) : optimize(o), debug(d) { } + bool optimize; + bool debug; + TPragmaTable pragmaTable; +}; + +// +// 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, TIntermediate& interm, EShLanguage L, TInfoSink& is) : + intermediate(interm), symbolTable(symt), infoSink(is), language(L), treeRoot(0), + recoveredFromError(false), numErrors(0), lexAfterType(false), loopNestingLevel(0), + inTypeParen(false), contextPragma(true, false) { } + TIntermediate& intermediate; // to hold and build a parse tree + TSymbolTable& symbolTable; // symbol table that goes with the language currently being parsed + TInfoSink& infoSink; + EShLanguage language; // vertex or fragment language (future: pack or unpack) + TIntermNode* treeRoot; // root of parse tree being created + bool recoveredFromError; // true if a parse error has occurred, but we continue to parse + int numErrors; + bool lexAfterType; // true if we've recognized a type, so can only be looking for an identifier + int loopNestingLevel; // 0 if outside all loops + 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 + TMap extensionBehavior; + void initializeExtensionBehavior(); + + void C_DECL error(TSourceLoc, const char *szReason, const char *szToken, + const char *szExtraInfoFormat, ...); + bool reservedErrorCheck(int line, const TString& identifier); + void recover(); + + bool parseVectorFields(const TString&, int vecSize, TVectorFields&, int line); + bool parseMatrixFields(const TString&, int matSize, TMatrixFields&, int line); + void assignError(int line, const char* op, TString left, TString right); + void unaryOpError(int line, char* op, TString operand); + void binaryOpError(int line, char* op, TString left, TString right); + bool lValueErrorCheck(int line, char* op, TIntermTyped*); + bool constErrorCheck(TIntermTyped* node); + bool integerErrorCheck(TIntermTyped* node, char* token); + bool globalErrorCheck(int line, bool global, 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 insertBuiltInArrayAtGlobalLevel(); + 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 containsSampler(TType& type); + bool nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type); + bool nonInitErrorCheck(int line, TString& identifier, TPublicType& type); + bool paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type); + bool extensionErrorCheck(int line, const char*); + 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 areAllChildConst(TIntermAggregate* aggrNode); + 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); + bool arraySetMaxSize(TIntermSymbol*, TType*, int, bool, TSourceLoc); + struct TPragma contextPragma; + TString HashErrMsg; + bool AfterEOF; +}; + +int PaParseStrings(char* argv[], int strLen[], int argc, TParseContext&); +void PaReservedWord(); +int PaIdentOrType(TString& id, TParseContext&, TSymbol*&); +int PaParseComment(int &lineno, TParseContext&); +void setInitialState(); + +typedef TParseContext* TParseContextPointer; +extern TParseContextPointer& GetGlobalParseContext(); +#define GlobalParseContext GetGlobalParseContext() + +typedef struct TThreadParseContextRec +{ + TParseContext *lpGlobalParseContext; +} TThreadParseContext; + +#endif // _PARSER_HELPER_INCLUDED_ diff --git a/glslang/MachineIndependent/PoolAlloc.cpp b/glslang/MachineIndependent/PoolAlloc.cpp new file mode 100644 index 00000000..9034bb37 --- /dev/null +++ b/glslang/MachineIndependent/PoolAlloc.cpp @@ -0,0 +1,342 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#include "../Include/PoolAlloc.h" +#include "../Include/Common.h" + +#include "Include/InitializeGlobals.h" +#include "osinclude.h" + +OS_TLSIndex PoolIndex; + +void InitializeGlobalPools() +{ + TThreadGlobalPools* globalPools= static_cast(OS_GetTLSValue(PoolIndex)); + if (globalPools) + return; + + TPoolAllocator *globalPoolAllocator = new TPoolAllocator(true); + + TThreadGlobalPools* threadData = new TThreadGlobalPools(); + + threadData->globalPoolAllocator = globalPoolAllocator; + + OS_SetTLSValue(PoolIndex, threadData); + globalPoolAllocator->push(); +} + +void FreeGlobalPools() +{ + // Release the allocated memory for this thread. + TThreadGlobalPools* globalPools= static_cast(OS_GetTLSValue(PoolIndex)); + if (!globalPools) + return; + + GlobalPoolAllocator.popAll(); + delete &GlobalPoolAllocator; + 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(OS_GetTLSValue(PoolIndex)); + + return *threadData->globalPoolAllocator; +} + +void SetGlobalPoolAllocatorPtr(TPoolAllocator* poolAllocator) +{ + TThreadGlobalPools* threadData = static_cast(OS_GetTLSValue(PoolIndex)); + + threadData->globalPoolAllocator = poolAllocator; +} + +// +// Implement the functionality of the TPoolAllocator class, which +// is documented in PoolAlloc.h. +// +TPoolAllocator::TPoolAllocator(bool g, int growthIncrement, int allocationAlignment) : + global(g), + pageSize(growthIncrement), + alignment(allocationAlignment), + freeList(0), + inUseList(0), + numCalls(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() +{ + if (!global) { + // + // Then we know that this object is not being + // allocated after other, globally scoped objects + // that depend on it. So we can delete the "in use" memory. + // + while (inUseList) { + tHeader* next = inUseList->nextPage; + inUseList->~tHeader(); + delete [] reinterpret_cast(inUseList); + inUseList = next; + } + } + + // + // Always delete the free list memory - it can't be being + // (correctly) referenced, whether the pool allocator was + // global or not. 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(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, char* locText) const +{ + for (int 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. + sprintf(assertMsg, "PoolAlloc: Damage %s %lu byte allocation at 0x%p\n", + locText, size, data()); + assert(0 && "PoolAlloc: Damage in guard block"); + } + } +} + + +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(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(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(::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(reinterpret_cast(memory) + headerSkip); + } + + // + // Need a simple page to allocate from. + // + tHeader* memory; + if (freeList) { + memory = freeList; + freeList = freeList->nextPage; + } else { + memory = reinterpret_cast(::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(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/glslang/MachineIndependent/QualifierAlive.cpp b/glslang/MachineIndependent/QualifierAlive.cpp new file mode 100644 index 00000000..a88fd437 --- /dev/null +++ b/glslang/MachineIndependent/QualifierAlive.cpp @@ -0,0 +1,91 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#include "../Include/intermediate.h" + +class TAliveTraverser : public TIntermTraverser { +public: + TAliveTraverser(TQualifier q) : TIntermTraverser(), found(false), qualifier(q) + { + visitSymbol = AliveSymbol; + visitSelection = AliveSelection; + rightToLeft = true; + } + bool wasFound() { return found; } +protected: + bool found; + TQualifier qualifier; + + friend void AliveSymbol(TIntermSymbol*, TIntermTraverser*); + friend bool AliveSelection(bool, TIntermSelection*, TIntermTraverser*); +}; + +// +// 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 AliveSymbol(TIntermSymbol* node, TIntermTraverser* it) +{ + TAliveTraverser* lit = static_cast(it); + + // + // If it's what we're looking for, record it. + // + if (node->getQualifier() == lit->qualifier) + lit->found = true; +} + +bool AliveSelection(bool preVisit, TIntermSelection* node, TIntermTraverser* it) +{ + TAliveTraverser* lit = static_cast(it); + + if (lit->wasFound()) + return false; + + return true; +} diff --git a/glslang/MachineIndependent/QualifierAlive.h b/glslang/MachineIndependent/QualifierAlive.h new file mode 100644 index 00000000..60dfa506 --- /dev/null +++ b/glslang/MachineIndependent/QualifierAlive.h @@ -0,0 +1,35 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +bool QualifierWritten(TIntermNode* root, TQualifier); diff --git a/glslang/MachineIndependent/RemoveTree.cpp b/glslang/MachineIndependent/RemoveTree.cpp new file mode 100644 index 00000000..196279e3 --- /dev/null +++ b/glslang/MachineIndependent/RemoveTree.cpp @@ -0,0 +1,98 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#include "../Include/intermediate.h" +#include "RemoveTree.h" +// +// Code to recursively delete the intermediate tree. +// + +void RemoveSymbol(TIntermSymbol* node, TIntermTraverser* it) +{ + delete node; +} + +bool RemoveBinary(bool /*preVisit*/ , TIntermBinary* node, TIntermTraverser*) +{ + delete node; + + return true; +} + +bool RemoveUnary(bool /*preVisit */, TIntermUnary* node, TIntermTraverser*) +{ + delete node; + + return true; +} + +bool RemoveAggregate(bool /*preVisit*/ , TIntermAggregate* node, TIntermTraverser*) +{ + delete node; + + return true; +} + +bool RemoveSelection(bool /*preVisit*/ , TIntermSelection* node, TIntermTraverser*) +{ + delete node; + + return true; +} + +void RemoveConstantUnion(TIntermConstantUnion* node, TIntermTraverser*) +{ + delete node; +} + +// +// Entry point. +// +void RemoveAllTreeNodes(TIntermNode* root) +{ + TIntermTraverser it; + + it.visitAggregate = RemoveAggregate; + it.visitBinary = RemoveBinary; + it.visitConstantUnion = RemoveConstantUnion; + it.visitSelection = RemoveSelection; + it.visitSymbol = RemoveSymbol; + it.visitUnary = RemoveUnary; + + it.preVisit = false; + it.postVisit = true; + + root->traverse(&it); +} + diff --git a/glslang/MachineIndependent/RemoveTree.h b/glslang/MachineIndependent/RemoveTree.h new file mode 100644 index 00000000..a6d70b4b --- /dev/null +++ b/glslang/MachineIndependent/RemoveTree.h @@ -0,0 +1,35 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +void RemoveAllTreeNodes(TIntermNode*); diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp new file mode 100644 index 00000000..5d932d18 --- /dev/null +++ b/glslang/MachineIndependent/ShaderLang.cpp @@ -0,0 +1,586 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +// +// Implement the top-level of interface to the compiler/linker, +// as defined in ShaderLang.h +// +#include "SymbolTable.h" +#include "ParseHelper.h" + +#include "../Include/ShHandle.h" +#include "InitializeDll.h" + +#define SH_EXPORTING +#include "../Public/ShaderLang.h" +#include "Initialize.h" +// +// A symbol table for each language. Each has a different +// set of built-ins, and we want to preserve that from +// compile to compile. +// +TSymbolTable SymbolTables[EShLangCount]; + + +TPoolAllocator* PerProcessGPA = 0; +// +// This is the platform independent interface between an OGL driver +// and the shading language compiler/linker. +// + +// +// Driver must call this first, once, before doing any other +// compiler/linker operations. +// +int ShInitialize() +{ + TInfoSink infoSink; + bool ret = true; + + if (!InitProcess()) + return 0; + + // This method should be called once per process. If its called by multiple threads, then + // we need to have thread synchronization code around the initialization of per process + // global pool allocator + if (!PerProcessGPA) { + TPoolAllocator *builtInPoolAllocator = new TPoolAllocator(true); + builtInPoolAllocator->push(); + TPoolAllocator* gPoolAllocator = &GlobalPoolAllocator; + SetGlobalPoolAllocatorPtr(builtInPoolAllocator); + + TSymbolTable symTables[EShLangCount]; + GenerateBuiltInSymbolTable(0, infoSink, symTables); + + PerProcessGPA = new TPoolAllocator(true); + PerProcessGPA->push(); + SetGlobalPoolAllocatorPtr(PerProcessGPA); + + SymbolTables[EShLangVertex].copyTable(symTables[EShLangVertex]); + SymbolTables[EShLangFragment].copyTable(symTables[EShLangFragment]); + + SetGlobalPoolAllocatorPtr(gPoolAllocator); + + symTables[EShLangVertex].pop(); + symTables[EShLangFragment].pop(); + + builtInPoolAllocator->popAll(); + delete builtInPoolAllocator; + + } + + return ret ? 1 : 0; +} + +// +// Driver calls these to create and destroy compiler/linker +// objects. +// + +ShHandle ShConstructCompiler(const EShLanguage language, int debugOptions) +{ + if (!InitThread()) + return 0; + + TShHandleBase* base = static_cast(ConstructCompiler(language, debugOptions)); + + return reinterpret_cast(base); +} + +ShHandle ShConstructLinker(const EShExecutable executable, int debugOptions) +{ + if (!InitThread()) + return 0; + + TShHandleBase* base = static_cast(ConstructLinker(executable, debugOptions)); + + return reinterpret_cast(base); +} + +ShHandle ShConstructUniformMap() +{ + if (!InitThread()) + return 0; + + TShHandleBase* base = static_cast(ConstructUniformMap()); + + return reinterpret_cast(base); +} + +void ShDestruct(ShHandle handle) +{ + if (handle == 0) + return; + + TShHandleBase* base = static_cast(handle); + + if (base->getAsCompiler()) + DeleteCompiler(base->getAsCompiler()); + else if (base->getAsLinker()) + DeleteLinker(base->getAsLinker()); + else if (base->getAsUniformMap()) + DeleteUniformMap(base->getAsUniformMap()); +} + +// +// Cleanup symbol tables +// +int __fastcall ShFinalize() +{ + if (PerProcessGPA) { + PerProcessGPA->popAll(); + delete PerProcessGPA; + } + return 1; +} + +bool GenerateBuiltInSymbolTable(const TBuiltInResource* resources, TInfoSink& infoSink, TSymbolTable* symbolTables, EShLanguage language) +{ + TBuiltIns builtIns; + + if (resources) { + builtIns.initialize(*resources); + InitializeSymbolTable(builtIns.getBuiltInStrings(), language, infoSink, resources, symbolTables); + } else { + builtIns.initialize(); + InitializeSymbolTable(builtIns.getBuiltInStrings(), EShLangVertex, infoSink, resources, symbolTables); + InitializeSymbolTable(builtIns.getBuiltInStrings(), EShLangFragment, infoSink, resources, symbolTables); + } + + return true; +} + +bool InitializeSymbolTable(TBuiltInStrings* BuiltInStrings, EShLanguage language, TInfoSink& infoSink, const TBuiltInResource* resources, TSymbolTable* symbolTables) +{ + TIntermediate intermediate(infoSink); + TSymbolTable* symbolTable; + + if (resources) + symbolTable = symbolTables; + else + symbolTable = &symbolTables[language]; + + TParseContext parseContext(*symbolTable, intermediate, language, infoSink); + + GlobalParseContext = &parseContext; + + setInitialState(); + + assert(symbolTable->isEmpty() || symbolTable->atSharedBuiltInLevel()); + + // + // Parse the built-ins. This should only happen once per + // language symbol table. + // + // Push the symbol table to give it an initial scope. This + // push should not have a corresponding pop, so that built-ins + // are preserved, and the test for an empty table fails. + // + + symbolTable->push(); + + //Initialize the Preprocessor + int ret = InitPreprocessor(); + if (ret) { + infoSink.info.message(EPrefixInternalError, "Unable to intialize the Preprocessor"); + return false; + } + + for (TBuiltInStrings::iterator i = BuiltInStrings[parseContext.language].begin(); + i != BuiltInStrings[parseContext.language].end(); + ++i) { + const char* builtInShaders[1]; + int builtInLengths[1]; + + builtInShaders[0] = (*i).c_str(); + builtInLengths[0] = (int) (*i).size(); + + if (PaParseStrings(const_cast(builtInShaders), builtInLengths, 1, parseContext) != 0) { + infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins"); + return false; + } + } + + if (resources) { + IdentifyBuiltIns(parseContext.language, *symbolTable, *resources); + } else { + IdentifyBuiltIns(parseContext.language, *symbolTable); + } + + FinalizePreprocessor(); + + return true; +} + +// +// 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, + const EShOptimizationLevel optLevel, + const TBuiltInResource* resources, + int debugOptions + ) +{ + if (!InitThread()) + return 0; + + if (handle == 0) + return 0; + + TShHandleBase* base = reinterpret_cast(handle); + TCompiler* compiler = base->getAsCompiler(); + if (compiler == 0) + return 0; + + GlobalPoolAllocator.push(); + compiler->infoSink.info.erase(); + compiler->infoSink.debug.erase(); + + if (numStrings == 0) + return 1; + + TIntermediate intermediate(compiler->infoSink); + TSymbolTable symbolTable(SymbolTables[compiler->getLanguage()]); + + GenerateBuiltInSymbolTable(resources, compiler->infoSink, &symbolTable, compiler->getLanguage()); + + TParseContext parseContext(symbolTable, intermediate, compiler->getLanguage(), compiler->infoSink); + parseContext.initializeExtensionBehavior(); + + GlobalParseContext = &parseContext; + + setInitialState(); + + InitPreprocessor(); + // + // Parse the application's shaders. All the following symbol table + // work will be throw-away, so push a new allocation scope that can + // be thrown away, then push a scope for the current shader's globals. + // + bool success = true; + + symbolTable.push(); + if (!symbolTable.atGlobalLevel()) + parseContext.infoSink.info.message(EPrefixInternalError, "Wrong symbol table level"); + + if (parseContext.insertBuiltInArrayAtGlobalLevel()) + success = false; + + int ret = PaParseStrings(const_cast(shaderStrings), 0, numStrings, parseContext); + if (ret) + success = false; + + if (success && parseContext.treeRoot) { + if (optLevel == EShOptNoGeneration) + parseContext.infoSink.info.message(EPrefixNone, "No errors. No code generation or linking was requested."); + else { + success = intermediate.postProcess(parseContext.treeRoot, parseContext.language); + + if (success) { + + if (debugOptions & EDebugOpIntermediate) + intermediate.outputTree(parseContext.treeRoot); + + // + // Call the machine dependent compiler + // + if (! compiler->compile(parseContext.treeRoot)) + success = false; + } + } + } else if (!success) { + parseContext.infoSink.info.prefix(EPrefixError); + parseContext.infoSink.info << parseContext.numErrors << " compilation errors. No code generated.\n\n"; + success = false; + if (debugOptions & EDebugOpIntermediate) + intermediate.outputTree(parseContext.treeRoot); + } + + intermediate.remove(parseContext.treeRoot); + + // + // Ensure symbol table is returned to the built-in level, + // throwing away all but the built-ins. + // + while (! symbolTable.atSharedBuiltInLevel()) + symbolTable.pop(); + + FinalizePreprocessor(); + // + // Throw away all the temporary memory used by the compilation process. + // + GlobalPoolAllocator.pop(); + + return success ? 1 : 0; +} + +// +// Do an actual link on the given compile objects. +// +// Return: The return value of is really boolean, indicating +// success or failure. +// +int ShLink( + const ShHandle linkHandle, + const ShHandle compHandles[], + const int numHandles, + ShHandle uniformMapHandle, + short int** uniformsAccessed, + int* numUniformsAccessed) + +{ + if (!InitThread()) + return 0; + + TShHandleBase* base = reinterpret_cast(linkHandle); + TLinker* linker = static_cast(base->getAsLinker()); + if (linker == 0) + return 0; + + int returnValue; + GlobalPoolAllocator.push(); + returnValue = ShLinkExt(linkHandle, compHandles, numHandles); + GlobalPoolAllocator.pop(); + + if (returnValue) + return 1; + + return 0; +} +// +// This link method will be eventually used once the ICD supports the new linker interface +// +int ShLinkExt( + const ShHandle linkHandle, + const ShHandle compHandles[], + const int numHandles) +{ + if (linkHandle == 0 || numHandles == 0) + return 0; + + THandleList cObjects; + + {// support MSVC++6.0 + for (int i = 0; i < numHandles; ++i) { + if (compHandles[i] == 0) + return 0; + TShHandleBase* base = reinterpret_cast(compHandles[i]); + if (base->getAsLinker()) { + cObjects.push_back(base->getAsLinker()); + } + if (base->getAsCompiler()) + cObjects.push_back(base->getAsCompiler()); + + + if (cObjects[i] == 0) + return 0; + } + } + + TShHandleBase* base = reinterpret_cast(linkHandle); + TLinker* linker = static_cast(base->getAsLinker()); + + if (linker == 0) + return 0; + + linker->infoSink.info.erase(); + + {// support MSVC++6.0 + for (int i = 0; i < numHandles; ++i) { + if (cObjects[i]->getAsCompiler()) { + if (! cObjects[i]->getAsCompiler()->linkable()) { + linker->infoSink.info.message(EPrefixError, "Not all shaders have valid object code."); + return 0; + } + } + } + } + + bool ret = linker->link(cObjects); + + return ret ? 1 : 0; +} + +// +// ShSetEncrpytionMethod is a place-holder for specifying +// how source code is encrypted. +// +void ShSetEncryptionMethod(ShHandle handle) +{ + if (handle == 0) + return; +} + +// +// Return any compiler/linker/uniformmap log of messages for the application. +// +const char* ShGetInfoLog(const ShHandle handle) +{ + if (!InitThread()) + return 0; + + if (handle == 0) + return 0; + + TShHandleBase* base = static_cast(handle); + TInfoSink* infoSink; + + if (base->getAsCompiler()) + infoSink = &(base->getAsCompiler()->getInfoSink()); + else if (base->getAsLinker()) + infoSink = &(base->getAsLinker()->getInfoSink()); + + infoSink->info << infoSink->debug.c_str(); + return infoSink->info.c_str(); +} + +// +// Return the resulting binary code from the link process. Structure +// is machine dependent. +// +const void* ShGetExecutable(const ShHandle handle) +{ + if (!InitThread()) + return 0; + + if (handle == 0) + return 0; + + TShHandleBase* base = reinterpret_cast(handle); + + TLinker* linker = static_cast(base->getAsLinker()); + if (linker == 0) + return 0; + + return linker->getObjectCode(); +} + +// +// Let the linker know where the application said it's attributes are bound. +// The linker does not use these values, they are remapped by the ICD or +// hardware. It just needs them to know what's aliased. +// +// Return: The return value of is really boolean, indicating +// success or failure. +// +int ShSetVirtualAttributeBindings(const ShHandle handle, const ShBindingTable* table) +{ + if (!InitThread()) + return 0; + + if (handle == 0) + return 0; + + TShHandleBase* base = reinterpret_cast(handle); + TLinker* linker = static_cast(base->getAsLinker()); + + if (linker == 0) + return 0; + + linker->setAppAttributeBindings(table); + + return 1; +} + +// +// Let the linker know where the predefined attributes have to live. +// +int ShSetFixedAttributeBindings(const ShHandle handle, const ShBindingTable* table) +{ + if (!InitThread()) + return 0; + + if (handle == 0) + return 0; + + TShHandleBase* base = reinterpret_cast(handle); + TLinker* linker = static_cast(base->getAsLinker()); + + if (linker == 0) + return 0; + + linker->setFixedAttributeBindings(table); + return 1; +} + +// +// Some attribute locations are off-limits to the linker... +// +int ShExcludeAttributes(const ShHandle handle, int *attributes, int count) +{ + if (!InitThread()) + return 0; + + if (handle == 0) + return 0; + + TShHandleBase* base = reinterpret_cast(handle); + TLinker* linker = static_cast(base->getAsLinker()); + if (linker == 0) + return 0; + + linker->setExcludedAttributes(attributes, count); + + return 1; +} + +// +// Return the index for OpenGL to use for knowing where a uniform lives. +// +// Return: The return value of is really boolean, indicating +// success or failure. +// +int ShGetUniformLocation(const ShHandle handle, const char* name) +{ + if (!InitThread()) + return 0; + + if (handle == 0) + return -1; + + TShHandleBase* base = reinterpret_cast(handle); + TUniformMap* uniformMap= base->getAsUniformMap(); + if (uniformMap == 0) + return -1; + + return uniformMap->getLocation(name); +} + diff --git a/glslang/MachineIndependent/SymbolTable.cpp b/glslang/MachineIndependent/SymbolTable.cpp new file mode 100644 index 00000000..ea899503 --- /dev/null +++ b/glslang/MachineIndependent/SymbolTable.cpp @@ -0,0 +1,245 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +// +// Symbol table for parsing. Most functionaliy and main ideas +// are documented in the header file. +// + +#include "SymbolTable.h" + +// +// TType helper function needs a place to live. +// + +// +// 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 EbtSampler1D: mangledName += "s1"; break; + case EbtSampler2D: mangledName += "s2"; break; + case EbtSampler3D: mangledName += "s3"; break; + case EbtSamplerCube: mangledName += "sC"; break; + case EbtSampler1DShadow: mangledName += "sS1"; break; + case EbtSampler2DShadow: mangledName += "sS2"; break; + case EbtSamplerRect: mangledName += "sR2"; break; // ARB_texture_rectangle + case EbtSamplerRectShadow: mangledName += "sSR2"; break; // ARB_texture_rectangle + 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('0' + getNominalSize()); + if (isArray()) { + char buf[10]; + sprintf(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::iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++) + structureSize += ((*tl).type)->getObjectSize(); + + return structureSize; +} + +// +// Dump functions. +// + +void TVariable::dump(TInfoSink& infoSink) const +{ + infoSink.debug << getName().c_str() << ": " << type.getQualifierString() << " " << 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((*it).second); + if (function->getName() == name) + function->relateToOperator(op); + } + } +} + + +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 constUnion[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)); + } +} diff --git a/glslang/MachineIndependent/SymbolTable.h b/glslang/MachineIndependent/SymbolTable.h new file mode 100644 index 00000000..719c0c8a --- /dev/null +++ b/glslang/MachineIndependent/SymbolTable.h @@ -0,0 +1,318 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#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 "Include/Common.h" +#include "Include/intermediate.h" +#include "Include/InfoSink.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 changeQualifier(TQualifier qualifier) { type.changeQualifier(qualifier); } + void updateArrayInformationType(TType *t) { arrayInformationType = t; } + TType* getArrayInformationType() { return arrayInformationType; } + + virtual void dump(TInfoSink &infoSink) const; + + constUnion* getConstPointer() { + if (!unionArray) + unionArray = new constUnion[type.getObjectSize()]; + + return unionArray; + } + + constUnion* getConstPointer() const { return unionArray; } + + void shareConstPointer( constUnion *constArray) + { + 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 + constUnion *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)), + op(o), + defined(false) { } + TFunction(const TString *name, TType& retType, TOperator tOp = EOpNull) : + TSymbol(name), + returnType(retType), + mangledName(*name + '('), + op(tOp), + defined(false) { } + virtual ~TFunction(); + virtual bool isFunction() const { return true; } + + 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 setDefined() { defined = true; } + bool isDefined() { return defined; } + + int getParamCount() const { return static_cast(parameters.size()); } + TParameter& operator [](int i) { return parameters[i]; } + const TParameter& operator [](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 TParamList; + TParamList parameters; + TType returnType; + TString mangledName; + TOperator op; + bool defined; +}; + + +class TSymbolTableLevel { +public: + 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; + } + + + void relateToOperator(const char* name, TOperator op); + void dump(TInfoSink &infoSink) const; + TSymbolTableLevel* clone(TStructureMap& remapper); + +protected: + typedef std::map, pool_allocator > > tLevel; + typedef const tLevel::value_type tLevelPair; + typedef std::pair tInsertResult; + + 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(TSymbolTable& symTable) + { + table.push_back(symTable.table[0]); + uniqueId = symTable.uniqueId; + } + + ~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 atSharedBuiltInLevel() || atDynamicBuiltInLevel(); } + bool atSharedBuiltInLevel() { return table.size() == 1; } + bool atGlobalLevel() { return table.size() <= 3; } + void push() { + table.push_back(new TSymbolTableLevel); + } + + void pop() { + delete table[currentLevel()]; + table.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; + } + + TSymbolTableLevel* getGlobalLevel() { assert(table.size() >= 3); return table[2]; } + void relateToOperator(const char* name, TOperator op) { table[0]->relateToOperator(name, op); } + int getMaxSymbolId() { return uniqueId; } + void dump(TInfoSink &infoSink) const; + void copyTable(const TSymbolTable& copyOf); + +protected: + int currentLevel() const { return static_cast(table.size()) - 1; } + bool atDynamicBuiltInLevel() { return table.size() == 2; } + + std::vector table; + int uniqueId; // for unique identification in code generation +}; + +#endif // _SYMBOL_TABLE_INCLUDED_ diff --git a/glslang/MachineIndependent/glslang.l b/glslang/MachineIndependent/glslang.l new file mode 100644 index 00000000..094933ee --- /dev/null +++ b/glslang/MachineIndependent/glslang.l @@ -0,0 +1,637 @@ +/* +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +*/ +/* Based on +ANSI C grammar, Lex specification + +In 1985, Jeff Lee published this Lex specification together with a Yacc +grammar for the April 30, 1985 ANSI C draft. Tom Stockfisch reposted +both to net.sources in 1987; that original, as mentioned in the answer +to question 17.25 of the comp.lang.c FAQ, can be ftp'ed from ftp.uu.net, +file usenet/net.sources/ansi.c.grammar.Z. + +I intend to keep this version as close to the current C Standard grammar +as possible; please let me know if you discover discrepancies. + +Jutta Degener, 1995 +*/ + +D [0-9] +L [a-zA-Z_] +H [a-fA-F0-9] +E [Ee][+-]?{D}+ +O [0-7] + +%option nounput +%{ +#include +#include +#include "ParseHelper.h" +#include "glslang_tab.h" + +/* windows only pragma */ +#ifdef _MSC_VER +#pragma warning(disable : 4102) +#endif + +int yy_input(char* buf, int max_size); +TSourceLoc yylineno; + +#ifdef _WIN32 + extern int yyparse(TParseContext&); + #define YY_DECL int yylex(YYSTYPE* pyylval, TParseContext& parseContext) +#else + extern int yyparse(void*); + #define YY_DECL int yylex(YYSTYPE* pyylval, void* parseContextLocal) + #define parseContext (*((TParseContext*)(parseContextLocal))) +#endif + +#define YY_INPUT(buf,result,max_size) (result = yy_input(buf, max_size)) + +%} + +%option noyywrap +%option never-interactive +%option outfile="Gen_glslang.cpp" +%x FIELDS + + +%% +<*>"//"[^\n]*"\n" { /* ?? carriage and/or line-feed? */ }; + +"attribute" { pyylval->lex.line = yylineno; return(ATTRIBUTE); } +"const" { pyylval->lex.line = yylineno; return(CONST_QUAL); } +"uniform" { pyylval->lex.line = yylineno; return(UNIFORM); } +"varying" { pyylval->lex.line = yylineno; return(VARYING); } + +"break" { pyylval->lex.line = yylineno; return(BREAK); } +"continue" { pyylval->lex.line = yylineno; return(CONTINUE); } +"do" { pyylval->lex.line = yylineno; return(DO); } +"for" { pyylval->lex.line = yylineno; return(FOR); } +"while" { pyylval->lex.line = yylineno; return(WHILE); } + +"if" { pyylval->lex.line = yylineno; return(IF); } +"else" { pyylval->lex.line = yylineno; return(ELSE); } + +"in" { pyylval->lex.line = yylineno; return(IN_QUAL); } +"out" { pyylval->lex.line = yylineno; return(OUT_QUAL); } +"inout" { pyylval->lex.line = yylineno; return(INOUT_QUAL); } + +"float" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(FLOAT_TYPE); } +"int" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(INT_TYPE); } +"void" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(VOID_TYPE); } +"bool" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(BOOL_TYPE); } +"true" { pyylval->lex.line = yylineno; pyylval->lex.b = true; return(BOOLCONSTANT); } +"false" { pyylval->lex.line = yylineno; pyylval->lex.b = false; return(BOOLCONSTANT); } + +"discard" { pyylval->lex.line = yylineno; return(DISCARD); } +"return" { pyylval->lex.line = yylineno; return(RETURN); } + +"mat2" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MATRIX2); } +"mat3" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MATRIX3); } +"mat4" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MATRIX4); } + +"vec2" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (VEC2); } +"vec3" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (VEC3); } +"vec4" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (VEC4); } +"ivec2" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (IVEC2); } +"ivec3" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (IVEC3); } +"ivec4" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (IVEC4); } +"bvec2" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (BVEC2); } +"bvec3" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (BVEC3); } +"bvec4" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (BVEC4); } + +"sampler1D" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER1D; } +"sampler2D" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER2D; } +"sampler3D" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER3D; } +"samplerCube" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLERCUBE; } +"sampler1DShadow" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER1DSHADOW; } +"sampler2DShadow" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER2DSHADOW; } + +"sampler2DRect" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLERRECTARB; /* ARB_texture_rectangle */ } +"sampler2DRectShadow" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLERRECTSHADOWARB; /* ARB_texture_rectangle */ } + +"struct" { pyylval->lex.line = yylineno; return(STRUCT); } + +"asm" { PaReservedWord(); return 0; } + +"class" { PaReservedWord(); return 0; } +"union" { PaReservedWord(); return 0; } +"enum" { PaReservedWord(); return 0; } +"typedef" { PaReservedWord(); return 0; } +"template" { PaReservedWord(); return 0; } +"this" { PaReservedWord(); return 0; } +"packed" { PaReservedWord(); return 0; } + +"goto" { PaReservedWord(); return 0; } +"switch" { PaReservedWord(); return 0; } +"default" { PaReservedWord(); return 0; } + +"inline" { PaReservedWord(); return 0; } +"noinline" { PaReservedWord(); return 0; } +"volatile" { PaReservedWord(); return 0; } +"public" { PaReservedWord(); return 0; } +"static" { PaReservedWord(); return 0; } +"extern" { PaReservedWord(); return 0; } +"external" { PaReservedWord(); return 0; } +"interface" { PaReservedWord(); return 0; } + +"long" { PaReservedWord(); return 0; } +"short" { PaReservedWord(); return 0; } +"double" { PaReservedWord(); return 0; } +"half" { PaReservedWord(); return 0; } +"fixed" { PaReservedWord(); return 0; } +"unsigned" { PaReservedWord(); return 0; } + +"input" { PaReservedWord(); return 0; } +"output" { PaReservedWord(); return 0; } + +"hvec2" { PaReservedWord(); return 0; } +"hvec3" { PaReservedWord(); return 0; } +"hvec4" { PaReservedWord(); return 0; } +"fvec2" { PaReservedWord(); return 0; } +"fvec3" { PaReservedWord(); return 0; } +"fvec4" { PaReservedWord(); return 0; } +"dvec2" { PaReservedWord(); return 0; } +"dvec3" { PaReservedWord(); return 0; } +"dvec4" { PaReservedWord(); return 0; } + +"sampler3DRect" { PaReservedWord(); return 0; } + +"sizeof" { PaReservedWord(); return 0; } +"cast" { PaReservedWord(); return 0; } + +"namespace" { PaReservedWord(); return 0; } +"using" { PaReservedWord(); return 0; } + +{L}({L}|{D})* { + pyylval->lex.line = yylineno; + pyylval->lex.string = NewPoolTString(yytext); + return PaIdentOrType(*pyylval->lex.string, parseContext, pyylval->lex.symbol); +} + +0[xX]{H}+ { pyylval->lex.line = yylineno; pyylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } +0{O}+ { pyylval->lex.line = yylineno; pyylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } +0{D}+ { pyylval->lex.line = yylineno; parseContext.error(yylineno, "Invalid Octal number.", yytext, "", ""); parseContext.recover(); return 0;} +{D}+ { pyylval->lex.line = yylineno; pyylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } + +{D}+{E} { pyylval->lex.line = yylineno; pyylval->lex.f = static_cast(atof(yytext)); return(FLOATCONSTANT); } +{D}+"."{D}*({E})? { pyylval->lex.line = yylineno; pyylval->lex.f = static_cast(atof(yytext)); return(FLOATCONSTANT); } +"."{D}+({E})? { pyylval->lex.line = yylineno; pyylval->lex.f = static_cast(atof(yytext)); return(FLOATCONSTANT); } + +"/*" { int ret = PaParseComment(pyylval->lex.line, parseContext); if (!ret) return ret; } + +"+=" { pyylval->lex.line = yylineno; return(ADD_ASSIGN); } +"-=" { pyylval->lex.line = yylineno; return(SUB_ASSIGN); } +"*=" { pyylval->lex.line = yylineno; return(MUL_ASSIGN); } +"/=" { pyylval->lex.line = yylineno; return(DIV_ASSIGN); } +"%=" { pyylval->lex.line = yylineno; return(MOD_ASSIGN); } +"<<=" { pyylval->lex.line = yylineno; return(LEFT_ASSIGN); } +">>=" { pyylval->lex.line = yylineno; return(RIGHT_ASSIGN); } +"&=" { pyylval->lex.line = yylineno; return(AND_ASSIGN); } +"^=" { pyylval->lex.line = yylineno; return(XOR_ASSIGN); } +"|=" { pyylval->lex.line = yylineno; return(OR_ASSIGN); } + +"++" { pyylval->lex.line = yylineno; return(INC_OP); } +"--" { pyylval->lex.line = yylineno; return(DEC_OP); } +"&&" { pyylval->lex.line = yylineno; return(AND_OP); } +"||" { pyylval->lex.line = yylineno; return(OR_OP); } +"^^" { pyylval->lex.line = yylineno; return(XOR_OP); } +"<=" { pyylval->lex.line = yylineno; return(LE_OP); } +">=" { pyylval->lex.line = yylineno; return(GE_OP); } +"==" { pyylval->lex.line = yylineno; return(EQ_OP); } +"!=" { pyylval->lex.line = yylineno; return(NE_OP); } +"<<" { pyylval->lex.line = yylineno; return(LEFT_OP); } +">>" { pyylval->lex.line = yylineno; return(RIGHT_OP); } +";" { pyylval->lex.line = yylineno; parseContext.lexAfterType = false; return(SEMICOLON); } +("{"|"<%") { pyylval->lex.line = yylineno; parseContext.lexAfterType = false; return(LEFT_BRACE); } +("}"|"%>") { pyylval->lex.line = yylineno; return(RIGHT_BRACE); } +"," { pyylval->lex.line = yylineno; if (parseContext.inTypeParen) parseContext.lexAfterType = false; return(COMMA); } +":" { pyylval->lex.line = yylineno; return(COLON); } +"=" { pyylval->lex.line = yylineno; parseContext.lexAfterType = false; return(EQUAL); } +"(" { pyylval->lex.line = yylineno; parseContext.lexAfterType = false; parseContext.inTypeParen = true; return(LEFT_PAREN); } +")" { pyylval->lex.line = yylineno; parseContext.inTypeParen = false; return(RIGHT_PAREN); } +("["|"<:") { pyylval->lex.line = yylineno; return(LEFT_BRACKET); } +("]"|":>") { pyylval->lex.line = yylineno; return(RIGHT_BRACKET); } +"." { BEGIN(FIELDS); return(DOT); } +"!" { pyylval->lex.line = yylineno; return(BANG); } +"-" { pyylval->lex.line = yylineno; return(DASH); } +"~" { pyylval->lex.line = yylineno; return(TILDE); } +"+" { pyylval->lex.line = yylineno; return(PLUS); } +"*" { pyylval->lex.line = yylineno; return(STAR); } +"/" { pyylval->lex.line = yylineno; return(SLASH); } +"%" { pyylval->lex.line = yylineno; return(PERCENT); } +"<" { pyylval->lex.line = yylineno; return(LEFT_ANGLE); } +">" { pyylval->lex.line = yylineno; return(RIGHT_ANGLE); } +"|" { pyylval->lex.line = yylineno; return(VERTICAL_BAR); } +"^" { pyylval->lex.line = yylineno; return(CARET); } +"&" { pyylval->lex.line = yylineno; return(AMPERSAND); } +"?" { pyylval->lex.line = yylineno; return(QUESTION); } + +{L}({L}|{D})* { +BEGIN(INITIAL); + pyylval->lex.line = yylineno; + pyylval->lex.string = NewPoolTString(yytext); + return FIELD_SELECTION; } +[ \t\v\f\r] {} + +[ \t\v\n\f\r] { } +<*><> { (&parseContext)->AfterEOF = true; yy_delete_buffer(YY_CURRENT_BUFFER); yyterminate();} +<*>. { parseContext.infoSink.info << "FLEX: Unknown char " << yytext << "\n"; + return 0; } + +%% + + +//Including Pre-processor. +extern "C" { + #include "./preprocessor/preprocess.h" +} + +// +// The YY_INPUT macro just calls this. Maybe this could be just put into +// the macro directly. +// + +int yy_input(char* buf, int max_size) +{ + char *char_token =NULL; + int len; + + if ((len = yylex_CPP(buf, max_size)) == 0) + return 0; + if (len >= max_size) + YY_FATAL_ERROR( "input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); + + buf[len] = ' '; + return len+1; +} + + +// +// Parse an array of strings using yyparse. We set up globals used by +// yywrap. +// +// Returns 0 for success, as per yyparse(). +// +int PaParseStrings(char* argv[], int strLen[], int argc, TParseContext& parseContextLocal) +{ + int argv0len; + + ScanFromString(argv[0]); + + //Storing the Current Compiler Parse context into the cpp structure. + cpp->pC = (void*)&parseContextLocal; + + if (!argv || argc == 0) + return 1; + + for (int i = 0; i < argc; ++i) { + if (!argv[i]) { + parseContextLocal.error(0, "Null shader source string", "", ""); + parseContextLocal.recover(); + return 1; + } + } + + if (!strLen) { + argv0len = (int) strlen(argv[0]); + strLen = &argv0len; + } + yyrestart(0); + (&parseContextLocal)->AfterEOF = false; + cpp->PaWhichStr = 0; + cpp->PaArgv = argv; + cpp->PaArgc = argc; + cpp->PaStrLen = strLen; + cpp->notAVersionToken = 0; + yylineno = 1; + + if (*cpp->PaStrLen >= 0) { + int ret; + #ifdef _WIN32 + ret = yyparse(parseContextLocal); + #else + ret = yyparse((void*)(&parseContextLocal)); + #endif + if (cpp->CompileError == 1 || parseContextLocal.recoveredFromError || parseContextLocal.numErrors > 0) + return 1; + else + return 0; + } + else + return 0; +} + +void yyerror(char *s) +{ + if (((TParseContext *)cpp->pC)->AfterEOF) { + if (cpp->tokensBeforeEOF == 1) { + GlobalParseContext->error(yylineno, "syntax error", "pre-mature EOF", s, ""); + GlobalParseContext->recover(); + } + } else { + GlobalParseContext->error(yylineno, "syntax error", yytext, s, ""); + GlobalParseContext->recover(); + } +} + +void PaReservedWord() +{ + GlobalParseContext->error(yylineno, "Reserved word.", yytext, "", ""); + GlobalParseContext->recover(); +} + +int PaIdentOrType(TString& id, TParseContext& parseContextLocal, TSymbol*& symbol) +{ + symbol = parseContextLocal.symbolTable.find(id); + if (parseContextLocal.lexAfterType == false && symbol && symbol->isVariable()) { + TVariable* variable = static_cast(symbol); + if (variable->isUserType()) { + parseContextLocal.lexAfterType = true; + return TYPE_NAME; + } + } + + return IDENTIFIER; +} + +int PaParseComment(int &lineno, TParseContext& parseContextLocal) +{ + int transitionFlag = 0; + int nextChar; + + while (transitionFlag != 2) { + nextChar = yyinput(); + if (nextChar == '\n') + lineno++; + switch (nextChar) { + case '*' : + transitionFlag = 1; + break; + case '/' : /* if star is the previous character, then it is the end of comment */ + if (transitionFlag == 1) { + return 1 ; + } + break; + case EOF : + /* Raise error message here */ + parseContextLocal.error(yylineno, "End of shader found before end of comment.", "", "", ""); + GlobalParseContext->recover(); + return YY_NULL; + default : /* Any other character will be a part of the comment */ + transitionFlag = 0; + } + } + return 1; +} + +extern "C" { + +void CPPDebugLogMsg(const char *msg) +{ + ((TParseContext *)cpp->pC)->infoSink.debug.message(EPrefixNone, msg); +} + +void CPPWarningToInfoLog(const char *msg) +{ + ((TParseContext *)cpp->pC)->infoSink.info.message(EPrefixWarning, msg, yylineno); +} + +void CPPShInfoLogMsg(const char *msg) +{ + ((TParseContext *)cpp->pC)->error(yylineno,"", "",msg,""); + GlobalParseContext->recover(); +} + +void CPPErrorToInfoLog(char *msg) +{ + ((TParseContext *)cpp->pC)->error(yylineno,"syntax error", "",msg,""); + GlobalParseContext->recover(); +} + +void SetLineNumber(int line) +{ + yylineno &= ~SourceLocLineMask; + yylineno |= line; +} + +void SetStringNumber(int string) +{ + yylineno = (string << SourceLocStringShift) | (yylineno & SourceLocLineMask); +} + +int GetStringNumber(void) +{ + return yylineno >> 16; +} + +int GetLineNumber(void) +{ + return yylineno & SourceLocLineMask; +} + +void IncLineNumber(void) +{ + if ((yylineno & SourceLocLineMask) <= SourceLocLineMask) + ++yylineno; +} + +void DecLineNumber(void) +{ + if ((yylineno & SourceLocLineMask) > 0) + --yylineno; +} + +void HandlePragma(const char **tokens, int numTokens) +{ + if (!strcmp(tokens[0], "optimize")) { + if (numTokens != 4) { + CPPShInfoLogMsg("optimize pragma syntax is incorrect"); + return; + } + + if (strcmp(tokens[1], "(")) { + CPPShInfoLogMsg("\"(\" expected after 'optimize' keyword"); + return; + } + + if (!strcmp(tokens[2], "on")) + ((TParseContext *)cpp->pC)->contextPragma.optimize = true; + else if (!strcmp(tokens[2], "off")) + ((TParseContext *)cpp->pC)->contextPragma.optimize = false; + else { + CPPShInfoLogMsg("\"on\" or \"off\" expected after '(' for 'optimize' pragma"); + return; + } + + if (strcmp(tokens[3], ")")) { + CPPShInfoLogMsg("\")\" expected to end 'optimize' pragma"); + return; + } + } else if (!strcmp(tokens[0], "debug")) { + if (numTokens != 4) { + CPPShInfoLogMsg("debug pragma syntax is incorrect"); + return; + } + + if (strcmp(tokens[1], "(")) { + CPPShInfoLogMsg("\"(\" expected after 'debug' keyword"); + return; + } + + if (!strcmp(tokens[2], "on")) + ((TParseContext *)cpp->pC)->contextPragma.debug = true; + else if (!strcmp(tokens[2], "off")) + ((TParseContext *)cpp->pC)->contextPragma.debug = false; + else { + CPPShInfoLogMsg("\"on\" or \"off\" expected after '(' for 'debug' pragma"); + return; + } + + if (strcmp(tokens[3], ")")) { + CPPShInfoLogMsg("\")\" expected to end 'debug' pragma"); + return; + } + } else { + +#ifdef PRAGMA_TABLE + // + // implementation specific pragma + // use ((TParseContext *)cpp->pC)->contextPragma.pragmaTable to store the information about pragma + // For now, just ignore the pragma that the implementation cannot recognize + // An Example of one such implementation for a pragma that has a syntax like + // #pragma pragmaname(pragmavalue) + // This implementation stores the current pragmavalue against the pragma name in pragmaTable. + // + if (numTokens == 4 && !strcmp(tokens[1], "(") && !strcmp(tokens[3], ")")) { + TPragmaTable& pragmaTable = ((TParseContext *)cpp->pC)->contextPragma.pragmaTable; + TPragmaTable::iterator iter; + iter = pragmaTable.find(TString(tokens[0])); + if (iter != pragmaTable.end()) { + iter->second = tokens[2]; + } else { + pragmaTable[tokens[0]] = tokens[2]; + } + } else if (numTokens >= 2) { + TPragmaTable& pragmaTable = ((TParseContext *)cpp->pC)->contextPragma.pragmaTable; + TPragmaTable::iterator iter; + iter = pragmaTable.find(TString(tokens[0])); + if (iter != pragmaTable.end()) { + iter->second = tokens[1]; + } else { + pragmaTable[tokens[0]] = tokens[1]; + } + } +#endif // PRAGMA_TABLE + } +} + +void StoreStr(char *string) +{ + TString strSrc; + strSrc = TString(string); + + ((TParseContext *)cpp->pC)->HashErrMsg = ((TParseContext *)cpp->pC)->HashErrMsg + " " + strSrc; +} + +const char* GetStrfromTStr(void) +{ + cpp->ErrMsg = (((TParseContext *)cpp->pC)->HashErrMsg).c_str(); + return cpp->ErrMsg; +} + +void ResetTString(void) +{ + ((TParseContext *)cpp->pC)->HashErrMsg = ""; +} + +TBehavior GetBehavior(const char* behavior) +{ + if (!strcmp("require", behavior)) + return EBhRequire; + else if (!strcmp("enable", behavior)) + return EBhEnable; + else if (!strcmp("disable", behavior)) + return EBhDisable; + else if (!strcmp("warn", behavior)) + return EBhWarn; + else { + CPPShInfoLogMsg((TString("behavior '") + behavior + "' is not supported").c_str()); + return EBhDisable; + } +} + +void updateExtensionBehavior(const char* extName, const char* behavior) +{ + TBehavior behaviorVal = GetBehavior(behavior); + TMap:: iterator iter; + TString msg; + + // special cased for all extension + if (!strcmp(extName, "all")) { + if (behaviorVal == EBhRequire || behaviorVal == EBhEnable) { + CPPShInfoLogMsg("extension 'all' cannot have 'require' or 'enable' behavior"); + return; + } else { + for (iter = ((TParseContext *)cpp->pC)->extensionBehavior.begin(); iter != ((TParseContext *)cpp->pC)->extensionBehavior.end(); ++iter) + iter->second = behaviorVal; + } + } else { + iter = ((TParseContext *)cpp->pC)->extensionBehavior.find(TString(extName)); + if (iter == ((TParseContext *)cpp->pC)->extensionBehavior.end()) { + switch (behaviorVal) { + case EBhRequire: + CPPShInfoLogMsg((TString("extension '") + extName + "' is not supported").c_str()); + break; + case EBhEnable: + case EBhWarn: + case EBhDisable: + msg = TString("extension '") + extName + "' is not supported"; + ((TParseContext *)cpp->pC)->infoSink.info.message(EPrefixWarning, msg.c_str(), yylineno); + break; + } + return; + } else + iter->second = behaviorVal; + } +} + +} // extern "C" + +void setInitialState() +{ + yy_start = 1; +} diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y new file mode 100644 index 00000000..c3fe4272 --- /dev/null +++ b/glslang/MachineIndependent/glslang.y @@ -0,0 +1,2317 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +/** + * This is bison grammar and production code for parsing the OpenGL 2.0 shading + * languages. + */ +%{ + +/* Based on: +ANSI C Yacc grammar + +In 1985, Jeff Lee published his Yacc grammar (which is accompanied by a +matching Lex specification) for the April 30, 1985 draft version of the +ANSI C standard. Tom Stockfisch reposted it to net.sources in 1987; that +original, as mentioned in the answer to question 17.25 of the comp.lang.c +FAQ, can be ftp'ed from ftp.uu.net, file usenet/net.sources/ansi.c.grammar.Z. + +I intend to keep this version as close to the current C Standard grammar as +possible; please let me know if you discover discrepancies. + +Jutta Degener, 1995 +*/ + +#include "SymbolTable.h" +#include "ParseHelper.h" +#include "../Public/ShaderLang.h" + +#ifdef _WIN32 + #define YYPARSE_PARAM parseContext + #define YYPARSE_PARAM_DECL TParseContext& + #define YY_DECL int yylex(YYSTYPE* pyylval, TParseContext& parseContext) + #define YYLEX_PARAM parseContext +#else + #define YYPARSE_PARAM parseContextLocal + #define parseContext (*((TParseContext*)(parseContextLocal))) + #define YY_DECL int yylex(YYSTYPE* pyylval, void* parseContextLocal) + #define YYLEX_PARAM (void*)(parseContextLocal) + extern void yyerror(char*); +#endif + +#define FRAG_VERT_ONLY(S, L) { \ + if (parseContext.language != EShLangFragment && \ + parseContext.language != EShLangVertex) { \ + parseContext.error(L, " supported in vertex/fragment shaders only ", S, "", ""); \ + parseContext.recover(); \ + } \ +} + +#define VERTEX_ONLY(S, L) { \ + if (parseContext.language != EShLangVertex) { \ + parseContext.error(L, " supported in vertex shaders only ", S, "", ""); \ + parseContext.recover(); \ + } \ +} + +#define FRAG_ONLY(S, L) { \ + if (parseContext.language != EShLangFragment) { \ + parseContext.error(L, " supported in fragment shaders only ", S, "", ""); \ + parseContext.recover(); \ + } \ +} + +#define PACK_ONLY(S, L) { \ + if (parseContext.language != EShLangPack) { \ + parseContext.error(L, " supported in pack shaders only ", S, "", ""); \ + parseContext.recover(); \ + } \ +} + +#define UNPACK_ONLY(S, L) { \ + if (parseContext.language != EShLangUnpack) { \ + parseContext.error(L, " supported in unpack shaders only ", S, "", ""); \ + parseContext.recover(); \ + } \ +} + +#define PACK_UNPACK_ONLY(S, L) { \ + if (parseContext.language != EShLangUnpack && \ + parseContext.language != EShLangPack) { \ + parseContext.error(L, " supported in pack/unpack shaders only ", S, "", ""); \ + parseContext.recover(); \ + } \ +} +%} +%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; + TQualifier qualifier; + TFunction* function; + TParameter param; + TTypeLine typeLine; + TTypeList* typeList; + }; + } interm; +} + +%{ +#ifndef _WIN32 + extern int yylex(YYSTYPE*, void*); +#endif +%} + +%pure_parser /* Just in case is called from multiple threads */ +%expect 1 /* One shift reduce conflict because of if | else */ +%token ATTRIBUTE CONST_QUAL BOOL_TYPE FLOAT_TYPE INT_TYPE +%token BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN +%token BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 VEC2 VEC3 VEC4 +%token MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING +%token STRUCT VOID_TYPE WHILE +%token SAMPLER1D SAMPLER2D SAMPLER3D SAMPLERCUBE SAMPLER1DSHADOW SAMPLER2DSHADOW + +%token SAMPLERRECTARB SAMPLERRECTSHADOWARB // ARB_texture_rectangle + +%token IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT BOOLCONSTANT +%token FIELD_SELECTION +%token LEFT_OP RIGHT_OP +%token INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP +%token AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN +%token MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN +%token SUB_ASSIGN + +%token LEFT_PAREN RIGHT_PAREN LEFT_BRACKET RIGHT_BRACKET LEFT_BRACE RIGHT_BRACE DOT +%token COMMA COLON EQUAL SEMICOLON BANG DASH TILDE PLUS STAR SLASH PERCENT +%token LEFT_ANGLE RIGHT_ANGLE VERTICAL_BAR CARET AMPERSAND QUESTION + +%type assignment_operator unary_operator +%type variable_identifier primary_expression postfix_expression +%type expression integer_expression assignment_expression +%type unary_expression multiplicative_expression additive_expression +%type relational_expression equality_expression +%type conditional_expression constant_expression +%type logical_or_expression logical_xor_expression logical_and_expression +%type shift_expression and_expression exclusive_or_expression inclusive_or_expression +%type function_call initializer condition conditionopt + +%type translation_unit function_definition +%type statement simple_statement +%type statement_list compound_statement +%type declaration_statement selection_statement expression_statement +%type declaration external_declaration +%type for_init_statement compound_statement_no_new_scope +%type selection_rest_statement for_rest_statement +%type iteration_statement jump_statement statement_no_new_scope +%type single_declaration init_declarator_list + +%type parameter_declaration parameter_declarator parameter_type_specifier +%type parameter_qualifier + +%type type_qualifier fully_specified_type type_specifier +%type type_specifier_nonarray +%type struct_specifier +%type struct_declarator +%type struct_declarator_list struct_declaration struct_declaration_list +%type function_header function_declarator function_identifier +%type function_header_with_parameters function_call_header +%type function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype +%type 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) { + parseContext.error($1.line, "undeclared identifier", $1.string->c_str(), ""); + parseContext.recover(); + TType type(EbtFloat); + TVariable* fakeVariable = new TVariable($1.string, type); + parseContext.symbolTable.insert(*fakeVariable); + variable = fakeVariable; + } else { + // This identifier can only be a variable type symbol + if (! symbol->isVariable()) { + parseContext.error($1.line, "variable expected", $1.string->c_str(), ""); + parseContext.recover(); + } + variable = static_cast(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 ) { + constUnion* constArray = variable->getConstPointer(); + TType t(variable->getType()); + $$ = parseContext.intermediate.addConstantUnion(constArray, t, $1.line); + } else + $$ = parseContext.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)) { + parseContext.error($1.line, " integer constant overflow", "", ""); + parseContext.recover(); + } + constUnion *unionArray = new constUnion[1]; + unionArray->setIConst($1.i); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $1.line); + } + | FLOATCONSTANT { + constUnion *unionArray = new constUnion[1]; + unionArray->setFConst($1.f); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $1.line); + } + | BOOLCONSTANT { + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst($1.b); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, 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()) + parseContext.error($2.line, " left of '[' is not of type array, matrix, or vector ", $1->getAsSymbolNode()->getSymbol().c_str(), ""); + else + parseContext.error($2.line, " left of '[' is not of type array, matrix, or vector ", "expression", ""); + parseContext.recover(); + } + if ($1->getType().getQualifier() == EvqConst && $3->getQualifier() == EvqConst) { + if ($1->isArray()) { // constant folding for arrays + $$ = parseContext.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 + $$ = parseContext.addConstVectorNode(fields, $1, $2.line); + } else if ($1->isMatrix()) { // constant folding for matrices + $$ = parseContext.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() ) { + parseContext.error($2.line, "", "[", "field selection out of range '%d'", $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst()); + parseContext.recover(); + } else { + if ($1->isArray()) { + if ($1->getType().getArraySize() == 0) { + if ($1->getType().getMaxArraySize() <= $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst()) { + if (parseContext.arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), true, $2.line)) + parseContext.recover(); + } else { + if (parseContext.arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), 0, false, $2.line)) + parseContext.recover(); + } + } else if ( $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() >= $1->getType().getArraySize()) { + parseContext.error($2.line, "", "[", "array index out of range '%d'", $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst()); + parseContext.recover(); + } + } + $$ = parseContext.intermediate.addIndex(EOpIndexDirect, $1, $3, $2.line); + } + } else { + if ($1->isArray() && $1->getType().getArraySize() == 0) { + parseContext.error($2.line, "", "[", "array must be redeclared with a size before being indexed with a variable"); + parseContext.recover(); + } + + $$ = parseContext.intermediate.addIndex(EOpIndexIndirect, $1, $3, $2.line); + } + } + if ($$ == 0) { + constUnion *unionArray = new constUnion[1]; + unionArray->setFConst(0.0f); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $2.line); + } else if ($1->isArray()) { + if ($1->getType().getStruct()) + $$->setType(TType($1->getType().getStruct(), $1->getType().getTypeName())); + else + $$->setType(TType($1->getBasicType(), EvqTemporary, $1->getNominalSize(), $1->isMatrix())); + + if ($1->getType().getQualifier() == EvqConst) + $$->getTypePointer()->changeQualifier(EvqConst); + } else if ($1->isMatrix() && $1->getType().getQualifier() == EvqConst) + $$->setType(TType($1->getBasicType(), EvqConst, $1->getNominalSize())); + else if ($1->isMatrix()) + $$->setType(TType($1->getBasicType(), EvqTemporary, $1->getNominalSize())); + else if ($1->isVector() && $1->getType().getQualifier() == EvqConst) + $$->setType(TType($1->getBasicType(), EvqConst)); + else if ($1->isVector()) + $$->setType(TType($1->getBasicType(), EvqTemporary)); + else + $$->setType($1->getType()); + } + | function_call { + $$ = $1; + } + | postfix_expression DOT FIELD_SELECTION { + if ($1->isArray()) { + parseContext.error($3.line, "cannot apply dot operator to an array", ".", ""); + parseContext.recover(); + } + + if ($1->isVector()) { + TVectorFields fields; + if (! parseContext.parseVectorFields(*$3.string, $1->getNominalSize(), fields, $3.line)) { + fields.num = 1; + fields.offsets[0] = 0; + parseContext.recover(); + } + + if ($1->getType().getQualifier() == EvqConst) { // constant folding for vector fields + $$ = parseContext.addConstVectorNode(fields, $1, $3.line); + if ($$ == 0) { + parseContext.recover(); + $$ = $1; + } + else + $$->setType(TType($1->getBasicType(), EvqConst, (int) (*$3.string).size())); + } else { + if (fields.num == 1) { + constUnion *unionArray = new constUnion[1]; + unionArray->setIConst(fields.offsets[0]); + TIntermTyped* index = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $3.line); + $$ = parseContext.intermediate.addIndex(EOpIndexDirect, $1, index, $2.line); + $$->setType(TType($1->getBasicType())); + } else { + TString vectorString = *$3.string; + TIntermTyped* index = parseContext.intermediate.addSwizzle(fields, $3.line); + $$ = parseContext.intermediate.addIndex(EOpVectorSwizzle, $1, index, $2.line); + $$->setType(TType($1->getBasicType(),EvqTemporary, (int) vectorString.size())); + } + } + } else if ($1->isMatrix()) { + TMatrixFields fields; + if (! parseContext.parseMatrixFields(*$3.string, $1->getNominalSize(), fields, $3.line)) { + fields.wholeRow = false; + fields.wholeCol = false; + fields.row = 0; + fields.col = 0; + parseContext.recover(); + } + + if (fields.wholeRow || fields.wholeCol) { + parseContext.error($2.line, " non-scalar fields not implemented yet", ".", ""); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setIConst(0); + TIntermTyped* index = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $3.line); + $$ = parseContext.intermediate.addIndex(EOpIndexDirect, $1, index, $2.line); + $$->setType(TType($1->getBasicType(), EvqTemporary, $1->getNominalSize())); + } else { + constUnion *unionArray = new constUnion[1]; + unionArray->setIConst(fields.col * $1->getNominalSize() + fields.row); + TIntermTyped* index = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $3.line); + $$ = parseContext.intermediate.addIndex(EOpIndexDirect, $1, index, $2.line); + $$->setType(TType($1->getBasicType())); + } + } else if ($1->getBasicType() == EbtStruct) { + bool fieldFound = false; + TTypeList* fields = $1->getType().getStruct(); + if (fields == 0) { + parseContext.error($2.line, "structure has no fields", "Internal Error", ""); + parseContext.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) { + $$ = parseContext.addConstStruct(*$3.string, $1, $2.line); + if ($$ == 0) { + parseContext.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()->changeQualifier(EvqConst); + } + } else { + constUnion *unionArray = new constUnion[1]; + unionArray->setIConst(i); + TIntermTyped* index = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $3.line); + $$ = parseContext.intermediate.addIndex(EOpIndexDirectStruct, $1, index, $2.line); + $$->setType(*(*fields)[i].type); + } + } else { + parseContext.error($2.line, " no such field in structure", $3.string->c_str(), ""); + parseContext.recover(); + $$ = $1; + } + } + } else { + parseContext.error($2.line, " field selection requires structure, vector, or matrix on left hand side", $3.string->c_str(), ""); + parseContext.recover(); + $$ = $1; + } + // don't delete $3.string, it's from the pool + } + | postfix_expression INC_OP { + if (parseContext.lValueErrorCheck($2.line, "++", $1)) + parseContext.recover(); + $$ = parseContext.intermediate.addUnaryMath(EOpPostIncrement, $1, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.unaryOpError($2.line, "++", $1->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + | postfix_expression DEC_OP { + if (parseContext.lValueErrorCheck($2.line, "--", $1)) + parseContext.recover(); + $$ = parseContext.intermediate.addUnaryMath(EOpPostDecrement, $1, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.unaryOpError($2.line, "--", $1->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + ; + +integer_expression + : expression { + if (parseContext.integerErrorCheck($1, "[]")) + parseContext.recover(); + $$ = $1; + } + ; + +function_call + : function_call_or_method { + TFunction* fnCall = $1.function; + TOperator op = fnCall->getBuiltInOp(); + + if (op == EOpArrayLength) { + if ($1.intermNode->getAsTyped() == 0 || $1.intermNode->getAsTyped()->getType().getArraySize() == 0) { + parseContext.error($1.line, "", fnCall->getName().c_str(), "array must be declared with a size before using this method"); + parseContext.recover(); + } + + constUnion *unionArray = new constUnion[1]; + unionArray->setIConst($1.intermNode->getAsTyped()->getType().getArraySize()); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $1.line); + } else 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); // use this to get the type back + if (parseContext.constructorErrorCheck($1.line, $1.intermNode, *fnCall, op, &type)) { + $$ = 0; + } else { + // + // It's a constructor, of type 'type'. + // + $$ = parseContext.addConstructor($1.intermNode, &type, op, fnCall, $1.line); + } + + if ($$ == 0) { + parseContext.recover(); + $$ = parseContext.intermediate.setAggregateOperator(0, op, $1.line); + } + $$->setType(type); + } else { + // + // Not a constructor. Find it in the symbol table. + // + const TFunction* fnCandidate; + bool builtIn; + fnCandidate = parseContext.findFunction($1.line, fnCall, &builtIn); + if (fnCandidate) { + // + // A declared function. But, it might still map to a built-in + // operation. + // + 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. + // + $$ = parseContext.intermediate.addUnaryMath(op, $1.intermNode, 0, parseContext.symbolTable); + if ($$ == 0) { + parseContext.error($1.intermNode->getLine(), " wrong operand type", "Internal Error", + "built in unary operator function. Type: %s", + static_cast($1.intermNode)->getCompleteString().c_str()); + YYERROR; + } + } else { + $$ = parseContext.intermediate.setAggregateOperator($1.intermAggregate, op, $1.line); + } + } else { + // This is a real function call + + $$ = parseContext.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; + TQualifierList& qualifierList = $$->getAsAggregate()->getQualifier(); + for (int i = 0; i < fnCandidate->getParamCount(); ++i) { + qual = (*fnCandidate)[i].type->getQualifier(); + if (qual == EvqOut || qual == EvqInOut) { + if (parseContext.lValueErrorCheck($$->getLine(), "assign", $$->getAsAggregate()->getSequence()[i]->getAsTyped())) { + parseContext.error($1.intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error", ""); + parseContext.recover(); + } + } + qualifierList.push_back(qual); + } + } + $$->setType(fnCandidate->getReturnType()); + } else { + // error message was put out by PaFindFunction() + // Put on a dummy node for error recovery + constUnion *unionArray = new constUnion[1]; + unionArray->setFConst(0.0f); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $1.line); + parseContext.recover(); + } + } + delete fnCall; + } + ; + +function_call_or_method + : function_call_generic { + $$ = $1; + } + | postfix_expression DOT function_call_generic { + if ($1->isArray() && $3.function->getName() == "length") { + // + // implement array.length() + // + if (parseContext.extensionErrorCheck($3.line, "GL_3DL_array_objects")) { + parseContext.recover(); + $$ = $3; + } else { + $$ = $3; + $$.intermNode = $1; + $$.function->relateToOperator(EOpArrayLength); + } + } else { + parseContext.error($3.line, "methods are not supported", "", ""); + parseContext.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 = parseContext.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 { + // + // Constructor + // + if ($1.array) { + if (parseContext.extensionErrorCheck($1.line, "GL_3DL_array_objects")) { + parseContext.recover(); + $1.setArray(false); + } + } + + if ($1.userDef) { + TString tempString = ""; + TType type($1); + TFunction *function = new TFunction(&tempString, type, EOpConstructStruct); + $$ = function; + } else { + TOperator op = EOpNull; + 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; + } + if (op == EOpNull) { + parseContext.error($1.line, "cannot construct this type", TType::getBasicString($1.type), ""); + parseContext.recover(); + $1.type = EbtFloat; + op = EOpConstructFloat; + } + TString tempString = ""; + TType type($1); + TFunction *function = new TFunction(&tempString, type, op); + $$ = function; + } + } + | IDENTIFIER { + if (parseContext.reservedErrorCheck($1.line, *$1.string)) + parseContext.recover(); + TType type(EbtVoid); + TFunction *function = new TFunction($1.string, type); + $$ = function; + } + | FIELD_SELECTION { + if (parseContext.reservedErrorCheck($1.line, *$1.string)) + parseContext.recover(); + TType type(EbtVoid); + TFunction *function = new TFunction($1.string, type); + $$ = function; + } + ; + +unary_expression + : postfix_expression { + $$ = $1; + } + | INC_OP unary_expression { + if (parseContext.lValueErrorCheck($1.line, "++", $2)) + parseContext.recover(); + $$ = parseContext.intermediate.addUnaryMath(EOpPreIncrement, $2, $1.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.unaryOpError($1.line, "++", $2->getCompleteString()); + parseContext.recover(); + $$ = $2; + } + } + | DEC_OP unary_expression { + if (parseContext.lValueErrorCheck($1.line, "--", $2)) + parseContext.recover(); + $$ = parseContext.intermediate.addUnaryMath(EOpPreDecrement, $2, $1.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.unaryOpError($1.line, "--", $2->getCompleteString()); + parseContext.recover(); + $$ = $2; + } + } + | unary_operator unary_expression { + if ($1.op != EOpNull) { + $$ = parseContext.intermediate.addUnaryMath($1.op, $2, $1.line, parseContext.symbolTable); + if ($$ == 0) { + char* errorOp = ""; + switch($1.op) { + case EOpNegative: errorOp = "-"; break; + case EOpLogicalNot: errorOp = "!"; break; + case EOpBitwiseNot: errorOp = "~"; break; + default: break; + } + parseContext.unaryOpError($1.line, errorOp, $2->getCompleteString()); + parseContext.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; } + | TILDE { PACK_UNPACK_ONLY("~", $1.line); + $$.line = $1.line; $$.op = EOpBitwiseNot; } + ; +// 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); + $$ = parseContext.intermediate.addBinaryMath(EOpMul, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "*", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + | multiplicative_expression SLASH unary_expression { + FRAG_VERT_ONLY("/", $2.line); + $$ = parseContext.intermediate.addBinaryMath(EOpDiv, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "/", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + | multiplicative_expression PERCENT unary_expression { + PACK_UNPACK_ONLY("%", $2.line); + $$ = parseContext.intermediate.addBinaryMath(EOpMod, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "%", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + ; + +additive_expression + : multiplicative_expression { $$ = $1; } + | additive_expression PLUS multiplicative_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpAdd, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "+", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + | additive_expression DASH multiplicative_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpSub, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "-", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + ; + +shift_expression + : additive_expression { $$ = $1; } + | shift_expression LEFT_OP additive_expression { + PACK_UNPACK_ONLY("<<", $2.line); + $$ = parseContext.intermediate.addBinaryMath(EOpLeftShift, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "<<", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + | shift_expression RIGHT_OP additive_expression { + PACK_UNPACK_ONLY(">>", $2.line); + $$ = parseContext.intermediate.addBinaryMath(EOpRightShift, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, ">>", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + ; + +relational_expression + : shift_expression { $$ = $1; } + | relational_expression LEFT_ANGLE shift_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpLessThan, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "<", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst(false); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line); + } + } + | relational_expression RIGHT_ANGLE shift_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpGreaterThan, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, ">", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst(false); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line); + } + } + | relational_expression LE_OP shift_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpLessThanEqual, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "<=", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst(false); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line); + } + } + | relational_expression GE_OP shift_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpGreaterThanEqual, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, ">=", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst(false); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line); + } + } + ; + +equality_expression + : relational_expression { $$ = $1; } + | equality_expression EQ_OP relational_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpEqual, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "==", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst(false); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line); + } else if (($1->isArray() || $3->isArray()) && parseContext.extensionErrorCheck($2.line, "GL_3DL_array_objects")) + parseContext.recover(); + } + | equality_expression NE_OP relational_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpNotEqual, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "!=", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst(false); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line); + } else if (($1->isArray() || $3->isArray()) && parseContext.extensionErrorCheck($2.line, "GL_3DL_array_objects")) + parseContext.recover(); + } + ; + +and_expression + : equality_expression { $$ = $1; } + | and_expression AMPERSAND equality_expression { + PACK_UNPACK_ONLY("&", $2.line); + $$ = parseContext.intermediate.addBinaryMath(EOpAnd, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "&", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + ; + +exclusive_or_expression + : and_expression { $$ = $1; } + | exclusive_or_expression CARET and_expression { + PACK_UNPACK_ONLY("^", $2.line); + $$ = parseContext.intermediate.addBinaryMath(EOpExclusiveOr, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "^", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + ; + +inclusive_or_expression + : exclusive_or_expression { $$ = $1; } + | inclusive_or_expression VERTICAL_BAR exclusive_or_expression { + PACK_UNPACK_ONLY("|", $2.line); + $$ = parseContext.intermediate.addBinaryMath(EOpInclusiveOr, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "|", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + ; + +logical_and_expression + : inclusive_or_expression { $$ = $1; } + | logical_and_expression AND_OP inclusive_or_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpLogicalAnd, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "&&", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst(false); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line); + } + } + ; + +logical_xor_expression + : logical_and_expression { $$ = $1; } + | logical_xor_expression XOR_OP logical_and_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpLogicalXor, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "^^", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst(false); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line); + } + } + ; + +logical_or_expression + : logical_xor_expression { $$ = $1; } + | logical_or_expression OR_OP logical_xor_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpLogicalOr, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "||", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst(false); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line); + } + } + ; + +conditional_expression + : logical_or_expression { $$ = $1; } + | logical_or_expression QUESTION expression COLON assignment_expression { + if (parseContext.boolErrorCheck($2.line, $1)) + parseContext.recover(); + + $$ = parseContext.intermediate.addSelection($1, $3, $5, $2.line); + if ($3->getType() != $5->getType()) + $$ = 0; + + if ($$ == 0) { + parseContext.binaryOpError($2.line, ":", $3->getCompleteString(), $5->getCompleteString()); + parseContext.recover(); + $$ = $5; + } + } + ; + +assignment_expression + : conditional_expression { $$ = $1; } + | unary_expression assignment_operator assignment_expression { + if (parseContext.lValueErrorCheck($2.line, "assign", $1)) + parseContext.recover(); + $$ = parseContext.intermediate.addAssign($2.op, $1, $3, $2.line); + if ($$ == 0) { + parseContext.assignError($2.line, "assign", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } else if (($1->isArray() || $3->isArray()) && parseContext.extensionErrorCheck($2.line, "GL_3DL_array_objects")) + parseContext.recover(); + } + ; + +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; } + | MOD_ASSIGN { PACK_UNPACK_ONLY("%=", $1.line); $$.line = $1.line; $$.op = EOpModAssign; } + | ADD_ASSIGN { $$.line = $1.line; $$.op = EOpAddAssign; } + | SUB_ASSIGN { $$.line = $1.line; $$.op = EOpSubAssign; } + | LEFT_ASSIGN { PACK_UNPACK_ONLY("<<=", $1.line); $$.line = $1.line; $$.op = EOpLeftShiftAssign; } + | RIGHT_ASSIGN { PACK_UNPACK_ONLY("<<=", $1.line); $$.line = $1.line; $$.op = EOpRightShiftAssign; } + | AND_ASSIGN { PACK_UNPACK_ONLY("&=", $1.line); $$.line = $1.line; $$.op = EOpAndAssign; } + | XOR_ASSIGN { PACK_UNPACK_ONLY("^=", $1.line); $$.line = $1.line; $$.op = EOpExclusiveOrAssign; } + | OR_ASSIGN { PACK_UNPACK_ONLY("|=", $1.line); $$.line = $1.line; $$.op = EOpInclusiveOrAssign; } + ; + +expression + : assignment_expression { + $$ = $1; + } + | expression COMMA assignment_expression { + $$ = parseContext.intermediate.addComma($1, $3, $2.line); + if ($$ == 0) { + parseContext.binaryOpError($2.line, ",", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $3; + } + } + ; + +constant_expression + : conditional_expression { + if (parseContext.constErrorCheck($1)) + parseContext.recover(); + $$ = $1; + } + ; + +declaration + : function_prototype SEMICOLON { $$ = 0; } + | init_declarator_list SEMICOLON { + if ($1.intermAggregate) + $1.intermAggregate->setOperator(EOpSequence); + $$ = $1.intermAggregate; + } + ; + +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(parseContext.symbolTable.find($1->getMangledName())); + if (prevDec) { + if (prevDec->getReturnType() != $1->getReturnType()) { + parseContext.error($2.line, "overloaded functions must have the same return type", $1->getReturnType().getBasicString(), ""); + parseContext.recover(); + } + for (int i = 0; i < prevDec->getParamCount(); ++i) { + if ((*prevDec)[i].type->getQualifier() != (*$1)[i].type->getQualifier()) { + parseContext.error($2.line, "overloaded functions must have the same parameter qualifiers", (*$1)[i].type->getQualifierString(), ""); + parseContext.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; + + parseContext.symbolTable.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 + // + parseContext.error($2.line, "cannot be an argument type except for '(void)'", "void", ""); + parseContext.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) { + parseContext.error($2.line, "no qualifiers allowed for function return", getQualifierString($1.qualifier), ""); + parseContext.recover(); + } + // make sure a sampler is not involved as well... + if (parseContext.structQualifierErrorCheck($2.line, $1)) + parseContext.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; + } + ; + +parameter_declarator + // Type + name + : type_specifier IDENTIFIER { + if ($1.type == EbtVoid) { + parseContext.error($2.line, "illegal use of type 'void'", $2.string->c_str(), ""); + parseContext.recover(); + } + if (parseContext.reservedErrorCheck($2.line, *$2.string)) + parseContext.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 (parseContext.arrayTypeErrorCheck($3.line, $1)) + parseContext.recover(); + + if (parseContext.reservedErrorCheck($2.line, *$2.string)) + parseContext.recover(); + + int size; + if (parseContext.arraySizeErrorCheck($3.line, $4, size)) + parseContext.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 (parseContext.paramErrorCheck($3.line, $1.qualifier, $2, $$.param.type)) + parseContext.recover(); + } + | parameter_qualifier parameter_declarator { + $$ = $2; + if (parseContext.parameterSamplerErrorCheck($2.line, $1, *$2.param.type)) + parseContext.recover(); + if (parseContext.paramErrorCheck($2.line, EvqTemporary, $1, $$.param.type)) + parseContext.recover(); + } + // + // Only type + // + | type_qualifier parameter_qualifier parameter_type_specifier { + $$ = $3; + if (parseContext.paramErrorCheck($3.line, $1.qualifier, $2, $$.param.type)) + parseContext.recover(); + } + | parameter_qualifier parameter_type_specifier { + $$ = $2; + if (parseContext.parameterSamplerErrorCheck($2.line, $1, *$2.param.type)) + parseContext.recover(); + if (parseContext.paramErrorCheck($2.line, EvqTemporary, $1, $$.param.type)) + parseContext.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 { + $$ = $1; + if (parseContext.structQualifierErrorCheck($3.line, $$.type)) + parseContext.recover(); + + if (parseContext.nonInitConstErrorCheck($3.line, *$3.string, $$.type)) + parseContext.recover(); + + if (parseContext.nonInitErrorCheck($3.line, *$3.string, $$.type)) + parseContext.recover(); + } + | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET RIGHT_BRACKET { + if (parseContext.structQualifierErrorCheck($3.line, $1.type)) + parseContext.recover(); + + if (parseContext.nonInitConstErrorCheck($3.line, *$3.string, $1.type)) + parseContext.recover(); + + $$ = $1; + + if (parseContext.arrayTypeErrorCheck($4.line, $1.type) || parseContext.arrayQualifierErrorCheck($4.line, $1.type)) + parseContext.recover(); + else { + $1.type.setArray(true); + TVariable* variable; + if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable)) + parseContext.recover(); + } + } + | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { + if (parseContext.structQualifierErrorCheck($3.line, $1.type)) + parseContext.recover(); + + if (parseContext.nonInitConstErrorCheck($3.line, *$3.string, $1.type)) + parseContext.recover(); + + $$ = $1; + + if (parseContext.arrayTypeErrorCheck($4.line, $1.type) || parseContext.arrayQualifierErrorCheck($4.line, $1.type)) + parseContext.recover(); + else { + int size; + if (parseContext.arraySizeErrorCheck($4.line, $5, size)) + parseContext.recover(); + $1.type.setArray(true, size); + TVariable* variable; + if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable)) + parseContext.recover(); + } + } + | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET RIGHT_BRACKET EQUAL initializer { + if (parseContext.structQualifierErrorCheck($3.line, $1.type)) + parseContext.recover(); + + $$ = $1; + + TVariable* variable = 0; + if (parseContext.arrayTypeErrorCheck($4.line, $1.type) || parseContext.arrayQualifierErrorCheck($4.line, $1.type)) + parseContext.recover(); + else { + $1.type.setArray(true, $7->getType().getArraySize()); + if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable)) + parseContext.recover(); + } + + if (parseContext.extensionErrorCheck($$.line, "GL_3DL_array_objects")) + parseContext.recover(); + else { + TIntermNode* intermNode; + if (!parseContext.executeInitializer($3.line, *$3.string, $1.type, $7, intermNode, variable)) { + // + // build the intermediate representation + // + if (intermNode) + $$.intermAggregate = parseContext.intermediate.growAggregate($1.intermNode, intermNode, $6.line); + else + $$.intermAggregate = $1.intermAggregate; + } else { + parseContext.recover(); + $$.intermAggregate = 0; + } + } + } + | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer { + if (parseContext.structQualifierErrorCheck($3.line, $1.type)) + parseContext.recover(); + + $$ = $1; + + TVariable* variable = 0; + if (parseContext.arrayTypeErrorCheck($4.line, $1.type) || parseContext.arrayQualifierErrorCheck($4.line, $1.type)) + parseContext.recover(); + else { + int size; + if (parseContext.arraySizeErrorCheck($4.line, $5, size)) + parseContext.recover(); + $1.type.setArray(true, size); + if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable)) + parseContext.recover(); + } + + if (parseContext.extensionErrorCheck($$.line, "GL_3DL_array_objects")) + parseContext.recover(); + else { + TIntermNode* intermNode; + if (!parseContext.executeInitializer($3.line, *$3.string, $1.type, $8, intermNode, variable)) { + // + // build the intermediate representation + // + if (intermNode) + $$.intermAggregate = parseContext.intermediate.growAggregate($1.intermNode, intermNode, $7.line); + else + $$.intermAggregate = $1.intermAggregate; + } else { + parseContext.recover(); + $$.intermAggregate = 0; + } + } + } + | init_declarator_list COMMA IDENTIFIER EQUAL initializer { + if (parseContext.structQualifierErrorCheck($3.line, $1.type)) + parseContext.recover(); + + $$ = $1; + + TIntermNode* intermNode; + if (!parseContext.executeInitializer($3.line, *$3.string, $1.type, $5, intermNode)) { + // + // build the intermediate representation + // + if (intermNode) + $$.intermAggregate = parseContext.intermediate.growAggregate($1.intermNode, intermNode, $4.line); + else + $$.intermAggregate = $1.intermAggregate; + } else { + parseContext.recover(); + $$.intermAggregate = 0; + } + } + ; + +single_declaration + : fully_specified_type { + $$.type = $1; + $$.intermAggregate = 0; + } + | fully_specified_type IDENTIFIER { + $$.intermAggregate = 0; + $$.type = $1; + + if (parseContext.structQualifierErrorCheck($2.line, $$.type)) + parseContext.recover(); + + if (parseContext.nonInitConstErrorCheck($2.line, *$2.string, $$.type)) + parseContext.recover(); + + if (parseContext.nonInitErrorCheck($2.line, *$2.string, $$.type)) + parseContext.recover(); + } + | fully_specified_type IDENTIFIER LEFT_BRACKET RIGHT_BRACKET { + $$.intermAggregate = 0; + if (parseContext.structQualifierErrorCheck($2.line, $1)) + parseContext.recover(); + + if (parseContext.nonInitConstErrorCheck($2.line, *$2.string, $1)) + parseContext.recover(); + + $$.type = $1; + + if (parseContext.arrayTypeErrorCheck($3.line, $1) || parseContext.arrayQualifierErrorCheck($3.line, $1)) + parseContext.recover(); + else { + $1.setArray(true); + TVariable* variable; + if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable)) + parseContext.recover(); + } + } + | fully_specified_type IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { + $$.intermAggregate = 0; + if (parseContext.structQualifierErrorCheck($2.line, $1)) + parseContext.recover(); + + if (parseContext.nonInitConstErrorCheck($2.line, *$2.string, $1)) + parseContext.recover(); + + $$.type = $1; + + if (parseContext.arrayTypeErrorCheck($3.line, $1) || parseContext.arrayQualifierErrorCheck($3.line, $1)) + parseContext.recover(); + else { + int size; + if (parseContext.arraySizeErrorCheck($3.line, $4, size)) + parseContext.recover(); + + $1.setArray(true, size); + TVariable* variable; + if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable)) + parseContext.recover(); + } + } + | fully_specified_type IDENTIFIER LEFT_BRACKET RIGHT_BRACKET EQUAL initializer { + $$.intermAggregate = 0; + + if (parseContext.structQualifierErrorCheck($2.line, $1)) + parseContext.recover(); + + $$.type = $1; + + TVariable* variable = 0; + if (parseContext.arrayTypeErrorCheck($3.line, $1) || parseContext.arrayQualifierErrorCheck($3.line, $1)) + parseContext.recover(); + else { + $1.setArray(true, $6->getType().getArraySize()); + if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable)) + parseContext.recover(); + } + + if (parseContext.extensionErrorCheck($$.line, "GL_3DL_array_objects")) + parseContext.recover(); + else { + TIntermNode* intermNode; + if (!parseContext.executeInitializer($2.line, *$2.string, $1, $6, intermNode, variable)) { + // + // Build intermediate representation + // + if (intermNode) + $$.intermAggregate = parseContext.intermediate.makeAggregate(intermNode, $5.line); + else + $$.intermAggregate = 0; + } else { + parseContext.recover(); + $$.intermAggregate = 0; + } + } + } + | fully_specified_type IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer { + $$.intermAggregate = 0; + + if (parseContext.structQualifierErrorCheck($2.line, $1)) + parseContext.recover(); + + $$.type = $1; + + TVariable* variable = 0; + if (parseContext.arrayTypeErrorCheck($3.line, $1) || parseContext.arrayQualifierErrorCheck($3.line, $1)) + parseContext.recover(); + else { + int size; + if (parseContext.arraySizeErrorCheck($3.line, $4, size)) + parseContext.recover(); + + $1.setArray(true, size); + if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable)) + parseContext.recover(); + } + + if (parseContext.extensionErrorCheck($$.line, "GL_3DL_array_objects")) + parseContext.recover(); + else { + TIntermNode* intermNode; + if (!parseContext.executeInitializer($2.line, *$2.string, $1, $7, intermNode, variable)) { + // + // Build intermediate representation + // + if (intermNode) + $$.intermAggregate = parseContext.intermediate.makeAggregate(intermNode, $6.line); + else + $$.intermAggregate = 0; + } else { + parseContext.recover(); + $$.intermAggregate = 0; + } + } + } + | fully_specified_type IDENTIFIER EQUAL initializer { + if (parseContext.structQualifierErrorCheck($2.line, $1)) + parseContext.recover(); + + $$.type = $1; + + TIntermNode* intermNode; + if (!parseContext.executeInitializer($2.line, *$2.string, $1, $4, intermNode)) { + // + // Build intermediate representation + // + if (intermNode) + $$.intermAggregate = parseContext.intermediate.makeAggregate(intermNode, $3.line); + else + $$.intermAggregate = 0; + } else { + parseContext.recover(); + $$.intermAggregate = 0; + } + } + +// +// 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 buffer_declaration +//%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 (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "input")) +// parseContext.recover(); +// UNPACK_ONLY("input", $1.line); +// $$.qualifier = EvqInput; +// } +// | OUTPUT { +// if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "output")) +// parseContext.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 (parseContext.reservedErrorCheck($2.line, *$2.string, parseContext)) +// parseContext.recover(); +// $$.variable = new TVariable($2.string, $1); +// if (! parseContext.symbolTable.insert(*$$.variable)) { +// parseContext.error($2.line, "redefinition", $$.variable->getName().c_str(), ""); +// parseContext.recover(); +// // don't have to delete $$.variable, the pool pop will take care of it +// } +// } +// ; + +fully_specified_type + : type_specifier { + $$ = $1; + + if ($1.array) { + if (parseContext.extensionErrorCheck($1.line, "GL_3DL_array_objects")) { + parseContext.recover(); + $1.setArray(false); + } + } + } + | type_qualifier type_specifier { + if ($2.array && parseContext.extensionErrorCheck($2.line, "GL_3DL_array_objects")) { + parseContext.recover(); + $2.setArray(false); + } + if ($2.array && parseContext.arrayQualifierErrorCheck($2.line, $1)) { + parseContext.recover(); + $2.setArray(false); + } + + if ($1.qualifier == EvqAttribute && + ($2.type == EbtBool || $2.type == EbtInt)) { + parseContext.error($2.line, "cannot be bool or int", getQualifierString($1.qualifier), ""); + parseContext.recover(); + } + if (($1.qualifier == EvqVaryingIn || $1.qualifier == EvqVaryingOut) && + ($2.type == EbtBool || $2.type == EbtInt)) { + parseContext.error($2.line, "cannot be bool or int", getQualifierString($1.qualifier), ""); + parseContext.recover(); + } + $$ = $2; + $$.qualifier = $1.qualifier; + } + ; + +type_qualifier + : CONST_QUAL { + $$.setBasic(EbtVoid, EvqConst, $1.line); + } + | ATTRIBUTE { + VERTEX_ONLY("attribute", $1.line); + if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "attribute")) + parseContext.recover(); + $$.setBasic(EbtVoid, EvqAttribute, $1.line); + } + | VARYING { + if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "varying")) + parseContext.recover(); + if (parseContext.language == EShLangVertex) + $$.setBasic(EbtVoid, EvqVaryingOut, $1.line); + else + $$.setBasic(EbtVoid, EvqVaryingIn, $1.line); + } + | UNIFORM { + if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "uniform")) + parseContext.recover(); + $$.setBasic(EbtVoid, EvqUniform, $1.line); + } + ; + +type_specifier + : type_specifier_nonarray { + $$ = $1; + } + | type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET { + $$ = $1; + + if (parseContext.arrayTypeErrorCheck($2.line, $1)) + parseContext.recover(); + else { + int size; + if (parseContext.arraySizeErrorCheck($2.line, $3, size)) + parseContext.recover(); + $$.setArray(true, size); + } + } + ; + +type_specifier_nonarray + : VOID_TYPE { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtVoid, qual, $1.line); + } + | FLOAT_TYPE { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + } + | INT_TYPE { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, $1.line); + } + | BOOL_TYPE { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, $1.line); + } +// | UNSIGNED INT_TYPE { +// PACK_UNPACK_ONLY("unsigned", $1.line); +// TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; +// $$.setBasic(EbtInt, qual, $1.line); +// } + | VEC2 { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(2); + } + | VEC3 { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(3); + } + | VEC4 { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(4); + } + | BVEC2 { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, $1.line); + $$.setAggregate(2); + } + | BVEC3 { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, $1.line); + $$.setAggregate(3); + } + | BVEC4 { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, $1.line); + $$.setAggregate(4); + } + | IVEC2 { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, $1.line); + $$.setAggregate(2); + } + | IVEC3 { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, $1.line); + $$.setAggregate(3); + } + | IVEC4 { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, $1.line); + $$.setAggregate(4); + } + | MATRIX2 { + FRAG_VERT_ONLY("mat2", $1.line); + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(2, true); + } + | MATRIX3 { + FRAG_VERT_ONLY("mat3", $1.line); + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(3, true); + } + | MATRIX4 { + FRAG_VERT_ONLY("mat4", $1.line); + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(4, true); + } + | SAMPLER1D { + FRAG_VERT_ONLY("sampler1D", $1.line); + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler1D, qual, $1.line); + } + | SAMPLER2D { + FRAG_VERT_ONLY("sampler2D", $1.line); + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler2D, qual, $1.line); + } + | SAMPLER3D { + FRAG_VERT_ONLY("sampler3D", $1.line); + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler3D, qual, $1.line); + } + | SAMPLERCUBE { + FRAG_VERT_ONLY("samplerCube", $1.line); + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSamplerCube, qual, $1.line); + } + | SAMPLER1DSHADOW { + FRAG_VERT_ONLY("sampler1DShadow", $1.line); + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler1DShadow, qual, $1.line); + } + | SAMPLER2DSHADOW { + FRAG_VERT_ONLY("sampler2DShadow", $1.line); + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler2DShadow, qual, $1.line); + } + | SAMPLERRECTARB { + // ARB_texture_rectangle + + FRAG_VERT_ONLY("samplerRectARB", $1.line); + if (parseContext.extensionErrorCheck($1.line, "GL_ARB_texture_rectangle")) + parseContext.recover(); + + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSamplerRect, qual, $1.line); + } + | SAMPLERRECTSHADOWARB { + // ARB_texture_rectangle + + FRAG_VERT_ONLY("samplerRectShadowARB", $1.line); + if (parseContext.extensionErrorCheck($1.line, "GL_ARB_texture_rectangle")) + parseContext.recover(); + + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSamplerRectShadow, qual, $1.line); + } + | struct_specifier { + FRAG_VERT_ONLY("struct", $1.line); + $$ = $1; + $$.qualifier = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + } + | TYPE_NAME { + // + // This is for user defined type names. The lexical phase looked up the + // type. + // + TType& structure = static_cast($1.symbol)->getType(); + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtStruct, qual, $1.line); + $$.userDef = &structure; + } + ; + +struct_specifier + : STRUCT IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE { + TType* structure = new TType($4, *$2.string); + TVariable* userTypeDef = new TVariable($2.string, *structure, true); + if (! parseContext.symbolTable.insert(*userTypeDef)) { + parseContext.error($2.line, "redefinition", $2.string->c_str(), "struct"); + parseContext.recover(); + } + $$.setBasic(EbtStruct, EvqTemporary, $1.line); + $$.userDef = structure; + } + | STRUCT LEFT_BRACE struct_declaration_list RIGHT_BRACE { + TType* structure = new TType($3, TString("")); + $$.setBasic(EbtStruct, EvqTemporary, $1.line); + $$.userDef = structure; + } + ; + +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()) { + parseContext.error((*$2)[i].line, "duplicate field name in structure:", "struct", (*$2)[i].type->getFieldName().c_str()); + parseContext.recover(); + } + } + $$->push_back((*$2)[i]); + } + } + ; + +struct_declaration + : type_specifier struct_declarator_list SEMICOLON { + $$ = $2; + + if (parseContext.voidErrorCheck($1.line, (*$2)[0].type->getFieldName(), $1)) { + parseContext.recover(); + } + for (unsigned int i = 0; i < $$->size(); ++i) { + // + // Careful not to replace already know aspects of type, like array-ness + // + (*$$)[i].type->setType($1.type, $1.size, $1.matrix, $1.userDef); + + // don't allow arrays of arrays + if ((*$$)[i].type->isArray()) { + if (parseContext.arrayTypeErrorCheck($1.line, $1)) + parseContext.recover(); + } + if ($1.array) + (*$$)[i].type->setArraySize($1.arraySize); + if ($1.userDef) + (*$$)[i].type->setTypeName($1.userDef->getTypeName()); + } + } + ; + +struct_declarator_list + : struct_declarator { + $$ = NewPoolTTypeList(); + $$->push_back($1); + } + | struct_declarator_list COMMA struct_declarator { + $$->push_back($3); + } + ; + +struct_declarator + : IDENTIFIER { + $$.type = new TType(EbtVoid); + $$.line = $1.line; + $$.type->setFieldName(*$1.string); + } + | IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { + $$.type = new TType(EbtVoid); + $$.line = $1.line; + $$.type->setFieldName(*$1.string); + + int size; + if (parseContext.arraySizeErrorCheck($2.line, $3, size)) + parseContext.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 { parseContext.symbolTable.push(); } statement_list { parseContext.symbolTable.pop(); } RIGHT_BRACE { + if ($3 != 0) + $3->setOperator(EOpSequence); + $$ = $3; + } + ; + +statement_no_new_scope + : compound_statement_no_new_scope { $$ = $1; } + | simple_statement { $$ = $1; } + ; + +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->setOperator(EOpSequence); + $$ = $2; + } + ; + +statement_list + : statement { + $$ = parseContext.intermediate.makeAggregate($1, 0); + } + | statement_list statement { + $$ = parseContext.intermediate.growAggregate($1, $2, 0); + } + ; + +expression_statement + : SEMICOLON { $$ = 0; } + | expression SEMICOLON { $$ = static_cast($1); } + ; + +selection_statement + : IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement { + if (parseContext.boolErrorCheck($1.line, $3)) + parseContext.recover(); + $$ = parseContext.intermediate.addSelection($3, $5, $1.line); + } + ; + +selection_rest_statement + : statement ELSE statement { + $$.node1 = $1; + $$.node2 = $3; + } + | statement { + $$.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 (parseContext.boolErrorCheck($1->getLine(), $1)) + parseContext.recover(); + } + | fully_specified_type IDENTIFIER EQUAL initializer { + TIntermNode* intermNode; + if (parseContext.structQualifierErrorCheck($2.line, $1)) + parseContext.recover(); + if (parseContext.boolErrorCheck($2.line, $1)) + parseContext.recover(); + + if (!parseContext.executeInitializer($2.line, *$2.string, $1, $4, intermNode)) + $$ = $4; + else { + parseContext.recover(); + $$ = 0; + } + } + ; + +iteration_statement + : WHILE LEFT_PAREN { parseContext.symbolTable.push(); ++parseContext.loopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope { + parseContext.symbolTable.pop(); + $$ = parseContext.intermediate.addLoop($6, $4, 0, true, $1.line); + --parseContext.loopNestingLevel; + } + | DO { ++parseContext.loopNestingLevel; } statement WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON { + if (parseContext.boolErrorCheck($8.line, $6)) + parseContext.recover(); + + $$ = parseContext.intermediate.addLoop($3, $6, 0, false, $4.line); + --parseContext.loopNestingLevel; + } + | FOR LEFT_PAREN { parseContext.symbolTable.push(); ++parseContext.loopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope { + parseContext.symbolTable.pop(); + $$ = parseContext.intermediate.makeAggregate($4, $2.line); + $$ = parseContext.intermediate.growAggregate( + $$, + parseContext.intermediate.addLoop($7, reinterpret_cast($5.node1), reinterpret_cast($5.node2), true, $1.line), + $1.line); + $$->getAsAggregate()->setOperator(EOpSequence); + --parseContext.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 (parseContext.loopNestingLevel <= 0) { + parseContext.error($1.line, "continue statement only allowed in loops", "", ""); + parseContext.recover(); + } + $$ = parseContext.intermediate.addBranch(EOpContinue, $1.line); + } + | BREAK SEMICOLON { + if (parseContext.loopNestingLevel <= 0) { + parseContext.error($1.line, "break statement only allowed in loops", "", ""); + parseContext.recover(); + } + $$ = parseContext.intermediate.addBranch(EOpBreak, $1.line); + } + | RETURN SEMICOLON { + $$ = parseContext.intermediate.addBranch(EOpReturn, $1.line); + if (parseContext.currentFunctionType->getBasicType() != EbtVoid) { + parseContext.error($1.line, "non-void function must return a value", "return", ""); + parseContext.recover(); + } + } + | RETURN expression SEMICOLON { + $$ = parseContext.intermediate.addBranch(EOpReturn, $2, $1.line); + parseContext.functionReturnsValue = true; + if (parseContext.currentFunctionType->getBasicType() == EbtVoid) { + parseContext.error($1.line, "void function cannot return a value", "return", ""); + parseContext.recover(); + } else if (*(parseContext.currentFunctionType) != $2->getType()) { + parseContext.error($1.line, "function return is not matching type:", "return", ""); + parseContext.recover(); + } + } + | DISCARD SEMICOLON { + FRAG_ONLY("discard", $1.line); + $$ = parseContext.intermediate.addBranch(EOpKill, $1.line); + } + ; + +// Grammar Note: No 'goto'. Gotos are not supported. + +translation_unit + : external_declaration { + $$ = $1; + parseContext.treeRoot = $$; + } + | translation_unit external_declaration { + $$ = parseContext.intermediate.growAggregate($1, $2, 0); + parseContext.treeRoot = $$; + } + ; + +external_declaration + : function_definition { + $$ = $1; + } + | declaration { + $$ = $1; + } + ; + +function_definition + : function_prototype { + TFunction& function = *($1.function); + TFunction* prevDec = static_cast(parseContext.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. + // + parseContext.error($1.line, "function already has a body", function.getName().c_str(), ""); + parseContext.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) { + parseContext.error($1.line, "function cannot take any parameter(s)", function.getName().c_str(), ""); + parseContext.recover(); + } + if (function.getReturnType().getBasicType() != EbtVoid) { + parseContext.error($1.line, "", function.getReturnType().getBasicString(), "main function cannot return a value"); + parseContext.recover(); + } + } + + // + // New symbol table scope for body of function plus its arguments + // + parseContext.symbolTable.push(); + + // + // Remember the return type for later checking for RETURN statements. + // + parseContext.currentFunctionType = &(prevDec->getReturnType()); + parseContext.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++) { + TParameter& param = function[i]; + if (param.name != 0) { + TVariable *variable = new TVariable(param.name, *param.type); + // + // Insert the parameters with name in the symbol table. + // + if (! parseContext.symbolTable.insert(*variable)) { + parseContext.error($1.line, "redefinition", variable->getName().c_str(), ""); + parseContext.recover(); + delete variable; + } + // + // Transfer ownership of name pointer to symbol table. + // + param.name = 0; + + // + // Add the parameter to the HIL + // + paramNodes = parseContext.intermediate.growAggregate( + paramNodes, + parseContext.intermediate.addSymbol(variable->getUniqueId(), + variable->getName(), + variable->getType(), $1.line), + $1.line); + } else { + paramNodes = parseContext.intermediate.growAggregate(paramNodes, parseContext.intermediate.addSymbol(0, "", *param.type, $1.line), $1.line); + } + } + parseContext.intermediate.setAggregateOperator(paramNodes, EOpParameters, $1.line); + $1.intermAggregate = paramNodes; + parseContext.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 (parseContext.currentFunctionType->getBasicType() != EbtVoid && ! parseContext.functionReturnsValue) { + parseContext.error($1.line, "function does not return a value:", "", $1.function->getName().c_str()); + parseContext.recover(); + } + parseContext.symbolTable.pop(); + $$ = parseContext.intermediate.growAggregate($1.intermAggregate, $3, 0); + parseContext.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(parseContext.contextPragma.optimize); + $$->getAsAggregate()->setDebug(parseContext.contextPragma.debug); + $$->getAsAggregate()->addToPragmaTable(parseContext.contextPragma.pragmaTable); + } + ; + +%% diff --git a/glslang/MachineIndependent/intermOut.cpp b/glslang/MachineIndependent/intermOut.cpp new file mode 100644 index 00000000..a01899a6 --- /dev/null +++ b/glslang/MachineIndependent/intermOut.cpp @@ -0,0 +1,491 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#include "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(TInfoSink& i) : infoSink(i) { } + TInfoSink& infoSink; +}; + +TString TType::getCompleteString() const +{ + char buf[100]; + char *p = &buf[0]; + + if (qualifier != EvqTemporary && qualifier != EvqGlobal) + p += sprintf(p, "%s ", getQualifierString()); + if (array) + p += sprintf(p, "array of "); + if (matrix) + p += sprintf(p, "%dX%d matrix of ", size, size); + else if (size > 1) + p += sprintf(p, "%d-component vector of ", size); + + sprintf(p, "%s", getBasicString()); + + return TString(buf); +} + +// +// Helper functions for printing, not part of traversing. +// + +void OutputTreeText(TInfoSink& infoSink, TIntermNode* node, const int depth) +{ + int i; + + infoSink.debug << FormatSourceLoc(node->getLine()); + + for (i = 0; i < depth; ++i) + infoSink.debug << " "; +} + +// +// 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 OutputSymbol(TIntermSymbol* node, TIntermTraverser* it) +{ + TOutputTraverser* oit = static_cast(it); + + OutputTreeText(oit->infoSink, node, oit->depth); + + char buf[100]; + sprintf(buf, "'%s' (%s)\n", + node->getSymbol().c_str(), + node->getCompleteString().c_str()); + + oit->infoSink.debug << buf; +} + +bool OutputBinary(bool /* preVisit */, TIntermBinary* node, TIntermTraverser* it) +{ + TOutputTraverser* oit = static_cast(it); + TInfoSink& out = oit->infoSink; + + OutputTreeText(out, node, oit->depth); + + switch (node->getOp()) { + case EOpAssign: out.debug << "move second child to first child"; break; + case EOpAddAssign: out.debug << "add second child into first child"; break; + case EOpSubAssign: out.debug << "subtract second child into first child"; break; + case EOpMulAssign: out.debug << "multiply second child into first child"; break; + case EOpVectorTimesMatrixAssign: out.debug << "matrix mult second child into first child"; break; + case EOpVectorTimesScalarAssign: out.debug << "vector scale second child into first child"; break; + case EOpMatrixTimesScalarAssign: out.debug << "matrix scale second child into first child"; break; + case EOpMatrixTimesMatrixAssign: out.debug << "matrix mult second child into first child"; break; + case EOpDivAssign: out.debug << "divide second child into first child"; break; + case EOpModAssign: out.debug << "mod second child into first child"; break; + case EOpAndAssign: out.debug << "and second child into first child"; break; + case EOpInclusiveOrAssign: out.debug << "or second child into first child"; break; + case EOpExclusiveOrAssign: out.debug << "exclusive or second child into first child"; break; + case EOpLeftShiftAssign: out.debug << "left shift second child into first child"; break; + case EOpRightShiftAssign: out.debug << "right shift second child into first child"; break; + + case EOpIndexDirect: out.debug << "direct index"; break; + case EOpIndexIndirect: out.debug << "indirect index"; break; + case EOpIndexDirectStruct: out.debug << "direct index for structure"; break; + case EOpVectorSwizzle: out.debug << "vector swizzle"; break; + + case EOpAdd: out.debug << "add"; break; + case EOpSub: out.debug << "subtract"; break; + case EOpMul: out.debug << "component-wise multiply"; break; + case EOpDiv: out.debug << "divide"; break; + case EOpMod: out.debug << "mod"; break; + case EOpRightShift: out.debug << "right-shift"; break; + case EOpLeftShift: out.debug << "left-shift"; break; + case EOpAnd: out.debug << "bitwise and"; break; + case EOpInclusiveOr: out.debug << "inclusive-or"; break; + case EOpExclusiveOr: out.debug << "exclusive-or"; break; + case EOpEqual: out.debug << "Compare Equal"; break; + case EOpNotEqual: out.debug << "Compare Not Equal"; break; + case EOpLessThan: out.debug << "Compare Less Than"; break; + case EOpGreaterThan: out.debug << "Compare Greater Than"; break; + case EOpLessThanEqual: out.debug << "Compare Less Than or Equal"; break; + case EOpGreaterThanEqual: out.debug << "Compare Greater Than or Equal"; break; + + case EOpVectorTimesScalar: out.debug << "vector-scale"; break; + case EOpVectorTimesMatrix: out.debug << "vector-times-matrix"; break; + case EOpMatrixTimesVector: out.debug << "matrix-times-vector"; break; + case EOpMatrixTimesScalar: out.debug << "matrix-scale"; break; + case EOpMatrixTimesMatrix: out.debug << "matrix-multiply"; break; + + case EOpLogicalOr: out.debug << "logical-or"; break; + case EOpLogicalXor: out.debug << "logical-xor"; break; + case EOpLogicalAnd: out.debug << "logical-and"; break; + default: out.debug << ""; + } + + out.debug << " (" << node->getCompleteString() << ")"; + + out.debug << "\n"; + + return true; +} + +bool OutputUnary(bool /* preVisit */, TIntermUnary* node, TIntermTraverser* it) +{ + TOutputTraverser* oit = static_cast(it); + TInfoSink& out = oit->infoSink; + + OutputTreeText(out, node, oit->depth); + + switch (node->getOp()) { + case EOpNegative: out.debug << "Negate value"; break; + case EOpVectorLogicalNot: + case EOpLogicalNot: out.debug << "Negate conditional"; break; + case EOpBitwiseNot: out.debug << "Bitwise not"; break; + + case EOpPostIncrement: out.debug << "Post-Increment"; break; + case EOpPostDecrement: out.debug << "Post-Decrement"; break; + case EOpPreIncrement: out.debug << "Pre-Increment"; break; + case EOpPreDecrement: out.debug << "Pre-Decrement"; break; + + case EOpConvIntToBool: out.debug << "Convert int to bool"; break; + case EOpConvFloatToBool:out.debug << "Convert float to bool";break; + case EOpConvBoolToFloat:out.debug << "Convert bool to float";break; + case EOpConvIntToFloat: out.debug << "Convert int to float"; break; + case EOpConvFloatToInt: out.debug << "Convert float to int"; break; + case EOpConvBoolToInt: out.debug << "Convert bool to int"; break; + + case EOpRadians: out.debug << "radians"; break; + case EOpDegrees: out.debug << "degrees"; break; + case EOpSin: out.debug << "sine"; break; + case EOpCos: out.debug << "cosine"; break; + case EOpTan: out.debug << "tangent"; break; + case EOpAsin: out.debug << "arc sine"; break; + case EOpAcos: out.debug << "arc cosine"; break; + case EOpAtan: out.debug << "arc tangent"; break; + + case EOpExp: out.debug << "exp"; break; + case EOpLog: out.debug << "log"; break; + case EOpExp2: out.debug << "exp2"; break; + case EOpLog2: out.debug << "log2"; break; + case EOpSqrt: out.debug << "sqrt"; break; + case EOpInverseSqrt: out.debug << "inverse sqrt"; break; + + case EOpAbs: out.debug << "Absolute value"; break; + case EOpSign: out.debug << "Sign"; break; + case EOpFloor: out.debug << "Floor"; break; + case EOpCeil: out.debug << "Ceiling"; break; + case EOpFract: out.debug << "Fraction"; break; + + case EOpLength: out.debug << "length"; break; + case EOpNormalize: out.debug << "normalize"; break; + case EOpDPdx: out.debug << "dPdx"; break; + case EOpDPdy: out.debug << "dPdy"; break; + case EOpFwidth: out.debug << "fwidth"; break; + + case EOpAny: out.debug << "any"; break; + case EOpAll: out.debug << "all"; break; + + default: out.debug.message(EPrefixError, "Bad unary op"); + } + + out.debug << " (" << node->getCompleteString() << ")"; + + out.debug << "\n"; + + return true; +} + +bool OutputAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTraverser* it) +{ + TOutputTraverser* oit = static_cast(it); + TInfoSink& out = oit->infoSink; + + if (node->getOp() == EOpNull) { + out.debug.message(EPrefixError, "node is still EOpNull!"); + return true; + } + + OutputTreeText(out, node, oit->depth); + + switch (node->getOp()) { + case EOpSequence: out.debug << "Sequence\n"; return true; + case EOpComma: out.debug << "Comma\n"; return true; + case EOpFunction: out.debug << "Function Definition: " << node->getName(); break; + case EOpFunctionCall: out.debug << "Function Call: " << node->getName(); break; + case EOpParameters: out.debug << "Function Parameters: "; break; + + case EOpConstructFloat: out.debug << "Construct float"; break; + case EOpConstructVec2: out.debug << "Construct vec2"; break; + case EOpConstructVec3: out.debug << "Construct vec3"; break; + case EOpConstructVec4: out.debug << "Construct vec4"; break; + case EOpConstructBool: out.debug << "Construct bool"; break; + case EOpConstructBVec2: out.debug << "Construct bvec2"; break; + case EOpConstructBVec3: out.debug << "Construct bvec3"; break; + case EOpConstructBVec4: out.debug << "Construct bvec4"; break; + case EOpConstructInt: out.debug << "Construct int"; break; + case EOpConstructIVec2: out.debug << "Construct ivec2"; break; + case EOpConstructIVec3: out.debug << "Construct ivec3"; break; + case EOpConstructIVec4: out.debug << "Construct ivec4"; break; + case EOpConstructMat2: out.debug << "Construct mat2"; break; + case EOpConstructMat3: out.debug << "Construct mat3"; break; + case EOpConstructMat4: out.debug << "Construct mat4"; break; + case EOpConstructStruct: out.debug << "Construct structure"; break; + + case EOpLessThan: out.debug << "Compare Less Than"; break; + case EOpGreaterThan: out.debug << "Compare Greater Than"; break; + case EOpLessThanEqual: out.debug << "Compare Less Than or Equal"; break; + case EOpGreaterThanEqual: out.debug << "Compare Greater Than or Equal"; break; + case EOpVectorEqual: out.debug << "Equal"; break; + case EOpVectorNotEqual: out.debug << "NotEqual"; break; + + case EOpMod: out.debug << "mod"; break; + case EOpPow: out.debug << "pow"; break; + + case EOpAtan: out.debug << "arc tangent"; break; + + case EOpMin: out.debug << "min"; break; + case EOpMax: out.debug << "max"; break; + case EOpClamp: out.debug << "clamp"; break; + case EOpMix: out.debug << "mix"; break; + case EOpStep: out.debug << "step"; break; + case EOpSmoothStep: out.debug << "smoothstep"; break; + + case EOpDistance: out.debug << "distance"; break; + case EOpDot: out.debug << "dot-product"; break; + case EOpCross: out.debug << "cross-product"; break; + case EOpFaceForward: out.debug << "face-forward"; break; + case EOpReflect: out.debug << "reflect"; break; + case EOpRefract: out.debug << "refract"; break; + case EOpMul: out.debug << "component-wise multiply"; break; + + case EOpItof: out.debug << "itof"; break; + case EOpFtoi: out.debug << "ftoi"; break; + case EOpSkipPixels: out.debug << "skipPixels"; break; + case EOpReadInput: out.debug << "readInput"; break; + case EOpWritePixel: out.debug << "writePixel"; break; + case EOpBitmapLsb: out.debug << "bitmapLSB"; break; + case EOpBitmapMsb: out.debug << "bitmapMSB"; break; + case EOpWriteOutput: out.debug << "writeOutput"; break; + case EOpReadPixel: out.debug << "readPixel"; break; + + default: out.debug.message(EPrefixError, "Bad aggregation op"); + } + + if (node->getOp() != EOpSequence && node->getOp() != EOpParameters) + out.debug << " (" << node->getCompleteString() << ")"; + + out.debug << "\n"; + + return true; +} + +bool OutputSelection(bool /* preVisit */, TIntermSelection* node, TIntermTraverser* it) +{ + TOutputTraverser* oit = static_cast(it); + TInfoSink& out = oit->infoSink; + + OutputTreeText(out, node, oit->depth); + + out.debug << "Test condition and select"; + out.debug << " (" << node->getCompleteString() << ")\n"; + + ++oit->depth; + + OutputTreeText(oit->infoSink, node, oit->depth); + out.debug << "Condition\n"; + node->getCondition()->traverse(it); + + OutputTreeText(oit->infoSink, node, oit->depth); + if (node->getTrueBlock()) { + out.debug << "true case\n"; + node->getTrueBlock()->traverse(it); + } else + out.debug << "true case is null\n"; + + if (node->getFalseBlock()) { + OutputTreeText(oit->infoSink, node, oit->depth); + out.debug << "false case\n"; + node->getFalseBlock()->traverse(it); + } + + --oit->depth; + + return false; +} + +void OutputConstantUnion(TIntermConstantUnion* node, TIntermTraverser* it) +{ + TOutputTraverser* oit = static_cast(it); + TInfoSink& out = oit->infoSink; + + int size = node->getType().getObjectSize(); + + for (int i = 0; i < size; i++) { + OutputTreeText(out, node, oit->depth); + switch (node->getUnionArrayPointer()[i].getType()) { + case EbtBool: + if (node->getUnionArrayPointer()[i].getBConst()) + out.debug << "true"; + else + out.debug << "false"; + + out.debug << " (" << "const bool" << ")"; + + out.debug << "\n"; + break; + case EbtFloat: + { + char buf[300]; + sprintf(buf, "%f (%s)", node->getUnionArrayPointer()[i].getFConst(), "const float"); + + out.debug << buf << "\n"; + } + break; + case EbtInt: + { + char buf[300]; + sprintf(buf, "%d (%s)", node->getUnionArrayPointer()[i].getIConst(), "const int"); + + out.debug << buf << "\n"; + break; + } + default: + out.info.message(EPrefixInternalError, "Unknown constant", node->getLine()); + break; + } + } +} + +bool OutputLoop(bool /* preVisit */, TIntermLoop* node, TIntermTraverser* it) +{ + TOutputTraverser* oit = static_cast(it); + TInfoSink& out = oit->infoSink; + + OutputTreeText(out, node, oit->depth); + + out.debug << "Loop with condition "; + if (! node->testFirst()) + out.debug << "not "; + out.debug << "tested first\n"; + + ++oit->depth; + + OutputTreeText(oit->infoSink, node, oit->depth); + if (node->getTest()) { + out.debug << "Loop Condition\n"; + node->getTest()->traverse(it); + } else + out.debug << "No loop condition\n"; + + OutputTreeText(oit->infoSink, node, oit->depth); + if (node->getBody()) { + out.debug << "Loop Body\n"; + node->getBody()->traverse(it); + } else + out.debug << "No loop body\n"; + + if (node->getTerminal()) { + OutputTreeText(oit->infoSink, node, oit->depth); + out.debug << "Loop Terminal Expression\n"; + node->getTerminal()->traverse(it); + } + + --oit->depth; + + return false; +} + +bool OutputBranch(bool /* previsit*/, TIntermBranch* node, TIntermTraverser* it) +{ + TOutputTraverser* oit = static_cast(it); + TInfoSink& out = oit->infoSink; + + OutputTreeText(out, node, oit->depth); + + switch (node->getFlowOp()) { + case EOpKill: out.debug << "Branch: Kill"; break; + case EOpBreak: out.debug << "Branch: Break"; break; + case EOpContinue: out.debug << "Branch: Continue"; break; + case EOpReturn: out.debug << "Branch: Return"; break; + default: out.debug << "Branch: Unknown Branch"; break; + } + + if (node->getExpression()) { + out.debug << " with expression\n"; + ++oit->depth; + node->getExpression()->traverse(it); + --oit->depth; + } else + out.debug << "\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); + + it.visitAggregate = OutputAggregate; + it.visitBinary = OutputBinary; + it.visitConstantUnion = OutputConstantUnion; + it.visitSelection = OutputSelection; + it.visitSymbol = OutputSymbol; + it.visitUnary = OutputUnary; + it.visitLoop = OutputLoop; + it.visitBranch = OutputBranch; + + root->traverse(&it); +} diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h new file mode 100644 index 00000000..ae30c732 --- /dev/null +++ b/glslang/MachineIndependent/localintermediate.h @@ -0,0 +1,86 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef _LOCAL_INTERMEDIATE_INCLUDED_ +#define _LOCAL_INTERMEDIATE_INCLUDED_ + +#include "../Include/intermediate.h" +#include "../Public/ShaderLang.h" +#include "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(constUnion*, const TType&, TSourceLoc); + TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) ; + bool parseConstTree(TSourceLoc, TIntermNode*, constUnion*, TOperator, TSymbolTable&, TType, bool singleConstantParam = false); + TIntermNode* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, TSourceLoc); + TIntermBranch* addBranch(TOperator, TSourceLoc); + TIntermBranch* addBranch(TOperator, TIntermTyped*, TSourceLoc); + TIntermTyped* addSwizzle(TVectorFields&, TSourceLoc); + bool postProcess(TIntermNode*, EShLanguage); + void remove(TIntermNode*); + void outputTree(TIntermNode*); + +protected: + TInfoSink& infoSink; + +private: + void operator=(TIntermediate&); // prevent assignments +}; + +#endif // _LOCAL_INTERMEDIATE_INCLUDED_ diff --git a/glslang/MachineIndependent/parseConst.cpp b/glslang/MachineIndependent/parseConst.cpp new file mode 100644 index 00000000..ae073198 --- /dev/null +++ b/glslang/MachineIndependent/parseConst.cpp @@ -0,0 +1,266 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#include "ParseHelper.h" + +// +// Use this class to carry along data from node to node in +// the traversal +// +class TConstTraverser : public TIntermTraverser { +public: + TConstTraverser(constUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TSymbolTable& symTable, TType& t) : unionArray(cUnion), type(t), + constructorType(constructType), singleConstantParam(singleConstParam), infoSink(sink), symbolTable(symTable), error(false), isMatrix(false), matrixSize(0) { index = 0; tOp = EOpNull;} + int index ; + constUnion *unionArray; + TOperator tOp; + TType type; + TOperator constructorType; + bool singleConstantParam; + TInfoSink& infoSink; + TSymbolTable& symbolTable; + bool error; + 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 ParseSymbol(TIntermSymbol* node, TIntermTraverser* it) +{ + TConstTraverser* oit = static_cast(it); + oit->infoSink.info.message(EPrefixInternalError, "Symbol Node found in constant constructor", node->getLine()); + return; + +} + +bool ParseBinary(bool /* preVisit */, TIntermBinary* node, TIntermTraverser* it) +{ + TConstTraverser* oit = static_cast(it); + + TQualifier qualifier = node->getType().getQualifier(); + + if (qualifier != EvqConst) { + char buf[200]; + sprintf(buf, "'constructor' : assigning non-constant to %s", oit->type.getCompleteString().c_str()); + oit->infoSink.info.message(EPrefixError, buf, node->getLine()); + oit->error = true; + return false; + } + + oit->infoSink.info.message(EPrefixInternalError, "Binary Node found in constant constructor", node->getLine()); + + return false; +} + +bool ParseUnary(bool /* preVisit */, TIntermUnary* node, TIntermTraverser* it) +{ + TConstTraverser* oit = static_cast(it); + + char buf[200]; + sprintf(buf, "'constructor' : assigning non-constant to '%s'", oit->type.getCompleteString().c_str()); + oit->infoSink.info.message(EPrefixError, buf, node->getLine()); + oit->error = true; + return false; +} + +bool ParseAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTraverser* it) +{ + TConstTraverser* oit = static_cast(it); + + if (!node->isConstructor() && node->getOp() != EOpComma) { + char buf[200]; + sprintf(buf, "'constructor' : assigning non-constant to '%s'", oit->type.getCompleteString().c_str()); + oit->infoSink.info.message(EPrefixError, buf, node->getLine()); + oit->error = true; + return false; + } + + if (node->getSequence().size() == 0) { + oit->error = true; + return false; + } + + bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion(); + if (flag) + { + oit->singleConstantParam = true; + oit->constructorType = node->getOp(); + oit->size = node->getType().getObjectSize(); + + if (node->getType().isMatrix()) { + oit->isMatrix = true; + oit->matrixSize = node->getType().getNominalSize(); + } + } + + for (TIntermSequence::iterator p = node->getSequence().begin(); + p != node->getSequence().end(); p++) { + + if (node->getOp() == EOpComma) + oit->index = 0; + + (*p)->traverse(oit); + } + if (flag) + { + oit->singleConstantParam = false; + oit->constructorType = EOpNull; + oit->size = 0; + oit->isMatrix = false; + oit->matrixSize = 0; + } + return false; +} + +bool ParseSelection(bool /* preVisit */, TIntermSelection* node, TIntermTraverser* it) +{ + TConstTraverser* oit = static_cast(it); + oit->infoSink.info.message(EPrefixInternalError, "Selection Node found in constant constructor", node->getLine()); + oit->error = true; + return false; +} + +void ParseConstantUnion(TIntermConstantUnion* node, TIntermTraverser* it) +{ + TConstTraverser* oit = static_cast(it); + constUnion* leftUnionArray = oit->unionArray; + int instanceSize = oit->type.getObjectSize(); + + if (oit->index >= instanceSize) + return; + + if (!oit->singleConstantParam) { + int size = node->getType().getObjectSize(); + + constUnion *rightUnionArray = node->getUnionArrayPointer(); + for (int i=0; i < size; i++) { + if (oit->index >= instanceSize) + return; + leftUnionArray[oit->index] = rightUnionArray[i]; + + (oit->index)++; + } + } else { + int size, totalSize, matrixSize; + bool isMatrix = false; + size = oit->size; + matrixSize = oit->matrixSize; + isMatrix = oit->isMatrix; + totalSize = oit->index + size ; + constUnion *rightUnionArray = node->getUnionArrayPointer(); + if (!isMatrix) { + int count = 0; + for (int i = oit->index; i < totalSize; i++) { + if (i >= instanceSize) + return; + + leftUnionArray[i] = rightUnionArray[count]; + + (oit->index)++; + + if (node->getType().getObjectSize() > 1) + count++; + } + } else { // for matrix constructors + int count = 0; + int index = oit->index; + for (int i = index; i < totalSize; i++) { + if (i >= instanceSize) + return; + if (index - i == 0 || (i - index) % (matrixSize + 1) == 0 ) + leftUnionArray[i] = rightUnionArray[count]; + else + leftUnionArray[i].setFConst(0.0f); + + (oit->index)++; + + if (node->getType().getObjectSize() > 1) + count++; + } + } + } +} + +bool ParseLoop(bool /* preVisit */, TIntermLoop* node, TIntermTraverser* it) +{ + TConstTraverser* oit = static_cast(it); + oit->infoSink.info.message(EPrefixInternalError, "Loop Node found in constant constructor", node->getLine()); + oit->error = true; + return false; +} + +bool ParseBranch(bool /* previsit*/, TIntermBranch* node, TIntermTraverser* it) +{ + TConstTraverser* oit = static_cast(it); + oit->infoSink.info.message(EPrefixInternalError, "Branch Node found in constant constructor", node->getLine()); + oit->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, constUnion* unionArray, TOperator constructorType, TSymbolTable& symbolTable, TType t, bool singleConstantParam) +{ + if (root == 0) + return false; + + TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, symbolTable, t); + + it.visitAggregate = ParseAggregate; + it.visitBinary = ParseBinary; + it.visitConstantUnion = ParseConstantUnion; + it.visitSelection = ParseSelection; + it.visitSymbol = ParseSymbol; + it.visitUnary = ParseUnary; + it.visitLoop = ParseLoop; + it.visitBranch = ParseBranch; + + root->traverse(&it); + if (it.error) + return true; + else + return false; +} diff --git a/glslang/MachineIndependent/preprocessor/Makefile b/glslang/MachineIndependent/preprocessor/Makefile new file mode 100644 index 00000000..b6402ce7 --- /dev/null +++ b/glslang/MachineIndependent/preprocessor/Makefile @@ -0,0 +1,38 @@ +CC = gcc + +OBJECTS = atom.o cpp.o cppstruct.o memory.o scanner.o symbols.o tokens.o +AR=ar +SRCS=scanner.c atom.c memory.c tokens. cpp.c cppstruct.c symbols.c + +default: all +all : libPreprocessor.a +libPreprocessor.a : $(OBJECTS) + $(AR) rvu $@ $(OBJECTS) + ranlib $@ + +%.o : %.c + $(CC) -c $< + +# +# Cleanup +# +.PHONY : clean +clean : + $(RM) *.o *.a + +depend: + makedepend -Y -- $(SRCS) + +# DO NOT DELETE + +scanner.o: slglobals.h memory.h atom.h scanner.h parser.h cpp.h tokens.h +scanner.o: symbols.h compile.h +atom.o: slglobals.h memory.h atom.h scanner.h parser.h cpp.h tokens.h +atom.o: symbols.h compile.h +memory.o: memory.h +cpp.o: slglobals.h memory.h atom.h scanner.h parser.h cpp.h tokens.h +cpp.o: symbols.h compile.h +cppstruct.o: slglobals.h memory.h atom.h scanner.h parser.h cpp.h tokens.h +cppstruct.o: symbols.h compile.h +symbols.o: slglobals.h memory.h atom.h scanner.h parser.h cpp.h tokens.h +symbols.o: symbols.h compile.h diff --git a/glslang/MachineIndependent/preprocessor/atom.c b/glslang/MachineIndependent/preprocessor/atom.c new file mode 100644 index 00000000..39af441f --- /dev/null +++ b/glslang/MachineIndependent/preprocessor/atom.c @@ -0,0 +1,768 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ + +// +// atom.c +// + +#include +#include +#include +#include + +#include "slglobals.h" + +#undef malloc +#undef realloc +#undef free + +/////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////// String table: ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +static const struct { + int val; + const char *str; +} tokens[] = { + { CPP_AND_OP, "&&" }, + { CPP_AND_ASSIGN, "&=" }, + { CPP_SUB_ASSIGN, "-=" }, + { CPP_MOD_ASSIGN, "%=" }, + { CPP_ADD_ASSIGN, "+=" }, + { CPP_DIV_ASSIGN, "/=" }, + { CPP_MUL_ASSIGN, "*=" }, + { CPP_RIGHT_BRACKET, ":>" }, + { CPP_EQ_OP, "==" }, + { CPP_XOR_OP, "^^" }, + { CPP_XOR_ASSIGN, "^=" }, + { CPP_FLOATCONSTANT, "" }, + { CPP_GE_OP, ">=" }, + { CPP_RIGHT_OP, ">>" }, + { CPP_RIGHT_ASSIGN, ">>=" }, + { CPP_IDENTIFIER, "" }, + { CPP_INTCONSTANT, "" }, + { CPP_LE_OP, "<=" }, + { CPP_LEFT_OP, "<<" }, + { CPP_LEFT_ASSIGN, "<<=" }, + { CPP_LEFT_BRACKET, "<:" }, + { CPP_LEFT_BRACE, "<%" }, + { CPP_DEC_OP, "--" }, + { CPP_RIGHT_BRACE, "%>" }, + { CPP_NE_OP, "!=" }, + { CPP_OR_OP, "||" }, + { CPP_OR_ASSIGN, "|=" }, + { CPP_INC_OP, "++" }, + { CPP_STRCONSTANT, "" }, + { CPP_TYPEIDENTIFIER, "" }, +}; + +/////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////// String table: ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +#define INIT_STRING_TABLE_SIZE 16384 + +typedef struct StringTable_Rec { + char *strings; + int nextFree; + int size; +} StringTable; + +/* + * InitStringTable() - Initialize the string table. + * + */ + +static int InitStringTable(StringTable *stable) +{ + stable->strings = (char *) malloc(INIT_STRING_TABLE_SIZE); + if (!stable->strings) + return 0; + // Zero-th offset means "empty" so don't use it. + stable->nextFree = 1; + stable->size = INIT_STRING_TABLE_SIZE; + return 1; +} // InitStringTable + +/* + * FreeStringTable() - Free the string table. + * + */ + +static void FreeStringTable(StringTable *stable) +{ + if (stable->strings) + free(stable->strings); + stable->strings = NULL; + stable->nextFree = 0; + stable->size = 0; +} // FreeStringTable + +/* + * HashString() - Hash a string with the base hash function. + * + */ + +static int HashString(const char *s) +{ + int hval = 0; + + while (*s) { + hval = (hval*13507 + *s*197) ^ (hval >> 2); + s++; + } + return hval & 0x7fffffff; +} // HashString + +/* + * HashString2() - Hash a string with the incrimenting hash function. + * + */ + +static int HashString2(const char *s) +{ + int hval = 0; + + while (*s) { + hval = (hval*729 + *s*37) ^ (hval >> 1); + s++; + } + return hval; +} // HashString2 + +/* + * AddString() - Add a string to a string table. Return it's offset. + * + */ + +static int AddString(StringTable *stable, const char *s) +{ + int len, loc; + char *str; + + len = (int) strlen(s); + if (stable->nextFree + len + 1 >= stable->size) { + assert(stable->size < 1000000); + str = (char *) malloc(stable->size*2); + memcpy(str, stable->strings, stable->size); + free(stable->strings); + stable->strings = str; + } + loc = stable->nextFree; + strcpy(&stable->strings[loc], s); + stable->nextFree += len + 1; + return loc; +} // AddString + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////// Hash table: /////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +#define INIT_HASH_TABLE_SIZE 2047 +#define HASH_TABLE_MAX_COLLISIONS 3 + +typedef struct HashEntry_Rec { + int index; // String table offset of string representation + int value; // Atom (symbol) value +} HashEntry; + +typedef struct HashTable_Rec { + HashEntry *entry; + int size; + int entries; + int counts[HASH_TABLE_MAX_COLLISIONS + 1]; +} HashTable; + +/* + * InitHashTable() - Initialize the hash table. + * + */ + +static int InitHashTable(HashTable *htable, int fsize) +{ + int ii; + + htable->entry = (HashEntry *) malloc(sizeof(HashEntry)*fsize); + if (!htable->entry) + return 0; + htable->size = fsize; + for (ii = 0; ii < fsize; ii++) { + htable->entry[ii].index = 0; + htable->entry[ii].value = 0; + } + htable->entries = 0; + for (ii = 0; ii <= HASH_TABLE_MAX_COLLISIONS; ii++) + htable->counts[ii] = 0; + return 1; +} // InitHashTable + +/* + * FreeHashTable() - Free the hash table. + * + */ + +static void FreeHashTable(HashTable *htable) +{ + if (htable->entry) + free(htable->entry); + htable->entry = NULL; + htable->size = 0; + htable->entries = 0; +} // FreeHashTable + +/* + * Empty() - See if a hash table entry is empty. + * + */ + +static int Empty(HashTable *htable, int hashloc) +{ + assert(hashloc >= 0 && hashloc < htable->size); + if (htable->entry[hashloc].index == 0) { + return 1; + } else { + return 0; + } +} // Empty + +/* + * Match() - See if a hash table entry is matches a string. + * + */ + +static int Match(HashTable *htable, StringTable *stable, const char *s, int hashloc) +{ + int strloc; + + strloc = htable->entry[hashloc].index; + if (!strcmp(s, &stable->strings[strloc])) { + return 1; + } else { + return 0; + } +} // Match + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////// Atom table: /////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +#define INIT_ATOM_TABLE_SIZE 1024 + + +struct AtomTable_Rec { + StringTable stable; // String table. + HashTable htable; // Hashes string to atom number and token value. Multiple strings can + // have the same token value but each unique string is a unique atom. + int *amap; // Maps atom value to offset in string table. Atoms all map to unique + // strings except for some undefined values in the lower, fixed part + // of the atom table that map to "". The lowest 256 atoms + // correspond to single character ASCII values except for alphanumeric + // characters and '_', which can be other tokens. Next come the + // language tokens with their atom values equal to the token value. + // Then come predefined atoms, followed by user specified identifiers. + int *arev; // Reversed atom for symbol table use. + int nextFree; + int size; +}; + +static AtomTable latable = { { 0 } }; +AtomTable *atable = &latable; + +static int AddAtomFixed(AtomTable *atable, const char *s, int atom); + +/* + * GrowAtomTable() - Grow the atom table to at least "size" if it's smaller. + * + */ + +static int GrowAtomTable(AtomTable *atable, int size) +{ + int *newmap, *newrev; + + if (atable->size < size) { + if (atable->amap) { + newmap = realloc(atable->amap, sizeof(int)*size); + newrev = realloc(atable->arev, sizeof(int)*size); + } else { + newmap = malloc(sizeof(int)*size); + newrev = malloc(sizeof(int)*size); + atable->size = 0; + } + if (!newmap || !newrev) { + /* failed to grow -- error */ + if (newmap) + atable->amap = newmap; + if (newrev) + atable->amap = newrev; + return -1; + } + memset(&newmap[atable->size], 0, (size - atable->size) * sizeof(int)); + memset(&newrev[atable->size], 0, (size - atable->size) * sizeof(int)); + atable->amap = newmap; + atable->arev = newrev; + atable->size = size; + } + return 0; +} // GrowAtomTable + +/* + * lReverse() - Reverse the bottom 20 bits of a 32 bit int. + * + */ + +static int lReverse(int fval) +{ + unsigned int in = fval; + int result = 0, cnt = 0; + + while(in) { + result <<= 1; + result |= in&1; + in >>= 1; + cnt++; + } + + // Don't use all 31 bits. One million atoms is plenty and sometimes the + // upper bits are used for other things. + + if (cnt < 20) + result <<= 20 - cnt; + return result; +} // lReverse + +/* + * AllocateAtom() - Allocate a new atom. Associated with the "undefined" value of -1. + * + */ + +static int AllocateAtom(AtomTable *atable) +{ + if (atable->nextFree >= atable->size) + GrowAtomTable(atable, atable->nextFree*2); + atable->amap[atable->nextFree] = -1; + atable->arev[atable->nextFree] = lReverse(atable->nextFree); + atable->nextFree++; + return atable->nextFree - 1; +} // AllocateAtom + +/* + * SetAtomValue() - Allocate a new atom associated with "hashindex". + * + */ + +static void SetAtomValue(AtomTable *atable, int atomnumber, int hashindex) +{ + atable->amap[atomnumber] = atable->htable.entry[hashindex].index; + atable->htable.entry[hashindex].value = atomnumber; +} // SetAtomValue + +/* + * FindHashLoc() - Find the hash location for this string. Return -1 it hash table is full. + * + */ + +static int FindHashLoc(AtomTable *atable, const char *s) +{ + int hashloc, hashdelta, count; + int FoundEmptySlot = 0; + int collision[HASH_TABLE_MAX_COLLISIONS + 1]; + + hashloc = HashString(s) % atable->htable.size; + if (!Empty(&atable->htable, hashloc)) { + if (Match(&atable->htable, &atable->stable, s, hashloc)) + return hashloc; + collision[0] = hashloc; + hashdelta = HashString2(s); + count = 0; + while (count < HASH_TABLE_MAX_COLLISIONS) { + hashloc = ((hashloc + hashdelta) & 0x7fffffff) % atable->htable.size; + if (!Empty(&atable->htable, hashloc)) { + if (Match(&atable->htable, &atable->stable, s, hashloc)) { + return hashloc; + } + } else { + FoundEmptySlot = 1; + break; + } + count++; + collision[count] = hashloc; + } + + if (!FoundEmptySlot) { + if (cpp->options.DumpAtomTable) { + int ii; + char str[200]; + sprintf(str, "*** Hash failed with more than %d collisions. Must increase hash table size. ***", + HASH_TABLE_MAX_COLLISIONS); + CPPShInfoLogMsg(str); + + sprintf(str, "*** New string \"%s\", hash=%04x, delta=%04x", s, collision[0], hashdelta); + CPPShInfoLogMsg(str); + for (ii = 0; ii <= HASH_TABLE_MAX_COLLISIONS; ii++) { + sprintf(str, "*** Collides on try %d at hash entry %04x with \"%s\"", + ii + 1, collision[ii], GetAtomString(atable, atable->htable.entry[collision[ii]].value)); + CPPShInfoLogMsg(str); + } + } + return -1; + } else { + atable->htable.counts[count]++; + } + } + return hashloc; +} // FindHashLoc + +/* + * IncreaseHashTableSize() + * + */ + +static int IncreaseHashTableSize(AtomTable *atable) +{ + int ii, strloc, oldhashloc, value, size; + AtomTable oldtable; + char *s; + + // Save the old atom table and create a new one: + + oldtable = *atable; + size = oldtable.htable.size*2 + 1; + if (!InitAtomTable(atable, size)) + return 0; + + // Add all the existing values to the new atom table preserving their atom values: + + for (ii = atable->nextFree; ii < oldtable.nextFree; ii++) { + strloc = oldtable.amap[ii]; + s = &oldtable.stable.strings[strloc]; + oldhashloc = FindHashLoc(&oldtable, s); + assert(oldhashloc >= 0); + value = oldtable.htable.entry[oldhashloc].value; + AddAtomFixed(atable, s, value); + } + FreeAtomTable(&oldtable); + return 1; +} // IncreaseHashTableSize + +/* + * LookUpAddStringHash() - Lookup a string in the hash table. If it's not there, add it and + * initialize the atom value in the hash table to 0. Return the hash table index. + */ + +static int LookUpAddStringHash(AtomTable *atable, const char *s) +{ + int hashloc, strloc; + + while(1) { + hashloc = FindHashLoc(atable, s); + if (hashloc >= 0) + break; + IncreaseHashTableSize(atable); + } + + if (Empty(&atable->htable, hashloc)) { + atable->htable.entries++; + strloc = AddString(&atable->stable, s); + atable->htable.entry[hashloc].index = strloc; + atable->htable.entry[hashloc].value = 0; + } + return hashloc; +} // LookUpAddStringHash + +/* + * LookUpAddString() - Lookup a string in the hash table. If it's not there, add it and + * initialize the atom value in the hash table to the next atom number. + * Return the atom value of string. + */ + +int LookUpAddString(AtomTable *atable, const char *s) +{ + int hashindex, atom; + + hashindex = LookUpAddStringHash(atable, s); + atom = atable->htable.entry[hashindex].value; + if (atom == 0) { + atom = AllocateAtom(atable); + SetAtomValue(atable, atom, hashindex); + } + return atom; +} // LookUpAddString + +/* + * GetAtomString() + * + */ + +const char *GetAtomString(AtomTable *atable, int atom) +{ + int soffset; + + if (atom > 0 && atom < atable->nextFree) { + soffset = atable->amap[atom]; + if (soffset > 0 && soffset < atable->stable.nextFree) { + return &atable->stable.strings[soffset]; + } else { + return ""; + } + } else { + if (atom == 0) { + return ""; + } else { + if (atom == EOF) { + return ""; + } else { + return ""; + } + } + } +} // GetAtomString + +/* + * GetReversedAtom() + * + */ + +int GetReversedAtom(AtomTable *atable, int atom) +{ + if (atom > 0 && atom < atable->nextFree) { + return atable->arev[atom]; + } else { + return 0; + } +} // GetReversedAtom + +/* + * AddAtom() - Add a string to the atom, hash and string tables if it isn't already there. + * Return it's atom index. + */ + +int AddAtom(AtomTable *atable, const char *s) +{ + int atom; + + atom = LookUpAddString(atable, s); + return atom; +} // AddAtom + +/* + * AddAtomFixed() - Add an atom to the hash and string tables if it isn't already there. + * Assign it the atom value of "atom". + */ + +static int AddAtomFixed(AtomTable *atable, const char *s, int atom) +{ + int hashindex, lsize; + + hashindex = LookUpAddStringHash(atable, s); + if (atable->nextFree >= atable->size || atom >= atable->size) { + lsize = atable->size*2; + if (lsize <= atom) + lsize = atom + 1; + GrowAtomTable(atable, lsize); + } + atable->amap[atom] = atable->htable.entry[hashindex].index; + atable->htable.entry[hashindex].value = atom; + //if (atom >= atable->nextFree) + // atable->nextFree = atom + 1; + while (atom >= atable->nextFree) { + atable->arev[atable->nextFree] = lReverse(atable->nextFree); + atable->nextFree++; + } + return atom; +} // AddAtomFixed + +/* + * InitAtomTable() - Initialize the atom table. + * + */ + +int InitAtomTable(AtomTable *atable, int htsize) +{ + int ii; + + htsize = htsize <= 0 ? INIT_HASH_TABLE_SIZE : htsize; + if (!InitStringTable(&atable->stable)) + return 0; + if (!InitHashTable(&atable->htable, htsize)) + return 0; + + atable->nextFree = 0; + atable->amap = NULL; + atable->size = 0; + GrowAtomTable(atable, INIT_ATOM_TABLE_SIZE); + if (!atable->amap) + return 0; + + // Initialize lower part of atom table to "" atom: + + AddAtomFixed(atable, "", 0); + for (ii = 0; ii < FIRST_USER_TOKEN_SY; ii++) + atable->amap[ii] = atable->amap[0]; + + // Add single character tokens to the atom table: + + { + const char *s = "~!%^&*()-+=|,.<>/?;:[]{}#"; + char t[2]; + + t[1] = '\0'; + while (*s) { + t[0] = *s; + AddAtomFixed(atable, t, s[0]); + s++; + } + } + + // Add multiple character scanner tokens : + + for (ii = 0; ii < sizeof(tokens)/sizeof(tokens[0]); ii++) + AddAtomFixed(atable, tokens[ii].str, tokens[ii].val); + + // Add error symbol if running in error mode: + + if (cpp->options.ErrorMode) + AddAtomFixed(atable, "error", ERROR_SY); + + AddAtom(atable, "<*** end fixed atoms ***>"); + + return 1; +} // InitAtomTable + +/////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////// Debug Printing Functions: ////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +/* + * PrintAtomTable() + * + */ + +void PrintAtomTable(AtomTable *atable) +{ + int ii; + char str[200]; + + for (ii = 0; ii < atable->nextFree; ii++) { + sprintf(str, "%d: \"%s\"", ii, &atable->stable.strings[atable->amap[ii]]); + CPPDebugLogMsg(str); + } + sprintf(str, "Hash table: size=%d, entries=%d, collisions=", + atable->htable.size, atable->htable.entries); + CPPDebugLogMsg(str); + for (ii = 0; ii < HASH_TABLE_MAX_COLLISIONS; ii++) { + sprintf(str, " %d", atable->htable.counts[ii]); + CPPDebugLogMsg(str); + } + +} // PrintAtomTable + + +/* + * GetStringOfAtom() + * + */ + +char* GetStringOfAtom(AtomTable *atable, int atom) +{ + char* chr_str; + chr_str=&atable->stable.strings[atable->amap[atom]]; + return chr_str; +} // GetStringOfAtom + +/* + * FreeAtomTable() - Free the atom table and associated memory + * + */ + +void FreeAtomTable(AtomTable *atable) +{ + FreeStringTable(&atable->stable); + FreeHashTable(&atable->htable); + if (atable->amap) + free(atable->amap); + if (atable->arev) + free(atable->arev); + atable->amap = NULL; + atable->arev = NULL; + atable->nextFree = 0; + atable->size = 0; +} // FreeAtomTable + +/////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////// End of atom.c /////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/glslang/MachineIndependent/preprocessor/atom.h b/glslang/MachineIndependent/preprocessor/atom.h new file mode 100644 index 00000000..6d8898d1 --- /dev/null +++ b/glslang/MachineIndependent/preprocessor/atom.h @@ -0,0 +1,96 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// atom.h +// + +#if !defined(__ATOM_H) +#define __ATOM_H 1 + +typedef struct AtomTable_Rec AtomTable; + +extern AtomTable *atable; + +int InitAtomTable(AtomTable *atable, int htsize); +void FreeAtomTable(AtomTable *atable); +int AddAtom(AtomTable *atable, const char *s); +void PrintAtomTable(AtomTable *atable); +int LookUpAddString(AtomTable *atable, const char *s); +const char *GetAtomString(AtomTable *atable, int atom); +int GetReversedAtom(AtomTable *atable, int atom); +char* GetStringOfAtom(AtomTable *atable, int atom); +#endif // !defined(__ATOM_H) diff --git a/glslang/MachineIndependent/preprocessor/compile.h b/glslang/MachineIndependent/preprocessor/compile.h new file mode 100644 index 00000000..08a92808 --- /dev/null +++ b/glslang/MachineIndependent/preprocessor/compile.h @@ -0,0 +1,132 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// compile.h +// + +#if !defined(__COMPILE_H) +#define __COMPILE_H 1 + +int InitCPPStruct(void); + +typedef struct Options_Rec{ + const char *profileString; + int ErrorMode; + int Quiet; + + // Debug The Compiler options: + int DumpAtomTable; +} Options; + +struct CPPStruct_Rec { + // Public members + SourceLoc *pLastSourceLoc; // Set at the start of each statement by the tree walkers + Options options; // Compile options and parameters + + // Private members + SourceLoc lastSourceLoc; + + // Scanner data: + + SourceLoc *tokenLoc; // Source location of most recent token seen by the scanner + int mostRecentToken; // Most recent token seen by the scanner + InputSrc *currentInput; + int previous_token; + int notAVersionToken; // used to make sure that #version is the first token seen in the file, if present + + void *pC; // storing the parseContext of the compile object in cpp. + + // Private members: + SourceLoc ltokenLoc; + int ifdepth; //current #if-#else-#endif nesting in the cpp.c file (pre-processor) + int elsedepth[64]; //Keep a track of #if depth..Max allowed is 64. + int elsetracker; //#if-#else and #endif constructs...Counter. + const char *ErrMsg; + int CompileError; //Indicate compile error when #error, #else,#elif mismatch. + + // + // Globals used to communicate between PaParseStrings() and yy_input()and + // also across the files.(gen_glslang.cpp and scanner.c) + // + int PaWhichStr; // which string we're parsing + int* PaStrLen; // array of lengths of the PaArgv strings + int PaArgc; // count of strings in the array + char** PaArgv; // our array of strings to parse + unsigned int tokensBeforeEOF : 1; +}; + +#endif // !defined(__COMPILE_H) diff --git a/glslang/MachineIndependent/preprocessor/cpp.c b/glslang/MachineIndependent/preprocessor/cpp.c new file mode 100644 index 00000000..221f1a88 --- /dev/null +++ b/glslang/MachineIndependent/preprocessor/cpp.c @@ -0,0 +1,1037 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// cpp.c +// + +#include +#include +#include +#include +#include + +#include "slglobals.h" + +static int CPPif(yystypepp * yylvalpp); + +/* Don't use memory.c's replacements, as we clean up properly here */ +#undef malloc +#undef free + +static int bindAtom = 0; +static int constAtom = 0; +static int defaultAtom = 0; +static int defineAtom = 0; +static int definedAtom = 0; +static int elseAtom = 0; +static int elifAtom = 0; +static int endifAtom = 0; +static int ifAtom = 0; +static int ifdefAtom = 0; +static int ifndefAtom = 0; +static int includeAtom = 0; +static int lineAtom = 0; +static int pragmaAtom = 0; +static int texunitAtom = 0; +static int undefAtom = 0; +static int errorAtom = 0; +static int __LINE__Atom = 0; +static int __FILE__Atom = 0; +static int __VERSION__Atom = 0; +static int versionAtom = 0; +static int extensionAtom = 0; + +static Scope *macros = 0; +#define MAX_MACRO_ARGS 64 +#define MAX_IF_NESTING 64 + +static SourceLoc ifloc; /* outermost #if */ + +int InitCPP(void) +{ + char buffer[64], *t; + const char *f; + // Add various atoms needed by the CPP line scanner: + bindAtom = LookUpAddString(atable, "bind"); + constAtom = LookUpAddString(atable, "const"); + defaultAtom = LookUpAddString(atable, "default"); + defineAtom = LookUpAddString(atable, "define"); + definedAtom = LookUpAddString(atable, "defined"); + elifAtom = LookUpAddString(atable, "elif"); + elseAtom = LookUpAddString(atable, "else"); + endifAtom = LookUpAddString(atable, "endif"); + ifAtom = LookUpAddString(atable, "if"); + ifdefAtom = LookUpAddString(atable, "ifdef"); + ifndefAtom = LookUpAddString(atable, "ifndef"); + includeAtom = LookUpAddString(atable, "include"); + lineAtom = LookUpAddString(atable, "line"); + pragmaAtom = LookUpAddString(atable, "pragma"); + texunitAtom = LookUpAddString(atable, "texunit"); + undefAtom = LookUpAddString(atable, "undef"); + errorAtom = LookUpAddString(atable, "error"); + __LINE__Atom = LookUpAddString(atable, "__LINE__"); + __FILE__Atom = LookUpAddString(atable, "__FILE__"); + __VERSION__Atom = LookUpAddString(atable, "__VERSION__"); + versionAtom = LookUpAddString(atable, "version"); + extensionAtom = LookUpAddString(atable, "extension"); + macros = NewScopeInPool(mem_CreatePool(0, 0)); + strcpy(buffer, "PROFILE_"); + t = buffer + strlen(buffer); + f = cpp->options.profileString; + while ((isalnum(*f) || *f == '_') && t < buffer + sizeof(buffer) - 1) + *t++ = toupper(*f++); + *t = 0; + return 1; +} // InitCPP + +int FreeCPP(void) +{ + if (macros) + { + mem_FreePool(macros->pool); + macros = 0; + } + + return 1; +} + +int FinalCPP(void) +{ + if (cpp->ifdepth) + CPPErrorToInfoLog("#if mismatch"); + return 1; +} + +static int CPPdefine(yystypepp * yylvalpp) +{ + int token, name, args[MAX_MACRO_ARGS], argc; + const char *message; + MacroSymbol mac; + Symbol *symb; + SourceLoc dummyLoc; + memset(&mac, 0, sizeof(mac)); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != CPP_IDENTIFIER) { + CPPErrorToInfoLog("#define"); + return token; + } + name = yylvalpp->sc_ident; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token == '(' && !yylvalpp->sc_int) { + // gather arguments + argc = 0; + do { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (argc == 0 && token == ')') break; + if (token != CPP_IDENTIFIER) { + CPPErrorToInfoLog("#define"); + return token; + } + if (argc < MAX_MACRO_ARGS) + args[argc++] = yylvalpp->sc_ident; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } while (token == ','); + if (token != ')') { + CPPErrorToInfoLog("#define"); + return token; + } + mac.argc = argc; + mac.args = mem_Alloc(macros->pool, argc * sizeof(int)); + memcpy(mac.args, args, argc * sizeof(int)); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + mac.body = NewTokenStream(GetAtomString(atable, name), macros->pool); + while (token != '\n') { + while (token == '\\') { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token == '\n') + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + else + RecordToken(mac.body, '\\', yylvalpp); + } + RecordToken(mac.body, token, yylvalpp); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + }; + + symb = LookUpSymbol(macros, name); + if (symb) { + if (!symb->details.mac.undef) { + // already defined -- need to make sure they are identical + if (symb->details.mac.argc != mac.argc) goto error; + for (argc=0; argc < mac.argc; argc++) + if (symb->details.mac.args[argc] != mac.args[argc]) + goto error; + RewindTokenStream(symb->details.mac.body); + RewindTokenStream(mac.body); + do { + int old_lval, old_token; + old_token = ReadToken(symb->details.mac.body, yylvalpp); + old_lval = yylvalpp->sc_int; + token = ReadToken(mac.body, yylvalpp); + if (token != old_token || yylvalpp->sc_int != old_lval) { + error: + StoreStr("Macro Redefined"); + StoreStr(GetStringOfAtom(atable,name)); + message=GetStrfromTStr(); + DecLineNumber(); + CPPShInfoLogMsg(message); + IncLineNumber(); + ResetTString(); + break; } + } while (token > 0); + } + //FreeMacro(&symb->details.mac); + } else { + dummyLoc.file = 0; + dummyLoc.line = 0; + symb = AddSymbol(&dummyLoc, macros, name, MACRO_S); + } + symb->details.mac = mac; + return '\n'; +} // CPPdefine + +static int CPPundef(yystypepp * yylvalpp) +{ + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + Symbol *symb; + if(token == '\n'){ + CPPErrorToInfoLog("#undef"); + return token; + } + if (token != CPP_IDENTIFIER) + goto error; + symb = LookUpSymbol(macros, yylvalpp->sc_ident); + if (symb) { + symb->details.mac.undef = 1; + } + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != '\n') { + error: + CPPErrorToInfoLog("#undef"); + } + return token; +} // CPPundef + +/* CPPelse -- skip forward to appropriate spot. This is actually used +** to skip to and #endif after seeing an #else, AND to skip to a #else, +** #elif, or #endif after a #if/#ifdef/#ifndef/#elif test was false +*/ + +static int CPPelse(int matchelse, yystypepp * yylvalpp) +{ + int atom,depth=0; + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + while (token > 0) { + if (token != '#') { + while (token != '\n') + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + continue; + } + if ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) != CPP_IDENTIFIER) + continue; + atom = yylvalpp->sc_ident; + if (atom == ifAtom || atom == ifdefAtom || atom == ifndefAtom){ + depth++; cpp->ifdepth++; cpp->elsetracker++; + } + else if (atom == endifAtom) { + if(--depth<=0){ + cpp->elsedepth[cpp->elsetracker]=0; + --cpp->elsetracker; + if (cpp->ifdepth) + --cpp->ifdepth; + break; + } + --cpp->elsetracker; + --cpp->ifdepth; + } + else if (((int)(matchelse) != 0)&& depth==0) { + if (atom == elseAtom ) { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != '\n') { + CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline"); + while (token != '\n') + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + break; + } + else if (atom == elifAtom) { + /* we decrement cpp->ifdepth here, because CPPif will increment + * it and we really want to leave it alone */ + if (cpp->ifdepth){ + --cpp->ifdepth; + --cpp->elsetracker; + } + return CPPif(yylvalpp); + } + } + else if((atom==elseAtom) && (!ChkCorrectElseNesting())){ + CPPErrorToInfoLog("#else after a #else"); + cpp->CompileError=1; + } + }; + return token; +} + +enum eval_prec { + MIN_PREC, + COND, LOGOR, LOGAND, OR, XOR, AND, EQUAL, RELATION, SHIFT, ADD, MUL, UNARY, + MAX_PREC +}; + +static int op_logor(int a, int b) { return a || b; } +static int op_logand(int a, int b) { return a && b; } +static int op_or(int a, int b) { return a | b; } +static int op_xor(int a, int b) { return a ^ b; } +static int op_and(int a, int b) { return a & b; } +static int op_eq(int a, int b) { return a == b; } +static int op_ne(int a, int b) { return a != b; } +static int op_ge(int a, int b) { return a >= b; } +static int op_le(int a, int b) { return a <= b; } +static int op_gt(int a, int b) { return a > b; } +static int op_lt(int a, int b) { return a < b; } +static int op_shl(int a, int b) { return a << b; } +static int op_shr(int a, int b) { return a >> b; } +static int op_add(int a, int b) { return a + b; } +static int op_sub(int a, int b) { return a - b; } +static int op_mul(int a, int b) { return a * b; } +static int op_div(int a, int b) { return a / b; } +static int op_mod(int a, int b) { return a % b; } +static int op_pos(int a) { return a; } +static int op_neg(int a) { return -a; } +static int op_cmpl(int a) { return ~a; } +static int op_not(int a) { return !a; } + +struct { + int token, prec, (*op)(int, int); +} binop[] = { + { CPP_OR_OP, LOGOR, op_logor }, + { CPP_AND_OP, LOGAND, op_logand }, + { '|', OR, op_or }, + { '^', XOR, op_xor }, + { '&', AND, op_and }, + { CPP_EQ_OP, EQUAL, op_eq }, + { CPP_NE_OP, EQUAL, op_ne }, + { '>', RELATION, op_gt }, + { CPP_GE_OP, RELATION, op_ge }, + { '<', RELATION, op_lt }, + { CPP_LE_OP, RELATION, op_le }, + { CPP_LEFT_OP, SHIFT, op_shl }, + { CPP_RIGHT_OP, SHIFT, op_shr }, + { '+', ADD, op_add }, + { '-', ADD, op_sub }, + { '*', MUL, op_mul }, + { '/', MUL, op_div }, + { '%', MUL, op_mod }, +}; + +struct { + int token, (*op)(int); +} unop[] = { + { '+', op_pos }, + { '-', op_neg }, + { '~', op_cmpl }, + { '!', op_not }, +}; + +#define ALEN(A) (sizeof(A)/sizeof(A[0])) + +static int eval(int token, int prec, int *res, int *err, yystypepp * yylvalpp) +{ + int i, val; + Symbol *s; + if (token == CPP_IDENTIFIER) { + if (yylvalpp->sc_ident == definedAtom) { + int needclose = 0; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token == '(') { + needclose = 1; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + if (token != CPP_IDENTIFIER) + goto error; + *res = (s = LookUpSymbol(macros, yylvalpp->sc_ident)) + ? !s->details.mac.undef : 0; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (needclose) { + if (token != ')') + goto error; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + } else if (MacroExpand(yylvalpp->sc_ident, yylvalpp)) { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + return eval(token, prec, res, err, yylvalpp); + } else { + goto error; + } + } else if (token == CPP_INTCONSTANT) { + *res = yylvalpp->sc_int; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } else if (token == '(') { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + token = eval(token, MIN_PREC, res, err, yylvalpp); + if (!*err) { + if (token != ')') + goto error; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + } else { + for (i = ALEN(unop) - 1; i >= 0; i--) { + if (unop[i].token == token) + break; + } + if (i >= 0) { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + token = eval(token, UNARY, res, err, yylvalpp); + *res = unop[i].op(*res); + } else { + goto error; + } + } + while (!*err) { + if (token == ')' || token == '\n') break; + for (i = ALEN(binop) - 1; i >= 0; i--) { + if (binop[i].token == token) + break; + } + if (i < 0 || binop[i].prec <= prec) + break; + val = *res; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + token = eval(token, binop[i].prec, res, err, yylvalpp); + *res = binop[i].op(val, *res); + } + return token; +error: + CPPErrorToInfoLog("incorrect preprocessor directive"); + *err = 1; + *res = 0; + return token; +} // eval + +static int CPPif(yystypepp * yylvalpp) { + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + int res = 0, err = 0; + cpp->elsetracker++; + if (!cpp->ifdepth++) + ifloc = *cpp->tokenLoc; + if(cpp->ifdepth >MAX_IF_NESTING){ + CPPErrorToInfoLog("max #if nesting depth exceeded"); + return 0; + } + token = eval(token, MIN_PREC, &res, &err, yylvalpp); + if (token != '\n') { + CPPWarningToInfoLog("unexpected tokens following the preprocessor directive - expected a newline"); + while (token != '\n') + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + if (!res && !err) { + token = CPPelse(1, yylvalpp); + } + + return token; +} // CPPif + +static int CPPifdef(int defined, yystypepp * yylvalpp) +{ + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + int name = yylvalpp->sc_ident; + if(++cpp->ifdepth >MAX_IF_NESTING){ + CPPErrorToInfoLog("max #if nesting depth exceeded"); + return 0; + } + cpp->elsetracker++; + if (token != CPP_IDENTIFIER) { + defined ? CPPErrorToInfoLog("ifdef"):CPPErrorToInfoLog("ifndef"); + } else { + Symbol *s = LookUpSymbol(macros, name); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != '\n') { + CPPWarningToInfoLog("unexpected tokens following #ifdef preprocessor directive - expected a newline"); + while (token != '\n') + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + if (((s && !s->details.mac.undef) ? 1 : 0) != defined) + token = CPPelse(1, yylvalpp); + } + return token; +} // CPPifdef + +static int CPPline(yystypepp * yylvalpp) +{ + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if(token=='\n'){ + DecLineNumber(); + CPPErrorToInfoLog("#line"); + IncLineNumber(); + return token; + } + else if (token == CPP_INTCONSTANT) { + yylvalpp->sc_int=atoi(yylvalpp->symbol_name); + SetLineNumber(yylvalpp->sc_int); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + if (token == CPP_INTCONSTANT) { + yylvalpp->sc_int=atoi(yylvalpp->symbol_name); + SetStringNumber(yylvalpp->sc_int); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if(token!='\n') + CPPErrorToInfoLog("#line"); + } + else if (token == '\n'){ + return token; + } + else{ + CPPErrorToInfoLog("#line"); + } + } + else{ + CPPErrorToInfoLog("#line"); + } + return token; +} + +static int CPPerror(yystypepp * yylvalpp) { + + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + const char *message; + + while (token != '\n') { + if (token == CPP_FLOATCONSTANT || token == CPP_INTCONSTANT){ + StoreStr(yylvalpp->symbol_name); + }else if(token == CPP_IDENTIFIER || token == CPP_STRCONSTANT){ + StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident)); + }else { + StoreStr(GetStringOfAtom(atable,token)); + } + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + DecLineNumber(); + //store this msg into the shader's information log..set the Compile Error flag!!!! + message=GetStrfromTStr(); + CPPShInfoLogMsg(message); + ResetTString(); + cpp->CompileError=1; + IncLineNumber(); + return '\n'; +}//CPPerror + +static int CPPpragma(yystypepp * yylvalpp) +{ + char SrcStrName[2]; + char** allTokens; + int tokenCount = 0; + int maxTokenCount = 10; + const char* SrcStr; + int i; + + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + if (token=='\n') { + DecLineNumber(); + CPPErrorToInfoLog("#pragma"); + IncLineNumber(); + return token; + } + + allTokens = (char**)malloc(sizeof(char*) * maxTokenCount); + + while (token != '\n') { + if (tokenCount >= maxTokenCount) { + maxTokenCount *= 2; + allTokens = (char**)realloc((char**)allTokens, sizeof(char*) * maxTokenCount); + } + switch (token) { + case CPP_IDENTIFIER: + SrcStr = GetAtomString(atable, yylvalpp->sc_ident); + allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1); + strcpy(allTokens[tokenCount++], SrcStr); + break; + case CPP_INTCONSTANT: + SrcStr = yylvalpp->symbol_name; + allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1); + strcpy(allTokens[tokenCount++], SrcStr); + break; + case CPP_FLOATCONSTANT: + SrcStr = yylvalpp->symbol_name; + allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1); + strcpy(allTokens[tokenCount++], SrcStr); + break; + case -1: + // EOF + CPPShInfoLogMsg("#pragma directive must end with a newline"); + return token; + default: + SrcStrName[0] = token; + SrcStrName[1] = '\0'; + allTokens[tokenCount] = (char*)malloc(2); + strcpy(allTokens[tokenCount++], SrcStrName); + } + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + + cpp->currentInput->ungetch(cpp->currentInput, token, yylvalpp); + HandlePragma((const char**)allTokens, tokenCount); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + for (i = 0; i < tokenCount; ++i) { + free (allTokens[i]); + } + free (allTokens); + + return token; +} // CPPpragma + +#define GL2_VERSION_NUMBER 110 + +static int CPPversion(yystypepp * yylvalpp) +{ + + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + if (cpp->notAVersionToken == 1) + CPPShInfoLogMsg("#version must occur before any other statement in the program"); + + if(token=='\n'){ + DecLineNumber(); + CPPErrorToInfoLog("#version"); + IncLineNumber(); + return token; + } + if (token != CPP_INTCONSTANT) + CPPErrorToInfoLog("#version"); + + yylvalpp->sc_int=atoi(yylvalpp->symbol_name); + //SetVersionNumber(yylvalpp->sc_int); + + if (yylvalpp->sc_int != GL2_VERSION_NUMBER) + CPPShInfoLogMsg("Version number not supported by GL2"); + + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + if (token == '\n'){ + return token; + } + else{ + CPPErrorToInfoLog("#version"); + } + return token; +} // CPPversion + +static int CPPextension(yystypepp * yylvalpp) +{ + + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + char extensionName[80]; + + if(token=='\n'){ + DecLineNumber(); + CPPShInfoLogMsg("extension name not specified"); + IncLineNumber(); + return token; + } + + if (token != CPP_IDENTIFIER) + CPPErrorToInfoLog("#extension"); + + strcpy(extensionName, GetAtomString(atable, yylvalpp->sc_ident)); + + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != ':') { + CPPShInfoLogMsg("':' missing after extension name"); + return token; + } + + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != CPP_IDENTIFIER) { + CPPShInfoLogMsg("behavior for extension not specified"); + return token; + } + + updateExtensionBehavior(extensionName, GetAtomString(atable, yylvalpp->sc_ident)); + + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token == '\n'){ + return token; + } + else{ + CPPErrorToInfoLog("#extension"); + } + return token; +} // CPPextension + +int readCPPline(yystypepp * yylvalpp) +{ + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + const char *message; + int isVersion = 0; + + if (token == CPP_IDENTIFIER) { + if (yylvalpp->sc_ident == defineAtom) { + token = CPPdefine(yylvalpp); + } else if (yylvalpp->sc_ident == elseAtom) { + if(ChkCorrectElseNesting()){ + if (!cpp->ifdepth ){ + CPPErrorToInfoLog("#else mismatch"); + cpp->CompileError=1; + } + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != '\n') { + CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline"); + while (token != '\n') + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + token = CPPelse(0, yylvalpp); + }else{ + CPPErrorToInfoLog("#else after a #else"); + cpp->ifdepth=0; + cpp->notAVersionToken = 1; + return 0; + } + } else if (yylvalpp->sc_ident == elifAtom) { + if (!cpp->ifdepth){ + CPPErrorToInfoLog("#elif mismatch"); + cpp->CompileError=1; + } + // this token is really a dont care, but we still need to eat the tokens + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + while (token != '\n') + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + token = CPPelse(0, yylvalpp); + } else if (yylvalpp->sc_ident == endifAtom) { + cpp->elsedepth[cpp->elsetracker]=0; + --cpp->elsetracker; + if (!cpp->ifdepth){ + CPPErrorToInfoLog("#endif mismatch"); + cpp->CompileError=1; + } + else + --cpp->ifdepth; + } else if (yylvalpp->sc_ident == ifAtom) { + token = CPPif(yylvalpp); + } else if (yylvalpp->sc_ident == ifdefAtom) { + token = CPPifdef(1, yylvalpp); + } else if (yylvalpp->sc_ident == ifndefAtom) { + token = CPPifdef(0, yylvalpp); + } else if (yylvalpp->sc_ident == lineAtom) { + token = CPPline(yylvalpp); + } else if (yylvalpp->sc_ident == pragmaAtom) { + token = CPPpragma(yylvalpp); + } else if (yylvalpp->sc_ident == undefAtom) { + token = CPPundef(yylvalpp); + } else if (yylvalpp->sc_ident == errorAtom) { + token = CPPerror(yylvalpp); + } else if (yylvalpp->sc_ident == versionAtom) { + token = CPPversion(yylvalpp); + isVersion = 1; + } else if (yylvalpp->sc_ident == extensionAtom) { + token = CPPextension(yylvalpp); + } else { + StoreStr("Invalid Directive"); + StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident)); + message=GetStrfromTStr(); + CPPShInfoLogMsg(message); + ResetTString(); + } + } + while (token != '\n' && token != 0 && token != EOF) { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + + cpp->notAVersionToken = !isVersion; + + return token; +} // readCPPline + +void FreeMacro(MacroSymbol *s) { + DeleteTokenStream(s->body); +} + +static int eof_scan(InputSrc *in, yystypepp * yylvalpp) { return -1; } +static void noop(InputSrc *in, int ch, yystypepp * yylvalpp) { } + +static void PushEofSrc() { + InputSrc *in = malloc(sizeof(InputSrc)); + memset(in, 0, sizeof(InputSrc)); + in->scan = eof_scan; + in->getch = eof_scan; + in->ungetch = noop; + in->prev = cpp->currentInput; + cpp->currentInput = in; +} + +static void PopEofSrc() { + if (cpp->currentInput->scan == eof_scan) { + InputSrc *in = cpp->currentInput; + cpp->currentInput = in->prev; + free(in); + } +} + +static TokenStream *PrescanMacroArg(TokenStream *a, yystypepp * yylvalpp) { + int token; + TokenStream *n; + RewindTokenStream(a); + do { + token = ReadToken(a, yylvalpp); + if (token == CPP_IDENTIFIER && LookUpSymbol(macros, yylvalpp->sc_ident)) + break; + } while (token > 0); + if (token <= 0) return a; + n = NewTokenStream("macro arg", 0); + PushEofSrc(); + ReadFromTokenStream(a, 0, 0); + while ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) > 0) { + if (token == CPP_IDENTIFIER && MacroExpand(yylvalpp->sc_ident, yylvalpp)) + continue; + RecordToken(n, token, yylvalpp); + } + PopEofSrc(); + DeleteTokenStream(a); + return n; +} // PrescanMacroArg + +typedef struct MacroInputSrc { + InputSrc base; + MacroSymbol *mac; + TokenStream **args; +} MacroInputSrc; + +/* macro_scan --- +** return the next token for a macro expanion, handling macro args +*/ +static int macro_scan(MacroInputSrc *in, yystypepp * yylvalpp) { + int i; + int token = ReadToken(in->mac->body, yylvalpp); + if (token == CPP_IDENTIFIER) { + for (i = in->mac->argc-1; i>=0; i--) + if (in->mac->args[i] == yylvalpp->sc_ident) break; + if (i >= 0) { + ReadFromTokenStream(in->args[i], yylvalpp->sc_ident, 0); + return cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + } + if (token > 0) return token; + in->mac->busy = 0; + cpp->currentInput = in->base.prev; + if (in->args) { + for (i=in->mac->argc-1; i>=0; i--) + DeleteTokenStream(in->args[i]); + free(in->args); + } + free(in); + return cpp->currentInput->scan(cpp->currentInput, yylvalpp); +} // macro_scan + +/* MacroExpand +** check an identifier (atom) to see if it a macro that should be expanded. +** If it is, push an InputSrc that will produce the appropriate expansion +** and return TRUE. If not, return FALSE. +*/ + +int MacroExpand(int atom, yystypepp * yylvalpp) +{ + Symbol *sym = LookUpSymbol(macros, atom); + MacroInputSrc *in; + int i,j, token, depth=0; + const char *message; + if (atom == __LINE__Atom) { + yylvalpp->sc_int = GetLineNumber(); + sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int); + UngetToken(CPP_INTCONSTANT, yylvalpp); + return 1; + } + if (atom == __FILE__Atom) { + yylvalpp->sc_int = GetStringNumber(); + sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int); + UngetToken(CPP_INTCONSTANT, yylvalpp); + return 1; + } + if (atom == __VERSION__Atom) { + strcpy(yylvalpp->symbol_name,"100"); + yylvalpp->sc_int = atoi(yylvalpp->symbol_name); + UngetToken(CPP_INTCONSTANT, yylvalpp); + return 1; + } + if (!sym || sym->details.mac.undef) return 0; + if (sym->details.mac.busy) return 0; // no recursive expansions + in = malloc(sizeof(*in)); + memset(in, 0, sizeof(*in)); + in->base.scan = (void *)macro_scan; + in->base.line = cpp->currentInput->line; + in->base.name = cpp->currentInput->name; + in->mac = &sym->details.mac; + if (sym->details.mac.args) { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != '(') { + UngetToken(token, yylvalpp); + yylvalpp->sc_ident = atom; + return 0; + } + in->args = malloc(in->mac->argc * sizeof(TokenStream *)); + for (i=0; imac->argc; i++) + in->args[i] = NewTokenStream("macro arg", 0); + i=0;j=0; + do{ + depth = 0; + while(1) { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token <= 0) { + StoreStr("EOF in Macro "); + StoreStr(GetStringOfAtom(atable,atom)); + message=GetStrfromTStr(); + CPPShInfoLogMsg(message); + ResetTString(); + return 1; + } + if((in->mac->argc==0) && (token!=')')) break; + if (depth == 0 && (token == ',' || token == ')')) break; + if (token == '(') depth++; + if (token == ')') depth--; + RecordToken(in->args[i], token, yylvalpp); + j=1; + } + if (token == ')') { + if((in->mac->argc==1) &&j==0) + break; + i++; + break; + } + i++; + }while(i < in->mac->argc); + + if (i < in->mac->argc) { + StoreStr("Too few args in Macro "); + StoreStr(GetStringOfAtom(atable,atom)); + message=GetStrfromTStr(); + CPPShInfoLogMsg(message); + ResetTString(); + } else if (token != ')') { + depth=0; + while (token >= 0 && (depth > 0 || token != ')')) { + if (token == ')') depth--; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token == '(') depth++; + } + + if (token <= 0) { + StoreStr("EOF in Macro "); + StoreStr(GetStringOfAtom(atable,atom)); + message=GetStrfromTStr(); + CPPShInfoLogMsg(message); + ResetTString(); + return 1; + } + StoreStr("Too many args in Macro "); + StoreStr(GetStringOfAtom(atable,atom)); + message=GetStrfromTStr(); + CPPShInfoLogMsg(message); + ResetTString(); + } + for (i=0; imac->argc; i++) { + in->args[i] = PrescanMacroArg(in->args[i], yylvalpp); + } + } +#if 0 + printf(" <%s:%d>found macro %s\n", GetAtomString(atable, loc.file), + loc.line, GetAtomString(atable, atom)); + for (i=0; imac->argc; i++) { + printf("\targ %s = '", GetAtomString(atable, in->mac->args[i])); + DumpTokenStream(stdout, in->args[i]); + printf("'\n"); + } +#endif + /*retain the input source*/ + in->base.prev = cpp->currentInput; + sym->details.mac.busy = 1; + RewindTokenStream(sym->details.mac.body); + cpp->currentInput = &in->base; + return 1; +} // MacroExpand + +int ChkCorrectElseNesting(void) +{ + if(cpp->elsedepth[cpp->elsetracker]==0){ + cpp->elsedepth[cpp->elsetracker]=1; + return 1; + } + return 0; +} + + diff --git a/glslang/MachineIndependent/preprocessor/cpp.h b/glslang/MachineIndependent/preprocessor/cpp.h new file mode 100644 index 00000000..10ecd123 --- /dev/null +++ b/glslang/MachineIndependent/preprocessor/cpp.h @@ -0,0 +1,119 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// cpp.h +// + +#if !defined(__CPP_H) +#define __CPP_H 1 + +#include "parser.h" +#include "tokens.h" + +int InitCPP(void); +int FinalCPP(void); +int readCPPline(yystypepp * yylvalpp); +int MacroExpand(int atom, yystypepp * yylvalpp); +int ChkCorrectElseNesting(void); + +typedef struct MacroSymbol { + int argc; + int *args; + TokenStream *body; + unsigned busy:1; + unsigned undef:1; +} MacroSymbol; + +void FreeMacro(MacroSymbol *); +int PredefineMacro(char *); + +void CPPDebugLogMsg(const char *msg); // Prints information into debug log +void CPPShInfoLogMsg(const char*); // Store cpp Err Msg into Sh.Info.Log +void CPPWarningToInfoLog(const char *msg); // Prints warning messages into info log +void HandlePragma(const char**, int numTokens); // #pragma directive container. +void ResetTString(void); // #error Message as TString. +void CPPErrorToInfoLog(char*); // Stick all cpp errors into Sh.Info.log . +void StoreStr(char*); // Store the TString in Parse Context. +void SetLineNumber(int); // Set line number. +void SetStringNumber(int); // Set string number. +int GetLineNumber(void); // Get the current String Number. +int GetStringNumber(void); // Get the current String Number. +const char* GetStrfromTStr(void); // Convert TString to String. +void updateExtensionBehavior(const char* extName, const char* behavior); +int FreeCPP(void); + +#endif // !(defined(__CPP_H) diff --git a/glslang/MachineIndependent/preprocessor/cppstruct.c b/glslang/MachineIndependent/preprocessor/cppstruct.c new file mode 100644 index 00000000..b1b15fa0 --- /dev/null +++ b/glslang/MachineIndependent/preprocessor/cppstruct.c @@ -0,0 +1,185 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// cppstruct.c +// + +#include +#include + +#include "slglobals.h" + +CPPStruct *cpp = NULL; +static int refCount = 0; + +int InitPreprocessor(void); +int ResetPreprocessor(void); +int FreeCPPStruct(void); +int FinalizePreprocessor(void); + +/* + * InitCPPStruct() - Initilaize the CPP structure. + * + */ + +int InitCPPStruct(void) +{ + int len; + char *p; + + cpp = (CPPStruct *) malloc(sizeof(CPPStruct)); + if (cpp == NULL) + return 0; + + refCount++; + + // Initialize public members: + cpp->pLastSourceLoc = &cpp->lastSourceLoc; + + p = (char *) &cpp->options; + len = sizeof(cpp->options); + while (--len >= 0) + p[len] = 0; + + ResetPreprocessor(); + return 1; +} // InitCPPStruct + +int ResetPreprocessor(void) +{ + // Initialize private members: + + cpp->lastSourceLoc.file = 0; + cpp->lastSourceLoc.line = 0; + cpp->pC=0; + cpp->CompileError=0; + cpp->ifdepth=0; + for(cpp->elsetracker=0; cpp->elsetracker<64; cpp->elsetracker++) + cpp->elsedepth[cpp->elsetracker]=0; + cpp->elsetracker=0; + cpp->tokensBeforeEOF = 0; + return 1; +} + +//Intializing the Preprocessor. + +int InitPreprocessor(void) +{ + # define CPP_STUFF true + # ifdef CPP_STUFF + FreeCPPStruct(); + InitCPPStruct(); + cpp->options.Quiet = 1; + cpp->options.profileString = "generic"; + if (!InitAtomTable(atable, 0)) + return 1; + if (!InitScanner(cpp)) + return 1; + # endif + return 0; +} + +//FreeCPPStruct() - Free the CPP structure. + +int FreeCPPStruct(void) +{ + if (refCount) + { + free(cpp); + refCount--; + } + + return 1; +} + +//Finalizing the Preprocessor. + +int FinalizePreprocessor(void) +{ + # define CPP_STUFF true + # ifdef CPP_STUFF + FreeAtomTable(atable); + FreeCPPStruct(); + FreeScanner(); + # endif + return 0; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////// End of cppstruct.c ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/glslang/MachineIndependent/preprocessor/memory.c b/glslang/MachineIndependent/preprocessor/memory.c new file mode 100644 index 00000000..74e20ff0 --- /dev/null +++ b/glslang/MachineIndependent/preprocessor/memory.c @@ -0,0 +1,191 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +#include +#include +#include + +#ifdef __STDC99__ +#include +#elif defined (_WIN64) +typedef unsigned __int64 uintptr_t; +#else +typedef unsigned int uintptr_t; +#endif + +#include "memory.h" + +// default alignment and chunksize, if called with 0 arguments +#define CHUNKSIZE (64*1024) +#define ALIGN 8 + +// we need to call the `real' malloc and free, not our replacements +#undef malloc +#undef free + +struct chunk { + struct chunk *next; +}; + +struct cleanup { + struct cleanup *next; + void (*fn)(void *); + void *arg; +}; + +struct MemoryPool_rec { + struct chunk *next; + uintptr_t free, end; + size_t chunksize; + uintptr_t alignmask; + struct cleanup *cleanup; +}; + +MemoryPool *mem_CreatePool(size_t chunksize, unsigned int align) +{ + MemoryPool *pool; + + if (align == 0) align = ALIGN; + if (chunksize == 0) chunksize = CHUNKSIZE; + if (align & (align-1)) return 0; + if (chunksize < sizeof(MemoryPool)) return 0; + if (chunksize & (align-1)) return 0; + if (!(pool = malloc(chunksize))) return 0; + pool->next = 0; + pool->chunksize = chunksize; + pool->alignmask = (uintptr_t)(align)-1; + pool->free = ((uintptr_t)(pool + 1) + pool->alignmask) & ~pool->alignmask; + pool->end = (uintptr_t)pool + chunksize; + pool->cleanup = 0; + return pool; +} + +void mem_FreePool(MemoryPool *pool) +{ + struct cleanup *cleanup; + struct chunk *p, *next; + + for (cleanup = pool->cleanup; cleanup; cleanup = cleanup->next) { + cleanup->fn(cleanup->arg); + } + for (p = (struct chunk *)pool; p; p = next) { + next = p->next; + free(p); + } +} + +void *mem_Alloc(MemoryPool *pool, size_t size) +{ + struct chunk *ch; + void *rv = (void *)pool->free; + size = (size + pool->alignmask) & ~pool->alignmask; + if (size <= 0) size = pool->alignmask; + pool->free += size; + if (pool->free > pool->end || pool->free < (uintptr_t)rv) { + size_t minreq = (size + sizeof(struct chunk) + pool->alignmask) + & ~pool->alignmask; + pool->free = (uintptr_t)rv; + if (minreq >= pool->chunksize) { + // request size is too big for the chunksize, so allocate it as + // a single chunk of the right size + ch = malloc(minreq); + if (!ch) return 0; + } else { + ch = malloc(pool->chunksize); + if (!ch) return 0; + pool->free = (uintptr_t)ch + minreq; + pool->end = (uintptr_t)ch + pool->chunksize; + } + ch->next = pool->next; + pool->next = ch; + rv = (void *)(((uintptr_t)(ch+1) + pool->alignmask) & ~pool->alignmask); + } + return rv; +} + +int mem_AddCleanup(MemoryPool *pool, void (*fn)(void *), void *arg) { + struct cleanup *cleanup; + + pool->free = (pool->free + sizeof(void *) - 1) & ~(sizeof(void *)-1); + cleanup = mem_Alloc(pool, sizeof(struct cleanup)); + if (!cleanup) return -1; + cleanup->next = pool->cleanup; + cleanup->fn = fn; + cleanup->arg = arg; + pool->cleanup = cleanup; + return 0; +} diff --git a/glslang/MachineIndependent/preprocessor/memory.h b/glslang/MachineIndependent/preprocessor/memory.h new file mode 100644 index 00000000..dbd6fbdd --- /dev/null +++ b/glslang/MachineIndependent/preprocessor/memory.h @@ -0,0 +1,89 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +#ifndef __MEMORY_H +#define __MEMORY_H + +typedef struct MemoryPool_rec MemoryPool; + +extern MemoryPool *mem_CreatePool(size_t chunksize, unsigned align); +extern void mem_FreePool(MemoryPool *); +extern void *mem_Alloc(MemoryPool *p, size_t size); +extern void *mem_Realloc(MemoryPool *p, void *old, size_t oldsize, size_t newsize); +extern int mem_AddCleanup(MemoryPool *p, void (*fn)(void *), void *arg); + +#endif /* __MEMORY_H */ diff --git a/glslang/MachineIndependent/preprocessor/parser.h b/glslang/MachineIndependent/preprocessor/parser.h new file mode 100644 index 00000000..1b428447 --- /dev/null +++ b/glslang/MachineIndependent/preprocessor/parser.h @@ -0,0 +1,126 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ + +#ifndef BISON_PARSER_H +# define BISON_PARSER_H + +#ifndef yystypepp +typedef struct { + int sc_int; + float sc_fval; + int sc_ident; + char symbol_name[MAX_SYMBOL_NAME_LEN+1]; +} yystypepp; + +# define YYSTYPE_IS_TRIVIAL 1 +#endif +# define CPP_AND_OP 257 +# define CPP_SUB_ASSIGN 259 +# define CPP_MOD_ASSIGN 260 +# define CPP_ADD_ASSIGN 261 +# define CPP_DIV_ASSIGN 262 +# define CPP_MUL_ASSIGN 263 +# define CPP_EQ_OP 264 +# define CPP_XOR_OP 265 +# define ERROR_SY 266 +# define CPP_FLOATCONSTANT 267 +# define CPP_GE_OP 268 +# define CPP_RIGHT_OP 269 +# define CPP_IDENTIFIER 270 +# define CPP_INTCONSTANT 271 +# define CPP_LE_OP 272 +# define CPP_LEFT_OP 273 +# define CPP_DEC_OP 274 +# define CPP_NE_OP 275 +# define CPP_OR_OP 276 +# define CPP_INC_OP 277 +# define CPP_STRCONSTANT 278 +# define CPP_TYPEIDENTIFIER 279 + +# define FIRST_USER_TOKEN_SY 289 + +# define CPP_RIGHT_ASSIGN 280 +# define CPP_LEFT_ASSIGN 281 +# define CPP_AND_ASSIGN 282 +# define CPP_OR_ASSIGN 283 +# define CPP_XOR_ASSIGN 284 +# define CPP_LEFT_BRACKET 285 +# define CPP_RIGHT_BRACKET 286 +# define CPP_LEFT_BRACE 287 +# define CPP_RIGHT_BRACE 288 + +#endif /* not BISON_PARSER_H */ diff --git a/glslang/MachineIndependent/preprocessor/preprocess.h b/glslang/MachineIndependent/preprocessor/preprocess.h new file mode 100644 index 00000000..8f8a5962 --- /dev/null +++ b/glslang/MachineIndependent/preprocessor/preprocess.h @@ -0,0 +1,84 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ + +# include "slglobals.h" +extern CPPStruct *cpp; +int InitCPPStruct(void); +int InitScanner(CPPStruct *cpp); +int InitAtomTable(AtomTable *atable, int htsize); +int ScanFromString(char *s); +char* GetStringOfAtom(AtomTable *atable, int atom); diff --git a/glslang/MachineIndependent/preprocessor/scanner.c b/glslang/MachineIndependent/preprocessor/scanner.c new file mode 100644 index 00000000..6d562a46 --- /dev/null +++ b/glslang/MachineIndependent/preprocessor/scanner.c @@ -0,0 +1,794 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// scanner.c +// + +#include +#include +#include +#include + +#if 0 + #include + #else + #define isinff(x) (((*(int *)&(x) & 0x7f800000L)==0x7f800000L) && \ + ((*(int *)&(x) & 0x007fffffL)==0000000000L)) +#endif + +#include "slglobals.h" + + +typedef struct StringInputSrc { + InputSrc base; + char *p; +} StringInputSrc; + +static int eof_scan(InputSrc *is, yystypepp * yylvalpp) +{ + return EOF; +} // eof_scan + +static void noop(InputSrc *in, int ch, yystypepp * yylvalpp) {} + +static InputSrc eof_inputsrc = { 0, &eof_scan, &eof_scan, &noop }; + +static int byte_scan(InputSrc *, yystypepp * yylvalpp); + +#define EOL_SY '\n' + +#if defined(_WIN32) + #define DBG_BREAKPOINT() __asm int 3 + #elif defined(_M_AMD64) + #define DBG_BREAKPOINT() assert(!"Dbg_Breakpoint"); + #else + #define DBG_BREAKPOINT() + #endif + + #if defined(_WIN32) && !defined(_M_AMD64) + __int64 RDTSC ( void ) { + + __int64 v; + + __asm __emit 0x0f + __asm __emit 0x31 + __asm mov dword ptr v, eax + __asm mov dword ptr v+4, edx + + return v; + } +#endif + + +int InitScanner(CPPStruct *cpp) +{ + // Add various atoms needed by the CPP line scanner: + if (!InitCPP()) + return 0; + + cpp->mostRecentToken = 0; + cpp->tokenLoc = &cpp->ltokenLoc; + + cpp->ltokenLoc.file = 0; + cpp->ltokenLoc.line = 0; + + cpp->currentInput = &eof_inputsrc; + cpp->previous_token = '\n'; + cpp->notAVersionToken = 0; + + return 1; +} // InitScanner + +int FreeScanner(void) +{ + return (FreeCPP()); +} + +/* + * str_getch() + * takes care of reading from multiple strings. + * returns the next-char from the input stream. + * returns EOF when the complete shader is parsed. + */ +static int str_getch(StringInputSrc *in) +{ + for(;;){ + if (*in->p){ + if (*in->p == '\n') { + in->base.line++; + IncLineNumber(); + } + return *in->p++; + } + if(++(cpp->PaWhichStr) < cpp->PaArgc){ + free(in); + SetStringNumber(cpp->PaWhichStr); + SetLineNumber(1); + ScanFromString(cpp->PaArgv[cpp->PaWhichStr]); + in=(StringInputSrc*)cpp->currentInput; + continue; + } + else{ + cpp->currentInput = in->base.prev; + cpp->PaWhichStr=0; + free(in); + return EOF; + } + } +} // str_getch + +static void str_ungetch(StringInputSrc *in, int ch, yystypepp *type) { + if (in->p[-1] == ch)in->p--; + else { + *(in->p)='\0'; //this would take care of shifting to the previous string. + cpp->PaWhichStr--; + } + if (ch == '\n') { + in->base.line--; + DecLineNumber(); + } +} // str_ungetch + +int ScanFromString(char *s) +{ + + StringInputSrc *in = malloc(sizeof(StringInputSrc)); + memset(in, 0, sizeof(StringInputSrc)); + in->p = s; + in->base.line = 1; + in->base.scan = byte_scan; + in->base.getch = (int (*)(InputSrc *, yystypepp *))str_getch; + in->base.ungetch = (void (*)(InputSrc *, int, yystypepp *))str_ungetch; + in->base.prev = cpp->currentInput; + cpp->currentInput = &in->base; + + return 1; +} // ScanFromString; + + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////// Floating point constants: ///////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// +/* + * lBuildFloatValue() - Quick and dirty conversion to floating point. Since all + * we need is single precision this should be quite precise. + */ + +static float lBuildFloatValue(const char *str, int len, int exp) +{ + double val, expval, ten; + int ii, llen, absexp; + float rv; + + val = 0.0; + llen = len; + for (ii = 0; ii < len; ii++) + val = val*10.0 + (str[ii] - '0'); + if (exp != 0) { + absexp = exp > 0 ? exp : -exp; + expval = 1.0f; + ten = 10.0; + while (absexp) { + if (absexp & 1) + expval *= ten; + ten *= ten; + absexp >>= 1; + } + if (exp >= 0) { + val *= expval; + } else { + val /= expval; + } + } + rv = (float)val; + if (isinff(rv)) { + CPPErrorToInfoLog(" ERROR___FP_CONST_OVERFLOW"); + } + return rv; +} // lBuildFloatValue + + +/* + * lFloatConst() - Scan a floating point constant. Assumes that the scanner + * has seen at least one digit, followed by either a decimal '.' or the + * letter 'e'. + */ + +static int lFloatConst(char *str, int len, int ch, yystypepp * yylvalpp) +{ + int HasDecimal, declen, exp, ExpSign; + int str_len; + float lval; + + HasDecimal = 0; + declen = 0; + exp = 0; + + str_len=len; + if (ch == '.') { + str[len++]=ch; + HasDecimal = 1; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + while (ch >= '0' && ch <= '9') { + if (len < MAX_SYMBOL_NAME_LEN) { + declen++; + if (len > 0 || ch != '0') { + str[len] = ch; + len++;str_len++; + } + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } else { + CPPErrorToInfoLog("ERROR___FP_CONST_TOO_LONG"); + len = 1,str_len=1; + } + } + } + + // Exponent: + + if (ch == 'e' || ch == 'E') { + ExpSign = 1; + str[len++]=ch; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '+') { + str[len++]=ch; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } else if (ch == '-') { + ExpSign = -1; + str[len++]=ch; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } + if (ch >= '0' && ch <= '9') { + while (ch >= '0' && ch <= '9') { + exp = exp*10 + ch - '0'; + str[len++]=ch; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } + } else { + CPPErrorToInfoLog("ERROR___ERROR_IN_EXPONENT"); + } + exp *= ExpSign; + } + + if (len == 0) { + lval = 0.0f; + strcpy(str,"0.0"); + } else { + str[len]='\0'; + lval = lBuildFloatValue(str, str_len, exp - declen); + } + // Suffix: + + yylvalpp->sc_fval = lval; + strcpy(yylvalpp->symbol_name,str); + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return CPP_FLOATCONSTANT; +} // lFloatConst + +/////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////// Normal Scanner ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +static int byte_scan(InputSrc *in, yystypepp * yylvalpp) +{ + char symbol_name[MAX_SYMBOL_NAME_LEN + 1]; + char string_val[MAX_STRING_LEN + 1]; + int AlreadyComplained; + int len, ch, ii, ival = 0; + + for (;;) { + yylvalpp->sc_int = 0; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + + while (ch == ' ' || ch == '\t' || ch == '\r') { + yylvalpp->sc_int = 1; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } + + cpp->ltokenLoc.file = cpp->currentInput->name; + cpp->ltokenLoc.line = cpp->currentInput->line; + len = 0; + switch (ch) { + default: + return ch; // Single character token + case EOF: + return -1; + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': case '_': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': + case 'z': + do { + if (len < MAX_SYMBOL_NAME_LEN) { + symbol_name[len] = ch; + len++; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } else { + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } + } while ((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || + ch == '_'); + if (len >= MAX_SYMBOL_NAME_LEN) + len = MAX_SYMBOL_NAME_LEN - 1; + symbol_name[len] = '\0'; + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + yylvalpp->sc_ident = LookUpAddString(atable, symbol_name); + return CPP_IDENTIFIER; + break; + case '0': + yylvalpp->symbol_name[len++] = ch; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == 'x' || ch == 'X') { + yylvalpp->symbol_name[len++] = ch; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if ((ch >= '0' && ch <= '9') || + (ch >= 'A' && ch <= 'F') || + (ch >= 'a' && ch <= 'f')) + { + AlreadyComplained = 0; + ival = 0; + do { + yylvalpp->symbol_name[len++] = ch; + if (ival <= 0x0fffffff) { + if (ch >= '0' && ch <= '9') { + ii = ch - '0'; + } else if (ch >= 'A' && ch <= 'F') { + ii = ch - 'A' + 10; + } else { + ii = ch - 'a' + 10; + } + ival = (ival << 4) | ii; + } else { + if (!AlreadyComplained) + CPPErrorToInfoLog("ERROR___HEX_CONST_OVERFLOW"); + AlreadyComplained = 1; + } + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } while ((ch >= '0' && ch <= '9') || + (ch >= 'A' && ch <= 'F') || + (ch >= 'a' && ch <= 'f')); + } else { + CPPErrorToInfoLog("ERROR___ERROR_IN_HEX_CONSTANT"); + } + yylvalpp->symbol_name[len] = '\0'; + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + yylvalpp->sc_int = ival; + return CPP_INTCONSTANT; + } else if (ch >= '0' && ch <= '7') { // octal integer constants + AlreadyComplained = 0; + ival = 0; + do { + yylvalpp->symbol_name[len++] = ch; + if (ival <= 0x1fffffff) { + ii = ch - '0'; + ival = (ival << 3) | ii; + } else { + if (!AlreadyComplained) + CPPErrorToInfoLog("ERROR___OCT_CONST_OVERFLOW"); + AlreadyComplained = 1; + } + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } while (ch >= '0' && ch <= '7'); + if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'h' || ch == 'x'|| ch == 'E') + return lFloatConst(yylvalpp->symbol_name, len, ch, yylvalpp); + yylvalpp->symbol_name[len] = '\0'; + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + yylvalpp->sc_int = ival; + return CPP_INTCONSTANT; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + ch = '0'; + } + // Fall through... + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + do { + if (len < MAX_SYMBOL_NAME_LEN) { + if (len > 0 || ch != '0') { + yylvalpp->symbol_name[len] = ch; + len++; + } + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } + } while (ch >= '0' && ch <= '9'); + if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'h' || ch == 'x'|| ch == 'E') { + return lFloatConst(yylvalpp->symbol_name, len, ch, yylvalpp); + } else { + yylvalpp->symbol_name[len] = '\0'; + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + ival = 0; + AlreadyComplained = 0; + for (ii = 0; ii < len; ii++) { + ch = yylvalpp->symbol_name[ii] - '0'; + if ((ival > 214748364) || (ival == 214748364 && ch >= 8)) { + if (!AlreadyComplained) + CPPErrorToInfoLog("ERROR___INTEGER_CONST_OVERFLOW"); + AlreadyComplained = 1; + } + ival = ival*10 + ch; + } + yylvalpp->sc_int = ival; + if(ival==0) + strcpy(yylvalpp->symbol_name,"0"); + return CPP_INTCONSTANT; + } + break; + case '-': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '-') { + return CPP_DEC_OP; + } else if (ch == '=') { + return CPP_SUB_ASSIGN; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '-'; + } + case '+': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '+') { + return CPP_INC_OP; + } else if (ch == '=') { + return CPP_ADD_ASSIGN; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '+'; + } + case '*': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '=') { + return CPP_MUL_ASSIGN; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '*'; + } + case '%': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '=') { + return CPP_MOD_ASSIGN; + } else if (ch == '>'){ + return CPP_RIGHT_BRACE; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '%'; + } + case ':': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '>') { + return CPP_RIGHT_BRACKET; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return ':'; + } + case '^': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '^') { + return CPP_XOR_OP; + } else { + if (ch == '=') + return CPP_XOR_ASSIGN; + else{ + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '^'; + } + } + + case '=': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '=') { + return CPP_EQ_OP; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '='; + } + case '!': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '=') { + return CPP_NE_OP; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '!'; + } + case '|': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '|') { + return CPP_OR_OP; + } else { + if (ch == '=') + return CPP_OR_ASSIGN; + else{ + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '|'; + } + } + case '&': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '&') { + return CPP_AND_OP; + } else { + if (ch == '=') + return CPP_AND_ASSIGN; + else{ + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '&'; + } + } + case '<': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '<') { + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if(ch == '=') + return CPP_LEFT_ASSIGN; + else{ + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return CPP_LEFT_OP; + } + } else { + if (ch == '=') { + return CPP_LE_OP; + } else { + if (ch == '%') + return CPP_LEFT_BRACE; + else if (ch == ':') + return CPP_LEFT_BRACKET; + else{ + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '<'; + } + } + } + case '>': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '>') { + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if(ch == '=') + return CPP_RIGHT_ASSIGN; + else{ + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return CPP_RIGHT_OP; + } + } else { + if (ch == '=') { + return CPP_GE_OP; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '>'; + } + } + case '.': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch >= '0' && ch <= '9') { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return lFloatConst(yylvalpp->symbol_name, 0, '.', yylvalpp); + } else { + if (ch == '.') { + return -1; // Special EOF hack + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '.'; + } + } + case '/': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '/') { + do { + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } while (ch != '\n' && ch != EOF); + if (ch == EOF) + return -1; + return '\n'; + } else if (ch == '*') { + int nlcount = 0; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + do { + while (ch != '*') { + if (ch == '\n') nlcount++; + if (ch == EOF) { + CPPErrorToInfoLog("ERROR___EOF_IN_COMMENT"); + return -1; + } + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == EOF) { + CPPErrorToInfoLog("ERROR___EOF_IN_COMMENT"); + return -1; + } + } while (ch != '/'); + if (nlcount) { + return '\n'; + } + // Go try it again... + } else if (ch == '=') { + return CPP_DIV_ASSIGN; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '/'; + } + break; + case '"': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + while (ch != '"' && ch != '\n' && ch != EOF) { + if (ch == '\\') { + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '\n' || ch == EOF) { + break; + } + } + if (len < MAX_STRING_LEN) { + string_val[len] = ch; + len++; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } + }; + string_val[len] = '\0'; + if (ch == '"') { + yylvalpp->sc_ident = LookUpAddString(atable, string_val); + return CPP_STRCONSTANT; + } else { + CPPErrorToInfoLog("ERROR___CPP_EOL_IN_STRING"); + return ERROR_SY; + } + } + } +} // byte_scan + +int yylex_CPP(char* buf, int maxSize) +{ + yystypepp yylvalpp; + int token = '\n'; + + for(;;) { + + char* tokenString = 0; + token = cpp->currentInput->scan(cpp->currentInput, &yylvalpp); + if(check_EOF(token)) + return 0; + if (token == '#') { + if (cpp->previous_token == '\n'|| cpp->previous_token == 0) { + token = readCPPline(&yylvalpp); + if(check_EOF(token)) + return 0; + continue; + } else { + CPPErrorToInfoLog("preprocessor command must not be preceded by any other statement in that line"); + return 0; + } + } + cpp->previous_token = token; + // expand macros + if (token == CPP_IDENTIFIER && MacroExpand(yylvalpp.sc_ident, &yylvalpp)) { + cpp->notAVersionToken = 1; + continue; + } + + if (token == '\n') + continue; + + if (token == CPP_IDENTIFIER) { + cpp->notAVersionToken = 1; + tokenString = GetStringOfAtom(atable,yylvalpp.sc_ident); + } else if (token == CPP_FLOATCONSTANT||token == CPP_INTCONSTANT){ + cpp->notAVersionToken = 1; + tokenString = yylvalpp.symbol_name; + } else { + cpp->notAVersionToken = 1; + tokenString = GetStringOfAtom(atable,token); + } + + if (tokenString) { + if ((signed)strlen(tokenString) >= maxSize) { + cpp->tokensBeforeEOF = 1; + return maxSize; + } else if (strlen(tokenString) > 0) { + strcpy(buf, tokenString); + cpp->tokensBeforeEOF = 1; + return (int)strlen(tokenString); + } + + return 0; + } + } + + return 0; +} // yylex + +//Checks if the token just read is EOF or not. +int check_EOF(int token) +{ + if(token==-1){ + if(cpp->ifdepth >0){ + CPPErrorToInfoLog("#endif missing!! Compilation stopped"); + cpp->CompileError=1; + } + return 1; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////// End of scanner.c ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/glslang/MachineIndependent/preprocessor/scanner.h b/glslang/MachineIndependent/preprocessor/scanner.h new file mode 100644 index 00000000..fb4d0574 --- /dev/null +++ b/glslang/MachineIndependent/preprocessor/scanner.h @@ -0,0 +1,118 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// scanner.h +// + +#if !defined(__SCANNER_H) +#define __SCANNER_H 1 + +#define MAX_SYMBOL_NAME_LEN 128 +#define MAX_STRING_LEN 512 + +#include "parser.h" + +// Not really atom table stuff but needed first... + +typedef struct SourceLoc_Rec { + unsigned short file, line; +} SourceLoc; + +int yyparse (void); + +int yylex_CPP(char* buf, int maxSize); + +typedef struct InputSrc { + struct InputSrc *prev; + int (*scan)(struct InputSrc *, yystypepp *); + int (*getch)(struct InputSrc *, yystypepp *); + void (*ungetch)(struct InputSrc *, int, yystypepp *); + int name; /* atom */ + int line; +} InputSrc; + +int InitScanner(CPPStruct *cpp); // Intialise the cpp scanner. +int ScanFromString(char *); // Start scanning the input from the string mentioned. +int check_EOF(int); // check if we hit a EOF abruptly +void CPPErrorToInfoLog(char *); // sticking the msg,line into the Shader's.Info.log +void SetLineNumber(int); +void SetStringNumber(int); +void IncLineNumber(void); +void DecLineNumber(void); +int FreeScanner(void); // Free the cpp scanner +#endif // !(defined(__SCANNER_H) + diff --git a/glslang/MachineIndependent/preprocessor/slglobals.h b/glslang/MachineIndependent/preprocessor/slglobals.h new file mode 100644 index 00000000..ebe27c30 --- /dev/null +++ b/glslang/MachineIndependent/preprocessor/slglobals.h @@ -0,0 +1,115 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// slglobals.h +// + +#if !defined(__SLGLOBALS_H) +#define __SLGLOBALS_H 1 + +typedef struct CPPStruct_Rec CPPStruct; + +extern CPPStruct *cpp; + +#undef CPPC_DEBUG_THE_COMPILER +#if defined(_DEBUG) +#define CPPC_DEBUG_THE_COMPILER 1 +#endif + +#undef CPPC_ENABLE_TOOLS +#define CPPC_ENABLE_TOOLS 1 + +#include "memory.h" +#include "atom.h" +#include "scanner.h" +#include "cpp.h" +#include "tokens.h" +#include "symbols.h" +#include "compile.h" +#if !defined(NO_PARSER) +#include "parser.h" +#endif + +#if !defined(NULL) +#define NULL 0 +#endif + +#endif // !(defined(__SLGLOBALS_H) + + + + diff --git a/glslang/MachineIndependent/preprocessor/symbols.c b/glslang/MachineIndependent/preprocessor/symbols.c new file mode 100644 index 00000000..2929ef1d --- /dev/null +++ b/glslang/MachineIndependent/preprocessor/symbols.c @@ -0,0 +1,318 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// symbols.c +// + +#include +#include +#include +#include + +#include "slglobals.h" + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////// Symbol Table Variables: /////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +Scope *ScopeList = NULL; +Scope *CurrentScope = NULL; +Scope *GlobalScope = NULL; + +static void unlinkScope(void *_scope) { + Scope *scope = _scope; + + if (scope->next) + scope->next->prev = scope->prev; + if (scope->prev) + scope->prev->next = scope->next; + else + ScopeList = scope->next; +} + +/* + * NewScope() + * + */ +Scope *NewScopeInPool(MemoryPool *pool) +{ + Scope *lScope; + + lScope = mem_Alloc(pool, sizeof(Scope)); + lScope->pool = pool; + lScope->parent = NULL; + lScope->funScope = NULL; + lScope->symbols = NULL; + + lScope->level = 0; + + lScope->programs = NULL; + if ((lScope->next = ScopeList)) + ScopeList->prev = lScope; + lScope->prev = 0; + ScopeList = lScope; + mem_AddCleanup(pool, unlinkScope, lScope); + return lScope; +} // NewScope + +/* + * PushScope() + * + */ + +void PushScope(Scope *fScope) +{ + Scope *lScope; + + if (CurrentScope) { + fScope->level = CurrentScope->level + 1; + if (fScope->level == 1) { + if (!GlobalScope) { + /* HACK - CTD -- if GlobalScope==NULL and level==1, we're + * defining a function in the superglobal scope. Things + * will break if we leave the level as 1, so we arbitrarily + * set it to 2 */ + fScope->level = 2; + } + } + if (fScope->level >= 2) { + lScope = fScope; + while (lScope->level > 2) + lScope = lScope->next; + fScope->funScope = lScope; + } + } else { + fScope->level = 0; + } + fScope->parent = CurrentScope; + CurrentScope = fScope; +} // PushScope + +/* + * PopScope() + * + */ + +Scope *PopScope(void) +{ + Scope *lScope; + + lScope = CurrentScope; + if (CurrentScope) + CurrentScope = CurrentScope->parent; + return lScope; +} // PopScope + +/* + * NewSymbol() - Allocate a new symbol node; + * + */ + +Symbol *NewSymbol(SourceLoc *loc, Scope *fScope, int name, symbolkind kind) +{ + Symbol *lSymb; + char *pch; + int ii; + + lSymb = (Symbol *) mem_Alloc(fScope->pool, sizeof(Symbol)); + lSymb->left = NULL; + lSymb->right = NULL; + lSymb->next = NULL; + lSymb->name = name; + lSymb->loc = *loc; + lSymb->kind = kind; + + // Clear union area: + + pch = (char *) &lSymb->details; + for (ii = 0; ii < sizeof(lSymb->details); ii++) + *pch++ = 0; + return lSymb; +} // NewSymbol + +/* + * lAddToTree() - Using a binary tree is not a good idea for basic atom values because they + * are generated in order. We'll fix this later (by reversing the bit pattern). + */ + +static void lAddToTree(Symbol **fSymbols, Symbol *fSymb) +{ + Symbol *lSymb; + int lrev, frev; + + lSymb = *fSymbols; + if (lSymb) { + frev = GetReversedAtom(atable, fSymb->name); + while (lSymb) { + lrev = GetReversedAtom(atable, lSymb->name); + if (lrev == frev) { + CPPErrorToInfoLog("GetAtomString(atable, fSymb->name)"); + break; + } else { + if (lrev > frev) { + if (lSymb->left) { + lSymb = lSymb->left; + } else { + lSymb->left = fSymb; + break; + } + } else { + if (lSymb->right) { + lSymb = lSymb->right; + } else { + lSymb->right = fSymb; + break; + } + } + } + } + } else { + *fSymbols = fSymb; + } +} // lAddToTree + + +/* + * AddSymbol() - Add a variable, type, or function name to a scope. + * + */ + +Symbol *AddSymbol(SourceLoc *loc, Scope *fScope, int atom, symbolkind kind) +{ + Symbol *lSymb; + + if (!fScope) + fScope = CurrentScope; + lSymb = NewSymbol(loc, fScope, atom, kind); + lAddToTree(&fScope->symbols, lSymb); + return lSymb; +} // AddSymbol + + +/*********************************************************************************************/ +/************************************ Symbol Semantic Functions ******************************/ +/*********************************************************************************************/ + +/* + * LookUpLocalSymbol() + * + */ + +Symbol *LookUpLocalSymbol(Scope *fScope, int atom) +{ + Symbol *lSymb; + int rname, ratom; + + ratom = GetReversedAtom(atable, atom); + if (!fScope) + fScope = CurrentScope; + lSymb = fScope->symbols; + while (lSymb) { + rname = GetReversedAtom(atable, lSymb->name); + if (rname == ratom) { + return lSymb; + } else { + if (rname > ratom) { + lSymb = lSymb->left; + } else { + lSymb = lSymb->right; + } + } + } + return NULL; +} // LookUpLocalSymbol + +/* + * LookUpSymbol() + * + */ + +Symbol *LookUpSymbol(Scope *fScope, int atom) +{ + Symbol *lSymb; + + if (!fScope) + fScope = CurrentScope; + while (fScope) { + lSymb = LookUpLocalSymbol(fScope, atom); + if (lSymb) + return lSymb; + fScope = fScope->parent; + } + return NULL; +} // LookUpSymbol + diff --git a/glslang/MachineIndependent/preprocessor/symbols.h b/glslang/MachineIndependent/preprocessor/symbols.h new file mode 100644 index 00000000..618418c7 --- /dev/null +++ b/glslang/MachineIndependent/preprocessor/symbols.h @@ -0,0 +1,145 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// symbols.h +// + +#if !defined(__SYMBOLS_H) +#define __SYMBOLS_H 1 + +#include "memory.h" + +typedef enum symbolkind { + MACRO_S +} symbolkind; + +// Typedefs for things defined here in "symbols.h": + +typedef struct Scope_Rec Scope; +typedef struct Symbol_Rec Symbol; + +typedef struct SymbolList_Rec { + struct SymbolList_Rec *next; + Symbol *symb; +} SymbolList; + +struct Scope_Rec { + Scope *next, *prev; // doubly-linked list of all scopes + Scope *parent; + Scope *funScope; // Points to base scope of enclosing function + MemoryPool *pool; // pool used for allocation in this scope + Symbol *symbols; + + int level; // 0 = super globals, 1 = globals, etc. + + // Only used at global scope (level 1): + SymbolList *programs; // List of programs for this compilation. +}; + + +// Symbol table is a simple binary tree. + +#include "cpp.h" // to get MacroSymbol def + +struct Symbol_Rec { + Symbol *left, *right; + Symbol *next; + int name; // Name atom + SourceLoc loc; + symbolkind kind; + union { + MacroSymbol mac; + } details; +}; + +extern Scope *CurrentScope; +extern Scope *GlobalScope; +extern Scope *ScopeList; + +Scope *NewScopeInPool(MemoryPool *); +#define NewScope() NewScopeInPool(CurrentScope->pool) +void PushScope(Scope *fScope); +Scope *PopScope(void); +Symbol *NewSymbol(SourceLoc *loc, Scope *fScope, int name, symbolkind kind); +Symbol *AddSymbol(SourceLoc *loc, Scope *fScope, int atom, symbolkind kind); +Symbol *LookUpLocalSymbol(Scope *fScope, int atom); +Symbol *LookUpSymbol(Scope *fScope, int atom); +void CPPErrorToInfoLog(char *); + + +#endif // !defined(__SYMBOLS_H) + diff --git a/glslang/MachineIndependent/preprocessor/tokens.c b/glslang/MachineIndependent/preprocessor/tokens.c new file mode 100644 index 00000000..c2f79115 --- /dev/null +++ b/glslang/MachineIndependent/preprocessor/tokens.c @@ -0,0 +1,472 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// tokens.c +// + +#include +#include +#include +#include +#include + +#include "slglobals.h" + +/////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////// Preprocessor and Token Recorder and Playback: //////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +/* + * idstr() + * Copy a string to a malloc'ed block and convert it into something suitable + * for an ID + * + */ + +static char *idstr(const char *fstr, MemoryPool *pool) +{ + size_t len; + char *str, *t; + const char *f; + + len = strlen(fstr); + if (!pool) + str = (char *) malloc(len + 1); + else + str = (char *) mem_Alloc(pool, len + 1); + + for (f=fstr, t=str; *f; f++) { + if (isalnum(*f)) *t++ = *f; + else if (*f == '.' || *f == '/') *t++ = '_'; + } + *t = 0; + return str; +} // idstr + + +/* + * lNewBlock() + * + */ + +static TokenBlock *lNewBlock(TokenStream *fTok, MemoryPool *pool) +{ + TokenBlock *lBlock; + + if (!pool) + lBlock = (TokenBlock *) malloc(sizeof(TokenBlock) + 256); + else + lBlock = (TokenBlock *) mem_Alloc(pool, sizeof(TokenBlock) + 256); + lBlock->count = 0; + lBlock->current = 0; + lBlock->data = (unsigned char *) lBlock + sizeof(TokenBlock); + lBlock->max = 256; + lBlock->next = NULL; + if (fTok->head) { + fTok->current->next = lBlock; + } else { + fTok->head = lBlock; + } + fTok->current = lBlock; + return lBlock; +} // lNewBlock + +/* + * lAddByte() + * + */ + +static void lAddByte(TokenStream *fTok, unsigned char fVal) +{ + TokenBlock *lBlock; + lBlock = fTok->current; + if (lBlock->count >= lBlock->max) + lBlock = lNewBlock(fTok, 0); + lBlock->data[lBlock->count++] = fVal; +} // lAddByte + + + +/* + * lReadByte() - Get the next byte from a stream. + * + */ + +static int lReadByte(TokenStream *pTok) +{ + TokenBlock *lBlock; + int lval = -1; + + lBlock = pTok->current; + if (lBlock) { + if (lBlock->current >= lBlock->count) { + lBlock = lBlock->next; + if (lBlock) + lBlock->current = 0; + pTok->current = lBlock; + } + if (lBlock) + lval = lBlock->data[lBlock->current++]; + } + return lval; +} // lReadByte + +/////////////////////////////////////// Global Functions:////////////////////////////////////// + +/* + * NewTokenStream() + * + */ + +TokenStream *NewTokenStream(const char *name, MemoryPool *pool) +{ + TokenStream *pTok; + + if (!pool) + pTok = (TokenStream *) malloc(sizeof(TokenStream)); + else + pTok = (TokenStream*)mem_Alloc(pool, sizeof(TokenStream)); + pTok->next = NULL; + pTok->name = idstr(name, pool); + pTok->head = NULL; + pTok->current = NULL; + lNewBlock(pTok, pool); + return pTok; +} // NewTokenStream + +/* + * DeleteTokenStream() + * + */ + +void DeleteTokenStream(TokenStream *pTok) +{ + TokenBlock *pBlock, *nBlock; + + if (pTok) { + pBlock = pTok->head; + while (pBlock) { + nBlock = pBlock->next; + free(pBlock); + pBlock = nBlock; + } + if (pTok->name) + free(pTok->name); + free(pTok); + } +} // DeleteTokenStream + +/* + * RecordToken() - Add a token to the end of a list for later playback or printout. + * + */ + +void RecordToken(TokenStream *pTok, int token, yystypepp * yylvalpp) +{ + const char *s; + unsigned char *str=NULL; + + if (token > 256) + lAddByte(pTok, (unsigned char)((token & 0x7f) + 0x80)); + else + lAddByte(pTok, (unsigned char)(token & 0x7f)); + switch (token) { + case CPP_IDENTIFIER: + case CPP_TYPEIDENTIFIER: + case CPP_STRCONSTANT: + s = GetAtomString(atable, yylvalpp->sc_ident); + while (*s) + lAddByte(pTok, (unsigned char) *s++); + lAddByte(pTok, 0); + break; + case CPP_FLOATCONSTANT: + case CPP_INTCONSTANT: + str=yylvalpp->symbol_name; + while (*str){ + lAddByte(pTok,(unsigned char) *str); + *str++; + } + lAddByte(pTok, 0); + break; + case '(': + lAddByte(pTok, (unsigned char)(yylvalpp->sc_int ? 1 : 0)); + default: + break; + } +} // RecordToken + +/* + * RewindTokenStream() - Reset a token stream in preperation for reading. + * + */ + +void RewindTokenStream(TokenStream *pTok) +{ + if (pTok->head) { + pTok->current = pTok->head; + pTok->current->current = 0; + } +} // RewindTokenStream + +/* + * ReadToken() - Read the next token from a stream. + * + */ + +int ReadToken(TokenStream *pTok, yystypepp * yylvalpp) +{ + char symbol_name[MAX_SYMBOL_NAME_LEN + 1]; + char string_val[MAX_STRING_LEN + 1]; + int ltoken, len; + char ch; + + ltoken = lReadByte(pTok); + if (ltoken >= 0) { + if (ltoken > 127) + ltoken += 128; + switch (ltoken) { + case CPP_IDENTIFIER: + case CPP_TYPEIDENTIFIER: + len = 0; + ch = lReadByte(pTok); + while ((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || + ch == '_') + { + if (len < MAX_SYMBOL_NAME_LEN) { + symbol_name[len] = ch; + len++; + ch = lReadByte(pTok); + } + } + symbol_name[len] = '\0'; + assert(ch == '\0'); + yylvalpp->sc_ident = LookUpAddString(atable, symbol_name); + return CPP_IDENTIFIER; + break; + case CPP_STRCONSTANT: + len = 0; + while ((ch = lReadByte(pTok)) != 0) + if (len < MAX_STRING_LEN) + string_val[len++] = ch; + string_val[len] = 0; + yylvalpp->sc_ident = LookUpAddString(atable, string_val); + break; + case CPP_FLOATCONSTANT: + len = 0; + ch = lReadByte(pTok); + while ((ch >= '0' && ch <= '9')||(ch=='e'||ch=='E'||ch=='.')||(ch=='+'||ch=='-')) + { + if (len < MAX_SYMBOL_NAME_LEN) { + symbol_name[len] = ch; + len++; + ch = lReadByte(pTok); + } + } + symbol_name[len] = '\0'; + assert(ch == '\0'); + strcpy(yylvalpp->symbol_name,symbol_name); + yylvalpp->sc_fval=(float)atof(yylvalpp->symbol_name); + break; + case CPP_INTCONSTANT: + len = 0; + ch = lReadByte(pTok); + while ((ch >= '0' && ch <= '9')) + { + if (len < MAX_SYMBOL_NAME_LEN) { + symbol_name[len] = ch; + len++; + ch = lReadByte(pTok); + } + } + symbol_name[len] = '\0'; + assert(ch == '\0'); + strcpy(yylvalpp->symbol_name,symbol_name); + yylvalpp->sc_int=atoi(yylvalpp->symbol_name); + break; + case '(': + yylvalpp->sc_int = lReadByte(pTok); + break; + } + return ltoken; + } + return EOF_SY; +} // ReadToken + +typedef struct TokenInputSrc { + InputSrc base; + TokenStream *tokens; + int (*final)(CPPStruct *); +} TokenInputSrc; + +static int scan_token(TokenInputSrc *in, yystypepp * yylvalpp) +{ + int token = ReadToken(in->tokens, yylvalpp); + int (*final)(CPPStruct *); + cpp->tokenLoc->file = cpp->currentInput->name; + cpp->tokenLoc->line = cpp->currentInput->line; + if (token == '\n') { + in->base.line++; + return token; + } + if (token > 0) return token; + cpp->currentInput = in->base.prev; + final = in->final; + free(in); + if (final && !final(cpp)) return -1; + return cpp->currentInput->scan(cpp->currentInput, yylvalpp); +} + +int ReadFromTokenStream(TokenStream *ts, int name, int (*final)(CPPStruct *)) +{ + TokenInputSrc *in = malloc(sizeof(TokenInputSrc)); + memset(in, 0, sizeof(TokenInputSrc)); + in->base.name = name; + in->base.prev = cpp->currentInput; + in->base.scan = (int (*)(InputSrc *, yystypepp *))scan_token; + in->base.line = 1; + in->tokens = ts; + in->final = final; + RewindTokenStream(ts); + cpp->currentInput = &in->base; + return 1; +} + +typedef struct UngotToken { + InputSrc base; + int token; + yystypepp lval; +} UngotToken; + +static int reget_token(UngotToken *t, yystypepp * yylvalpp) +{ + int token = t->token; + *yylvalpp = t->lval; + cpp->currentInput = t->base.prev; + free(t); + return token; +} + +void UngetToken(int token, yystypepp * yylvalpp) { + UngotToken *t = malloc(sizeof(UngotToken)); + memset(t, 0, sizeof(UngotToken)); + t->token = token; + t->lval = *yylvalpp; + t->base.scan = (void *)reget_token; + t->base.prev = cpp->currentInput; + t->base.name = cpp->currentInput->name; + t->base.line = cpp->currentInput->line; + cpp->currentInput = &t->base; +} + + +void DumpTokenStream(FILE *fp, TokenStream *s, yystypepp * yylvalpp) { + int token; + char str[100]; + + if (fp == 0) fp = stdout; + RewindTokenStream(s); + while ((token = ReadToken(s, yylvalpp)) > 0) { + switch (token) { + case CPP_IDENTIFIER: + case CPP_TYPEIDENTIFIER: + sprintf(str, "%s ", GetAtomString(atable, yylvalpp->sc_ident)); + break; + case CPP_STRCONSTANT: + sprintf(str, "\"%s\"", GetAtomString(atable, yylvalpp->sc_ident)); + break; + case CPP_FLOATCONSTANT: + //printf("%g9.6 ", yylvalpp->sc_fval); + break; + case CPP_INTCONSTANT: + //printf("%d ", yylvalpp->sc_int); + break; + default: + if (token >= 127) + sprintf(str, "%s ", GetAtomString(atable, token)); + else + sprintf(str, "%c", token); + break; + } + CPPDebugLogMsg(str); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////// End of tokens.c /////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/glslang/MachineIndependent/preprocessor/tokens.h b/glslang/MachineIndependent/preprocessor/tokens.h new file mode 100644 index 00000000..dda09caa --- /dev/null +++ b/glslang/MachineIndependent/preprocessor/tokens.h @@ -0,0 +1,122 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// tokens.h +// + +#if !defined(__TOKENS_H) +#define __TOKENS_H 1 + +#include "parser.h" + +#define EOF_SY (-1) + +typedef struct TokenBlock_Rec TokenBlock; + +typedef struct TokenStream_Rec { + struct TokenStream_Rec *next; + char *name; + TokenBlock *head; + TokenBlock *current; +} TokenStream; + +struct TokenBlock_Rec { + TokenBlock *next; + int current; + int count; + int max; + unsigned char *data; +}; + +extern TokenStream stdlib_cpp_stream; + + +TokenStream *NewTokenStream(const char *name, MemoryPool *pool); +void DeleteTokenStream(TokenStream *pTok); +void RecordToken(TokenStream *pTok, int token, yystypepp * yylvalpp); +void RewindTokenStream(TokenStream *pTok); +int ReadToken(TokenStream *pTok, yystypepp * yylvalpp); +int ReadFromTokenStream(TokenStream *pTok, int name, int (*final)(CPPStruct *)); +void UngetToken(int, yystypepp * yylvalpp); + +#if defined(CPPC_ENABLE_TOOLS) + +void DumpTokenStream(FILE *, TokenStream *, yystypepp * yylvalpp); + +#endif // defined(CPPC_ENABLE_TOOLS) + +#endif // !defined(__TOKENS_H) diff --git a/glslang/MachineIndependent/unistd.h b/glslang/MachineIndependent/unistd.h new file mode 100644 index 00000000..c7c91470 --- /dev/null +++ b/glslang/MachineIndependent/unistd.h @@ -0,0 +1 @@ +// This is a NULL file and is meant to be empty diff --git a/glslang/OSDependent/Linux/Makefile b/glslang/OSDependent/Linux/Makefile new file mode 100644 index 00000000..dc8d0745 --- /dev/null +++ b/glslang/OSDependent/Linux/Makefile @@ -0,0 +1,62 @@ +#### +#### This Makefile should be used in the Linux Compiler build. This Makefile build the OSDependent +#### component as a static library. +#### + +# +# Compilation related +# +INCLUDE = -I. -I../.. -I../../Include -I../../../OGLCompilersDLL +WARNINGS = -Wall -Wwrite-strings -Wpointer-arith -Wcast-align -Wstrict-prototypes \ + -Wnested-externs +DEFINE = -Dlinux -D__i386__ + +CPP = g++ +CPPOPTIONS = -O3 -Wno-deprecated -D_ALT_NS=1 +CPPOPTIONS = -g -Wno-deprecated -D_ALT_NS=1 +CPPFLAGS = $(CPPOPTIONS) $(DEFINE) $(INCLUDE) + +# +# Linking related +# +AR = ar +STATIC_OPTION = rcs + +# +# Misc +# +export PERL = perl +export RM = rm -f +export MV = mv -f +export DEPEND = g++ -M + +# +# Object file variables are defined here. +# +OSSRCS = ossource.cpp +OSOBJS = ossource.o + +LIBNAME = libOssource.a + +all : $(LIBNAME) + +$(LIBNAME) : $(OSOBJS) + $(AR) $(STATIC_OPTION) $(LIBNAME) $(OSOBJS) + +%.o : %.cpp + $(CPP) $(CPPFLAGS) -c $< + + +# +# Dependency +# +depend : $(OSSRCS) + $(DEPEND) $(CPPFLAGS) $(OSSRCS) > depend +include depend + +# +# Cleanup +# +.PHONY : clean +clean : + $(RM) *.o *.a diff --git a/glslang/OSDependent/Linux/osinclude.h b/glslang/OSDependent/Linux/osinclude.h new file mode 100644 index 00000000..883c993d --- /dev/null +++ b/glslang/OSDependent/Linux/osinclude.h @@ -0,0 +1,78 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef __OSINCLUDE_H +#define __OSINCLUDE_H + +// +// This file contains any Linux specific functions. +// + +#if !(defined(linux)) +#error Trying to include a Linux specific file in a non-Linux build. +#endif + +#include +#include +#include +#include +#include "Include/InitializeGlobals.h" +#include "Include/PoolAlloc.h" + +#define _vsnprintf vsnprintf + + +void DetachThreadLinux(void *); + +// +// Thread Local Storage Operations +// +typedef unsigned int OS_TLSIndex; +#define OS_INVALID_TLS_INDEX 0xFFFFFFFF + +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) +{ + // + // This function should return 0 if nIndex is invalid. + // + assert(nIndex != OS_INVALID_TLS_INDEX); + return pthread_getspecific(nIndex); +} + +#endif // __OSINCLUDE_H diff --git a/glslang/OSDependent/Linux/ossource.cpp b/glslang/OSDependent/Linux/ossource.cpp new file mode 100644 index 00000000..08757b73 --- /dev/null +++ b/glslang/OSDependent/Linux/ossource.cpp @@ -0,0 +1,141 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +// +// This file contains the Linux specific functions +// +#include "osinclude.h" +#include "InitializeDll.h" + +#if !(defined(linux)) +#error Trying to build a Linux specific file in a non-Linux build. +#endif + + +// +// Thread cleanup +// + +// +// Wrapper for Linux call to DetachThread. This is required as pthread_cleanup_push() expects +// the cleanup routine to return void. +// +void DetachThreadLinux(void *) +{ + DetachThread(); +} + + +// +// Registers cleanup handler, sets cancel type and state, and excecutes the thread specific +// cleanup handler. This function will be called in the Standalone.cpp for regression +// testing. When OpenGL applications are run with the driver code, Linux OS does the +// thread cleanup. +// +void OS_CleanupThreadData(void) +{ + int old_cancel_state, old_cancel_type; + void *cleanupArg = NULL; + + // + // Set thread cancel state and push cleanup handler. + // + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancel_state); + pthread_cleanup_push(DetachThreadLinux, (void *) cleanupArg); + + // + // Put the thread in deferred cancellation mode. + // + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old_cancel_type); + + // + // Pop cleanup handler and execute it prior to unregistering the cleanup handler. + // + pthread_cleanup_pop(1); + + // + // Restore the thread's previous cancellation mode. + // + pthread_setcanceltype(old_cancel_state, NULL); +} + + +// +// 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/glslang/OSDependent/Windows/main.cpp b/glslang/OSDependent/Windows/main.cpp new file mode 100644 index 00000000..ee4ad55b --- /dev/null +++ b/glslang/OSDependent/Windows/main.cpp @@ -0,0 +1,69 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#include "InitializeDll.h" + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + + if (!InitProcess()) + return FALSE; + break; + case DLL_THREAD_ATTACH: + + if (!InitThread()) + return FALSE; + break; + + case DLL_THREAD_DETACH: + + if (!DetachThread()) + return FALSE; + break; + + case DLL_PROCESS_DETACH: + + DetachProcess(); + break; + + default: + assert(0 && "DllMain(): Reason for calling DLL Main is unknown"); + return FALSE; + } + + return TRUE; +} diff --git a/glslang/OSDependent/Windows/osinclude.h b/glslang/OSDependent/Windows/osinclude.h new file mode 100644 index 00000000..652f5586 --- /dev/null +++ b/glslang/OSDependent/Windows/osinclude.h @@ -0,0 +1,69 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef __OSINCLUDE_H +#define __OSINCLUDE_H + +// +// This file contains contains the window's specific datatypes and +// declares any windows specific functions. +// + +#if !(defined(_WIN32) || defined(_WIN64)) +#error Trying to include a windows specific file in a non windows build. +#endif + +#define STRICT +#define VC_EXTRALEAN 1 +#include +#include + + +// +// Thread Local Storage Operations +// +typedef DWORD OS_TLSIndex; +#define OS_INVALID_TLS_INDEX (TLS_OUT_OF_INDEXES) + +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); + return TlsGetValue(nIndex); +} + +#endif // __OSINCLUDE_H diff --git a/glslang/OSDependent/Windows/ossource.cpp b/glslang/OSDependent/Windows/ossource.cpp new file mode 100644 index 00000000..3c2cb85a --- /dev/null +++ b/glslang/OSDependent/Windows/ossource.cpp @@ -0,0 +1,85 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +#include "osinclude.h" +// +// This file contains contains the window's specific functions +// + +#if !(defined(_WIN32) || defined(_WIN64)) +#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/glslang/Public/ShaderLang.h b/glslang/Public/ShaderLang.h new file mode 100644 index 00000000..581ad3cb --- /dev/null +++ b/glslang/Public/ShaderLang.h @@ -0,0 +1,212 @@ +// +//Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// +#ifndef _COMPILER_INTERFACE_INCLUDED_ +#define _COMPILER_INTERFACE_INCLUDED_ + +#include "../Include/ResourceLimits.h" + +#ifdef _WIN32 +#define C_DECL __cdecl +#ifdef SH_EXPORTING + #define SH_IMPORT_EXPORT __declspec(dllexport) +#else + #define SH_IMPORT_EXPORT __declspec(dllimport) +#endif +#else +#define SH_IMPORT_EXPORT +#define __fastcall +#define C_DECL +#endif + +// +// This is the platform independent interface between an OGL driver +// and the shading language compiler/linker. +// + +#ifdef __cplusplus + extern "C" { +#endif +// +// Driver must call this first, once, before doing any other +// compiler/linker operations. +// +SH_IMPORT_EXPORT int ShInitialize(); +// +// Driver should call this at shutdown. +// +SH_IMPORT_EXPORT int __fastcall ShFinalize(); +// +// Types of languages the compiler can consume. +// +typedef enum { + EShLangVertex, + EShLangFragment, + EShLangPack, + EShLangUnpack, + EShLangCount, +} EShLanguage; + +// +// Types of output the linker will create. +// +typedef enum { + EShExVertexFragment, + EShExPackFragment, + EShExUnpackFragment, + EShExFragment +} EShExecutable; + +// +// Optimization level for the compiler. +// +typedef enum { + EShOptNoGeneration, + EShOptNone, + EShOptSimple, // Optimizations that can be done quickly + EShOptFull, // Optimizations that will take more time +} EShOptimizationLevel; + +// +// Build a table for bindings. This can be used for locating +// attributes, uniforms, globals, etc., as needed. +// +typedef struct { + char* name; + int binding; +} ShBinding; + +typedef struct { + int numBindings; + ShBinding* bindings; // array of bindings +} ShBindingTable; + +// +// ShHandle held by but opaque to the driver. It is allocated, +// managed, and de-allocated by the compiler/linker. It's contents +// are defined by and used by the compiler and linker. For example, +// symbol table information and object code passed from the compiler +// to the linker can be stored where ShHandle points. +// +// If handle creation fails, 0 will be returned. +// +typedef void* ShHandle; + +// +// Driver calls these to create and destroy compiler/linker +// objects. +// +SH_IMPORT_EXPORT ShHandle ShConstructCompiler(const EShLanguage, int debugOptions); // one per shader +SH_IMPORT_EXPORT ShHandle ShConstructLinker(const EShExecutable, int debugOptions); // one per shader pair +SH_IMPORT_EXPORT ShHandle ShConstructUniformMap(); // one per uniform namespace (currently entire program object) +SH_IMPORT_EXPORT void ShDestruct(ShHandle); + +// +// The return value of ShCompile is boolean, indicating +// success or failure. +// +// The info-log should be written by ShCompile into +// ShHandle, so it can answer future queries. +// +SH_IMPORT_EXPORT int ShCompile( + const ShHandle, + const char* const shaderStrings[], + const int numStrings, + const EShOptimizationLevel, + const TBuiltInResource *resources, + int debugOptions + ); + + +// +// Similar to ShCompile, but accepts an opaque handle to an +// intermediate language structure. +// +SH_IMPORT_EXPORT int ShCompileIntermediate( + ShHandle compiler, + ShHandle intermediate, + const EShOptimizationLevel, + int debuggable // boolean + ); + +SH_IMPORT_EXPORT int ShLink( + const ShHandle, // linker object + const ShHandle h[], // compiler objects to link together + const int numHandles, + ShHandle uniformMap, // updated with new uniforms + short int** uniformsAccessed, // returned with indexes of uniforms accessed + int* numUniformsAccessed); + +SH_IMPORT_EXPORT int ShLinkExt( + const ShHandle, // linker object + const ShHandle h[], // compiler objects to link together + const int numHandles); + +// +// ShSetEncrpytionMethod is a place-holder for specifying +// how source code is encrypted. +// +SH_IMPORT_EXPORT void ShSetEncryptionMethod(ShHandle); + +// +// All the following return 0 if the information is not +// available in the object passed down, or the object is bad. +// +SH_IMPORT_EXPORT const char* ShGetInfoLog(const ShHandle); +SH_IMPORT_EXPORT const void* ShGetExecutable(const ShHandle); +SH_IMPORT_EXPORT int ShSetVirtualAttributeBindings(const ShHandle, const ShBindingTable*); // to detect user aliasing +SH_IMPORT_EXPORT int ShSetFixedAttributeBindings(const ShHandle, const ShBindingTable*); // to force any physical mappings +SH_IMPORT_EXPORT int ShGetPhysicalAttributeBindings(const ShHandle, const ShBindingTable**); // for all attributes +// +// Tell the linker to never assign a vertex attribute to this list of physical attributes +// +SH_IMPORT_EXPORT int ShExcludeAttributes(const ShHandle, int *attributes, int count); + +// +// Returns the location ID of the named uniform. +// Returns -1 if error. +// +SH_IMPORT_EXPORT int ShGetUniformLocation(const ShHandle uniformMap, const char* name); + +enum TDebugOptions { + EDebugOpNone = 0x000, + EDebugOpIntermediate = 0x001, + EDebugOpAssembly = 0x002, + EDebugOpObjectCode = 0x004, + EDebugOpLinkMaps = 0x008 +}; +#ifdef __cplusplus + } +#endif + +#endif // _COMPILER_INTERFACE_INCLUDED_ diff --git a/tools/bison.exe b/tools/bison.exe new file mode 100644 index 0000000000000000000000000000000000000000..4881bf604916b1331205bdd5f32624831e2a2331 GIT binary patch literal 196096 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 literal 0 HcmV?d00001 diff --git a/tools/bison.hairy b/tools/bison.hairy new file mode 100644 index 00000000..260b687c --- /dev/null +++ b/tools/bison.hairy @@ -0,0 +1,334 @@ + +extern int timeclock; + + +int yyerror; /* Yyerror and yycost are set by guards. */ +int yycost; /* If yyerror is set to a nonzero value by a */ + /* guard, the reduction with which the guard */ + /* is associated is not performed, and the */ + /* error recovery mechanism is invoked. */ + /* Yycost indicates the cost of performing */ + /* the reduction given the attributes of the */ + /* symbols. */ + + +/* YYMAXDEPTH indicates the size of the parser's state and value */ +/* stacks. */ + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 500 +#endif + +/* YYMAXRULES must be at least as large as the number of rules that */ +/* could be placed in the rule queue. That number could be determined */ +/* from the grammar and the size of the stack, but, as yet, it is not. */ + +#ifndef YYMAXRULES +#define YYMAXRULES 100 +#endif + +#ifndef YYMAXBACKUP +#define YYMAXBACKUP 100 +#endif + + +short yyss[YYMAXDEPTH]; /* the state stack */ +YYSTYPE yyvs[YYMAXDEPTH]; /* the semantic value stack */ +YYLTYPE yyls[YYMAXDEPTH]; /* the location stack */ +short yyrq[YYMAXRULES]; /* the rule queue */ +int yychar; /* the lookahead symbol */ + +YYSTYPE yylval; /* the semantic value of the */ + /* lookahead symbol */ + +YYSTYPE yytval; /* the semantic value for the state */ + /* at the top of the state stack. */ + +YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ + +YYLTYPE yytloc; /* location data for the state at the */ + /* top of the state stack */ + + +int yynunlexed; +short yyunchar[YYMAXBACKUP]; +YYSTYPE yyunval[YYMAXBACKUP]; +YYLTYPE yyunloc[YYMAXBACKUP]; + +short *yygssp; /* a pointer to the top of the state */ + /* stack; only set during error */ + /* recovery. */ + +YYSTYPE *yygvsp; /* a pointer to the top of the value */ + /* stack; only set during error */ + /* recovery. */ + +YYLTYPE *yyglsp; /* a pointer to the top of the */ + /* location stack; only set during */ + /* error recovery. */ + + +/* Yyget is an interface between the parser and the lexical analyzer. */ +/* It is costly to provide such an interface, but it avoids requiring */ +/* the lexical analyzer to be able to back up the scan. */ + +yyget() +{ + if (yynunlexed > 0) + { + yynunlexed--; + yychar = yyunchar[yynunlexed]; + yylval = yyunval[yynunlexed]; + yylloc = yyunloc[yynunlexed]; + } + else if (yychar <= 0) + yychar = 0; + else + { + yychar = yylex(); + if (yychar < 0) + yychar = 0; + else yychar = YYTRANSLATE(yychar); + } +} + + + +yyunlex(chr, val, loc) +int chr; +YYSTYPE val; +YYLTYPE loc; +{ + yyunchar[yynunlexed] = chr; + yyunval[yynunlexed] = val; + yyunloc[yynunlexed] = loc; + yynunlexed++; +} + + + +yyrestore(first, last) +register short *first; +register short *last; +{ + register short *ssp; + register short *rp; + register int symbol; + register int state; + register int tvalsaved; + + ssp = yygssp; + yyunlex(yychar, yylval, yylloc); + + tvalsaved = 0; + while (first != last) + { + symbol = yystos[*ssp]; + if (symbol < YYNTBASE) + { + yyunlex(symbol, yytval, yytloc); + tvalsaved = 1; + ssp--; + } + + ssp--; + + if (first == yyrq) + first = yyrq + YYMAXRULES; + + first--; + + for (rp = yyrhs + yyprhs[*first]; symbol = *rp; rp++) + { + if (symbol < YYNTBASE) + state = yytable[yypact[*ssp] + symbol]; + else + { + state = yypgoto[symbol - YYNTBASE] + *ssp; + + if (state >= 0 && state <= YYLAST && yycheck[state] == *ssp) + state = yytable[state]; + else + state = yydefgoto[symbol - YYNTBASE]; + } + + *++ssp = state; + } + } + + if ( ! tvalsaved && ssp > yyss) + { + yyunlex(yystos[*ssp], yytval, yytloc); + ssp--; + } + + yygssp = ssp; +} + + + +int +yyparse() +{ + register int yystate; + register int yyn; + register short *yyssp; + register short *yyrq0; + register short *yyptr; + register YYSTYPE *yyvsp; + + int yylen; + YYLTYPE *yylsp; + short *yyrq1; + short *yyrq2; + + yystate = 0; + yyssp = yyss - 1; + yyvsp = yyvs - 1; + yylsp = yyls - 1; + yyrq0 = yyrq; + yyrq1 = yyrq0; + yyrq2 = yyrq0; + + yychar = yylex(); + if (yychar < 0) + yychar = 0; + else yychar = YYTRANSLATE(yychar); + +yynewstate: + + if (yyssp >= yyss + YYMAXDEPTH - 1) + { + yyabort("Parser Stack Overflow"); + YYABORT; + } + + *++yyssp = yystate; + +yyresume: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + yyn += yychar; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar) + goto yydefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + yystate = yyn; + + yyptr = yyrq2; + while (yyptr != yyrq1) + { + yyn = *yyptr++; + yylen = yyr2[yyn]; + yyvsp -= yylen; + yylsp -= yylen; + + yyguard(yyn, yyvsp, yylsp); + if (yyerror) + goto yysemerr; + + yyaction(yyn, yyvsp, yylsp); + *++yyvsp = yyval; + + yylsp++; + if (yylen == 0) + { + yylsp->timestamp = timeclock; + yylsp->first_line = yytloc.first_line; + yylsp->first_column = yytloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } + + if (yyptr == yyrq + YYMAXRULES) + yyptr = yyrq; + } + + if (yystate == YYFINAL) + YYACCEPT; + + yyrq2 = yyptr; + yyrq1 = yyrq0; + + *++yyvsp = yytval; + *++yylsp = yytloc; + yytval = yylval; + yytloc = yylloc; + yyget(); + + goto yynewstate; + +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +yyreduce: + + *yyrq0++ = yyn; + + if (yyrq0 == yyrq + YYMAXRULES) + yyrq0 = yyrq; + + if (yyrq0 == yyrq2) + { + yyabort("Parser Rule Queue Overflow"); + YYABORT; + } + + yyssp -= yyr2[yyn]; + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yysemerr: + *--yyptr = yyn; + yyrq2 = yyptr; + yyvsp += yyr2[yyn]; + +yyerrlab: + + yygssp = yyssp; + yygvsp = yyvsp; + yyglsp = yylsp; + yyrestore(yyrq0, yyrq2); + yyrecover(); + yystate = *yygssp; + yyssp = yygssp; + yyvsp = yygvsp; + yyrq0 = yyrq; + yyrq1 = yyrq0; + yyrq2 = yyrq0; + goto yyresume; +} + +$ diff --git a/tools/bison.simple b/tools/bison.simple new file mode 100644 index 00000000..690fb2e5 --- /dev/null +++ b/tools/bison.simple @@ -0,0 +1,699 @@ +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ + +/* Skeleton output parser for bison, + Copyright (C) 1984, 1989, 1990 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 2, 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not __GNUC__ */ +#if HAVE_ALLOCA_H +#include +#else /* not HAVE_ALLOCA_H */ +#ifdef _AIX + #pragma alloca +#else /* not _AIX */ +char *alloca (); +#endif /* not _AIX */ +#endif /* not HAVE_ALLOCA_H */ +#endif /* not __GNUC__ */ + +extern void yyerror(char* s); + +#ifndef alloca +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) +#include +#else /* not sparc */ +#if (defined (MSDOS) && !defined (__TURBOC__)) || defined (WIN32) +#include +#else /* not MSDOS, or __TURBOC__ */ +#if defined(_AIX) +#include + #pragma alloca +#else /* not MSDOS, __TURBOC__, or _AIX */ +#ifdef __hpux +#ifdef __cplusplus +extern "C" { +void *alloca (unsigned int); +}; +#else /* not __cplusplus */ +void *alloca (); +#endif /* not __cplusplus */ +#endif /* __hpux */ +#endif /* not _AIX */ +#endif /* not MSDOS, or __TURBOC__ */ +#endif /* not sparc. */ +#endif /* not GNU C. */ +#endif /* alloca not defined. */ + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT return(0) +#define YYABORT return(1) +#define YYERROR goto yyerrlab1 +/* 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); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { yyerror ("syntax error: cannot back up"); YYERROR; } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYPURE +#define YYLEX yylex() +#endif + +#ifdef YYPURE +#ifdef YYLSP_NEEDED +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval, &yylloc) +#endif +#else /* not YYLSP_NEEDED */ +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval) +#endif +#endif /* not YYLSP_NEEDED */ +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYPURE + +int yychar; /* the lookahead symbol */ +YYSTYPE yylval; /* the semantic value of the */ + /* lookahead symbol */ + +#ifdef YYLSP_NEEDED +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ +#endif + +int yynerrs; /* number of parse errors so far */ +#endif /* not YYPURE */ + +#if YYDEBUG != 0 +int yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#if YYMAXDEPTH == 0 +#undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 10000 +#endif + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +int yyparse (void); +#endif + +#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ +#define __yy_memcpy(FROM,TO,COUNT) __builtin_memcpy(TO,FROM,COUNT) +#else /* not GNU C or C++ */ +#ifndef __cplusplus + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (from, to, count) + char *from; + char *to; + size_t count; +{ + register char *f = from; + register char *t = to; + register size_t i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#else /* __cplusplus */ + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (char *from, char *to, size_t count) +{ + register char *f = from; + register char *t = to; + register size_t i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#endif +#endif + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +#ifndef YYPARSE_PARAM_DECL +#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +#endif +#else +#define YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#endif + +extern YY_DECL; + +int +yyparse(YYPARSE_PARAM_DECL YYPARSE_PARAM) { + register int yystate; + register int yyn; + register short *yyssp; + register YYSTYPE *yyvsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1 = 0; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYINITDEPTH]; /* the state stack */ + YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ + +#ifdef YYLSP_NEEDED + YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + +#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +#define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + size_t yystacksize = YYINITDEPTH; + +#ifdef YYPURE + int yychar; + YYSTYPE yylval; + int yynerrs; +#ifdef YYLSP_NEEDED + YYLTYPE yylloc; +#endif +#endif + + YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + 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 - 1; + yyvsp = yyvs; +#ifdef YYLSP_NEEDED + yylsp = yyls; +#endif + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* 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; + short *yyss1 = yyss; +#ifdef YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; +#endif + + /* Get the current used size of the three stacks, in elements. */ + size_t size = yyssp - yyss + 1; + +#ifdef yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ +#ifdef YYLSP_NEEDED + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yyls1, size * sizeof (*yylsp), + &yystacksize); +#else + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yystacksize); +#endif + + yyss = yyss1; yyvs = yyvs1; +#ifdef YYLSP_NEEDED + yyls = yyls1; +#endif +#else /* no yyoverflow */ + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + { + yyerror("parser stack overflow"); + return 2; + } + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; + yyss = (short *) alloca (yystacksize * sizeof (*yyssp)); + __yy_memcpy ((char *)yyss1, (char *)yyss, size * sizeof (*yyssp)); + yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp)); + __yy_memcpy ((char *)yyvs1, (char *)yyvs, size * sizeof (*yyvsp)); +#ifdef YYLSP_NEEDED + yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp)); + __yy_memcpy ((char *)yyls1, (char *)yyls, size * sizeof (*yylsp)); +#endif +#endif /* no yyoverflow */ + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; +#ifdef YYLSP_NEEDED + yylsp = yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Stack size increased to %d\n", yystacksize); +#endif + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Entering state %d\n", yystate); +#endif + + goto yybackup; + yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Reading a token: "); +#endif + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + yychar1 = YYTRANSLATE(yychar); + +#if YYDEBUG != 0 + if (yydebug) + { + fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise meaning + of a token, for further debugging info. */ +#ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +#endif + fprintf (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + if (yylen > 0) + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (yydebug) + { + int i; + + fprintf (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) + fprintf (stderr, "%s ", yytname[yyrhs[i]]); + fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + +$ /* the action file gets copied in in place of this dollarsign */ + yyvsp -= yylen; + yyssp -= yylen; +#ifdef YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; + +#ifdef YYLSP_NEEDED + yylsp++; + if (yylen == 0) + { + yylsp->first_line = yylloc.first_line; + yylsp->first_column = yylloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } +#endif + + /* 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 - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + size += strlen(yytname[x]) + 15, count++; + msg = (char *) malloc(size + 15); + if (msg != 0) + { + strcpy(msg, "parse error"); + + if (count < 5) + { + count = 0; + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, yytname[x]); + strcat(msg, "'"); + count++; + } + } + yyerror(msg); + free(msg); + } + else + yyerror ("parse error; also virtual memory exceeded"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror("parse error"); + } + + goto yyerrlab1; +yyerrlab1: /* here on error raised explicitly by an action */ + + if (yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +#endif + + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; +#ifdef YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; +} diff --git a/tools/flex.exe b/tools/flex.exe new file mode 100644 index 0000000000000000000000000000000000000000..58f10ce3561e8b693e3e4d3ef247bc6507c38608 GIT binary patch literal 181248 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�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 literal 0 HcmV?d00001