Commit 8b851c6d by alokp@chromium.org

Preparation of hooking up the new preprocessor.

- Added custom Diagnostics class. Routed all info-log messages via this new class. - Added custom DirectiveHandler class. Moved directive-handling code to this class and routed the old path. - Deleted lexer_glue because it is not needed anymore. The new preprocessor is almost ready! - Killed a bunch of dead code related to PragmaTable. Review URL: https://codereview.appspot.com/6308074 git-svn-id: https://angleproject.googlecode.com/svn/trunk@1150 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 46aa13d8
......@@ -63,6 +63,11 @@
'compiler/debug.h',
'compiler/DetectRecursion.cpp',
'compiler/DetectRecursion.h',
'compiler/Diagnostics.h',
'compiler/Diagnostics.cpp',
'compiler/DirectiveHandler.h',
'compiler/DirectiveHandler.cpp',
'compiler/ExtensionBehavior.h',
'compiler/ForLoopUnroll.cpp',
'compiler/ForLoopUnroll.h',
'compiler/glslang.h',
......@@ -76,6 +81,7 @@
'compiler/InitializeDll.cpp',
'compiler/InitializeDll.h',
'compiler/InitializeGlobals.h',
'compiler/InitializeParseContext.cpp',
'compiler/InitializeParseContext.h',
'compiler/Intermediate.cpp',
'compiler/intermediate.h',
......@@ -114,8 +120,6 @@
'compiler/preprocessor/cpp.h',
'compiler/preprocessor/cppstruct.c',
'compiler/preprocessor/length_limits.h',
'compiler/preprocessor/lexer_glue.cpp',
'compiler/preprocessor/lexer_glue.h',
'compiler/preprocessor/memory.c',
'compiler/preprocessor/memory.h',
'compiler/preprocessor/parser.h',
......
......@@ -8,6 +8,7 @@
#include "compiler/DetectRecursion.h"
#include "compiler/ForLoopUnroll.h"
#include "compiler/Initialize.h"
#include "compiler/InitializeParseContext.h"
#include "compiler/MapLongVariableNames.h"
#include "compiler/ParseHelper.h"
#include "compiler/RenameFunction.h"
......
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "compiler/Diagnostics.h"
#include "compiler/InfoSink.h"
#include "compiler/preprocessor/new/SourceLocation.h"
TDiagnostics::TDiagnostics(TInfoSink& infoSink) : mInfoSink(infoSink)
{
}
TDiagnostics::~TDiagnostics()
{
}
void TDiagnostics::writeInfo(Severity severity,
const pp::SourceLocation& loc,
const std::string& reason,
const std::string& token,
const std::string& extra)
{
TInfoSinkBase& sink = mInfoSink.info;
TPrefixType prefix = severity == ERROR ? EPrefixError : EPrefixWarning;
/* VC++ format: file(linenum) : error #: 'token' : extrainfo */
sink.prefix(prefix);
sink.location(EncodeSourceLoc(loc.file, loc.line));
sink << "'" << token << "' : " << reason << " " << extra << "\n";
}
void TDiagnostics::writeDebug(const std::string& str)
{
mInfoSink.debug << str;
}
void TDiagnostics::print(ID id,
const pp::SourceLocation& loc,
const std::string& text)
{
}
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef COMPILER_DIAGNOSTICS_H_
#define COMPILER_DIAGNOSTICS_H_
#include "compiler/preprocessor/new/Diagnostics.h"
class TInfoSink;
class TDiagnostics : public pp::Diagnostics
{
public:
TDiagnostics(TInfoSink& infoSink);
virtual ~TDiagnostics();
void writeInfo(Severity severity,
const pp::SourceLocation& loc,
const std::string& reason,
const std::string& token,
const std::string& extra);
void writeDebug(const std::string& str);
protected:
virtual void print(ID id,
const pp::SourceLocation& loc,
const std::string& text);
private:
TInfoSink& mInfoSink;
};
#endif // COMPILER_DIAGNOSTICS_H_
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "compiler/DirectiveHandler.h"
#include <sstream>
#include "compiler/Debug.h"
#include "compiler/Diagnostics.h"
static TBehavior getBehavior(const std::string& str)
{
static const std::string kRequire("require");
static const std::string kEnable("enable");
static const std::string kDisable("disable");
static const std::string kWarn("warn");
if (str == kRequire) return EBhRequire;
else if (str == kEnable) return EBhEnable;
else if (str == kDisable) return EBhDisable;
else if (str == kWarn) return EBhWarn;
return EBhUndefined;
}
TDirectiveHandler::TDirectiveHandler(TExtensionBehavior& extBehavior,
TDiagnostics& diagnostics)
: mExtBehavior(extBehavior),
mDiagnostics(diagnostics)
{
}
TDirectiveHandler::~TDirectiveHandler()
{
}
void TDirectiveHandler::handleError(const pp::SourceLocation& loc,
const std::string& msg)
{
mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc, msg, "", "");
}
void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc,
const std::string& name,
const std::string& value)
{
static const std::string kSTDGL("STDGL");
static const std::string kOptimize("optimize");
static const std::string kDebug("debug");
static const std::string kOn("on");
static const std::string kOff("off");
bool invalidValue = false;
if (name == kSTDGL)
{
// The STDGL pragma is used to reserve pragmas for use by future
// revisions of GLSL. Ignore it.
return;
}
else if (name == kOptimize)
{
if (value == kOn) mPragma.optimize = true;
else if (value == kOff) mPragma.optimize = false;
else invalidValue = true;
}
else if (name == kDebug)
{
if (value == kOn) mPragma.debug = true;
else if (value == kOff) mPragma.debug = false;
else invalidValue = true;
}
else
{
mDiagnostics.report(pp::Diagnostics::UNRECOGNIZED_PRAGMA, loc, name);
return;
}
if (invalidValue)
mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
"invalid pragma value", value,
"'on' or 'off' expected");
}
void TDirectiveHandler::handleExtension(const pp::SourceLocation& loc,
const std::string& name,
const std::string& behavior)
{
static const std::string kExtAll("all");
TBehavior behaviorVal = getBehavior(behavior);
if (behaviorVal == EBhUndefined)
{
mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
"behavior", name, "invalid");
return;
}
if (name == kExtAll)
{
if (behaviorVal == EBhRequire)
{
mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
"extension", name,
"cannot have 'require' behavior");
}
else if (behaviorVal == EBhEnable)
{
mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
"extension", name,
"cannot have 'enable' behavior");
}
else
{
for (TExtensionBehavior::iterator iter = mExtBehavior.begin();
iter != mExtBehavior.end(); ++iter)
iter->second = behaviorVal;
}
return;
}
TExtensionBehavior::iterator iter = mExtBehavior.find(name);
if (iter != mExtBehavior.end())
{
iter->second = behaviorVal;
return;
}
pp::Diagnostics::Severity severity = pp::Diagnostics::ERROR;
switch (behaviorVal) {
case EBhRequire:
severity = pp::Diagnostics::ERROR;
break;
case EBhEnable:
case EBhWarn:
case EBhDisable:
severity = pp::Diagnostics::WARNING;
break;
default:
UNREACHABLE();
break;
}
mDiagnostics.writeInfo(severity, loc,
"extension", name, "is not supported");
}
void TDirectiveHandler::handleVersion(const pp::SourceLocation& loc,
int version)
{
static const int kVersion = 100;
if (version != kVersion)
{
std::stringstream stream;
stream << version;
std::string str = stream.str();
mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
"version number", str, "not supported");
}
}
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef COMPILER_DIRECTIVE_HANDLER_H_
#define COMPILER_DIRECTIVE_HANDLER_H_
#include "compiler/ExtensionBehavior.h"
#include "compiler/Pragma.h"
#include "compiler/preprocessor/new/DirectiveHandler.h"
class TDiagnostics;
class TDirectiveHandler : public pp::DirectiveHandler
{
public:
TDirectiveHandler(TExtensionBehavior& extBehavior,
TDiagnostics& diagnostics);
virtual ~TDirectiveHandler();
const TPragma& pragma() const { return mPragma; }
const TExtensionBehavior& extBehavior() const { return mExtBehavior; }
virtual void handleError(const pp::SourceLocation& loc,
const std::string& msg);
virtual void handlePragma(const pp::SourceLocation& loc,
const std::string& name,
const std::string& value);
virtual void handleExtension(const pp::SourceLocation& loc,
const std::string& name,
const std::string& behavior);
virtual void handleVersion(const pp::SourceLocation& loc,
int version);
private:
TPragma mPragma;
TExtensionBehavior& mExtBehavior;
TDiagnostics& mDiagnostics;
};
#endif // COMPILER_DIRECTIVE_HANDLER_H_
......@@ -7,9 +7,11 @@
#ifndef _EXTENSION_BEHAVIOR_INCLUDED_
#define _EXTENSION_BEHAVIOR_INCLUDED_
#include "compiler/Common.h"
#include <map>
#include <string>
typedef enum {
typedef enum
{
EBhRequire,
EBhEnable,
EBhWarn,
......@@ -19,20 +21,17 @@ typedef enum {
inline const char* getBehaviorString(TBehavior b)
{
switch(b) {
case EBhRequire:
return "require";
case EBhEnable:
return "enable";
case EBhWarn:
return "warn";
case EBhDisable:
return "disable";
default:
return NULL;
switch(b)
{
case EBhRequire: return "require";
case EBhEnable: return "enable";
case EBhWarn: return "warn";
case EBhDisable: return "disable";
default: return NULL;
}
}
typedef TMap<TString, TBehavior> TExtensionBehavior;
// Mapping between extension name and behavior.
typedef std::map<std::string, TBehavior> TExtensionBehavior;
#endif // _EXTENSION_TABLE_INCLUDED_
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "compiler/InitializeParseContext.h"
#include "compiler/osinclude.h"
OS_TLSIndex GlobalParseContextIndex = OS_INVALID_TLS_INDEX;
bool InitializeParseContextIndex()
{
if (GlobalParseContextIndex != OS_INVALID_TLS_INDEX) {
assert(0 && "InitializeParseContextIndex(): Parse Context already initalized");
return false;
}
//
// Allocate a TLS index.
//
GlobalParseContextIndex = OS_AllocTLSIndex();
if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
assert(0 && "InitializeParseContextIndex(): Parse Context already initalized");
return false;
}
return true;
}
bool FreeParseContextIndex()
{
OS_TLSIndex tlsiIndex = GlobalParseContextIndex;
if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
assert(0 && "FreeParseContextIndex(): Parse Context index not initalized");
return false;
}
GlobalParseContextIndex = OS_INVALID_TLS_INDEX;
return OS_FreeTLSIndex(tlsiIndex);
}
bool InitializeGlobalParseContext()
{
if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
assert(0 && "InitializeGlobalParseContext(): Parse Context index not initalized");
return false;
}
TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex));
if (lpParseContext != 0) {
assert(0 && "InitializeParseContextIndex(): Parse Context already initalized");
return false;
}
TThreadParseContext *lpThreadData = new TThreadParseContext();
if (lpThreadData == 0) {
assert(0 && "InitializeGlobalParseContext(): Unable to create thread parse context");
return false;
}
lpThreadData->lpGlobalParseContext = 0;
OS_SetTLSValue(GlobalParseContextIndex, lpThreadData);
return true;
}
bool FreeParseContext()
{
if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
assert(0 && "FreeParseContext(): Parse Context index not initalized");
return false;
}
TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex));
if (lpParseContext)
delete lpParseContext;
return true;
}
TParseContextPointer& GetGlobalParseContext()
{
//
// Minimal error checking for speed
//
TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex));
return lpParseContext->lpGlobalParseContext;
}
......@@ -13,4 +13,14 @@ bool FreeParseContextIndex();
bool InitializeGlobalParseContext();
bool FreeParseContext();
struct TParseContext;
typedef TParseContext* TParseContextPointer;
extern TParseContextPointer& GetGlobalParseContext();
#define GlobalParseContext GetGlobalParseContext()
typedef struct TThreadParseContextRec
{
TParseContext *lpGlobalParseContext;
} TThreadParseContext;
#endif // __INITIALIZE_PARSE_CONTEXT_INCLUDED_
......@@ -1445,9 +1445,3 @@ TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermC
return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine());
}
void TIntermAggregate::addToPragmaTable(const TPragmaTable& pTable)
{
assert(!pragmaTable);
pragmaTable = new TPragmaTable();
*pragmaTable = pTable;
}
......@@ -10,8 +10,7 @@
#include <stdio.h>
#include "compiler/glslang.h"
#include "compiler/osinclude.h"
#include "compiler/InitializeParseContext.h"
#include "compiler/preprocessor/new/SourceLocation.h"
extern "C" {
extern int InitPreprocessor();
......@@ -19,17 +18,6 @@ extern int FinalizePreprocessor();
extern void PredefineIntMacro(const char *name, int value);
}
static void ReportInfo(TInfoSinkBase& sink,
TPrefixType type, TSourceLoc loc,
const char* reason, const char* token,
const char* extraInfo)
{
/* VC++ format: file(linenum) : error #: 'token' : extrainfo */
sink.prefix(type);
sink.location(loc);
sink << "'" << token << "' : " << reason << " " << extraInfo << "\n";
}
static void DefineExtensionMacros(const TExtensionBehavior& extBehavior)
{
for (TExtensionBehavior::const_iterator iter = extBehavior.begin();
......@@ -40,6 +28,26 @@ static void DefineExtensionMacros(const TExtensionBehavior& extBehavior)
///////////////////////////////////////////////////////////////////////
//
// Preprocessor
//
////////////////////////////////////////////////////////////////////////
bool TParseContext::initPreprocessor()
{
if (InitPreprocessor())
return false;
DefineExtensionMacros(directiveHandler.extBehavior());
return true;
}
void TParseContext::destroyPreprocessor()
{
FinalizePreprocessor();
}
///////////////////////////////////////////////////////////////////////
//
// Sub- vector and matrix fields
//
////////////////////////////////////////////////////////////////////////
......@@ -210,7 +218,10 @@ void TParseContext::error(TSourceLoc loc,
va_start(marker, extraInfoFormat);
vsnprintf(extraInfo, sizeof(extraInfo), extraInfoFormat, marker);
ReportInfo(infoSink.info, EPrefixError, loc, reason, token, extraInfo);
pp::SourceLocation srcLoc;
DecodeSourceLoc(loc, &srcLoc.file, &srcLoc.line);
diagnostics.writeInfo(pp::Diagnostics::ERROR,
srcLoc, reason, token, extraInfo);
va_end(marker);
++numErrors;
......@@ -224,11 +235,19 @@ void TParseContext::warning(TSourceLoc loc,
va_start(marker, extraInfoFormat);
vsnprintf(extraInfo, sizeof(extraInfo), extraInfoFormat, marker);
ReportInfo(infoSink.info, EPrefixWarning, loc, reason, token, extraInfo);
pp::SourceLocation srcLoc;
DecodeSourceLoc(loc, &srcLoc.file, &srcLoc.line);
diagnostics.writeInfo(pp::Diagnostics::WARNING,
srcLoc, reason, token, extraInfo);
va_end(marker);
}
void TParseContext::trace(const char* str)
{
diagnostics.writeDebug(str);
}
//
// Same error message for all places assignments don't work.
//
......@@ -830,10 +849,7 @@ bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size,
// its an error
if (node->getSymbol() == "gl_FragData") {
TSymbol* fragData = symbolTable.find("gl_MaxDrawBuffers", &builtIn);
if (fragData == 0) {
infoSink.info.message(EPrefixInternalError, "gl_MaxDrawBuffers not defined", line);
return true;
}
ASSERT(fragData);
int fragDataValue = static_cast<TVariable*>(fragData)->getConstPointer()[0].getIConst();
if (fragDataValue <= size) {
......@@ -926,8 +942,9 @@ bool TParseContext::paramErrorCheck(int line, TQualifier qualifier, TQualifier p
bool TParseContext::extensionErrorCheck(int line, const TString& extension)
{
TExtensionBehavior::const_iterator iter = extensionBehavior.find(extension);
if (iter == extensionBehavior.end()) {
const TExtensionBehavior& extBehavior = directiveHandler.extBehavior();
TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str());
if (iter == extBehavior.end()) {
error(line, "extension", extension.c_str(), "is not supported");
return true;
}
......@@ -937,8 +954,7 @@ bool TParseContext::extensionErrorCheck(int line, const TString& extension)
return true;
}
if (iter->second == EBhWarn) {
TString msg = "extension " + extension + " is being used";
infoSink.info.message(EPrefixWarning, msg.c_str(), line);
warning(line, "extension", extension.c_str(), "is being used");
return false;
}
......@@ -947,8 +963,23 @@ bool TParseContext::extensionErrorCheck(int line, const TString& extension)
bool TParseContext::supportsExtension(const char* extension)
{
TExtensionBehavior::const_iterator iter = extensionBehavior.find(extension);
return (iter != extensionBehavior.end());
const TExtensionBehavior& extBehavior = directiveHandler.extBehavior();
TExtensionBehavior::const_iterator iter = extBehavior.find(extension);
return (iter != extBehavior.end());
}
void TParseContext::handleExtensionDirective(int line, const char* extName, const char* behavior)
{
pp::SourceLocation loc;
DecodeSourceLoc(line, &loc.file, &loc.line);
directiveHandler.handleExtension(loc, extName, behavior);
}
void TParseContext::handlePragmaDirective(int line, const char* name, const char* value)
{
pp::SourceLocation loc;
DecodeSourceLoc(line, &loc.file, &loc.line);
directiveHandler.handlePragma(loc, name, value);
}
/////////////////////////////////////////////////////////////////////////////////
......@@ -1295,11 +1326,9 @@ TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTy
ConstantUnion *unionArray;
if (tempConstantNode) {
unionArray = tempConstantNode->getUnionArrayPointer();
ASSERT(unionArray);
if (!unionArray) { // this error message should never be raised
infoSink.info.message(EPrefixInternalError, "ConstantUnion not initialized in addConstVectorNode function", line);
recover();
if (!unionArray) {
return node;
}
} else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error
......@@ -1484,10 +1513,8 @@ int PaParseStrings(int count, const char* const string[], const int length[],
if ((count == 0) || (string == NULL))
return 1;
// setup preprocessor.
if (InitPreprocessor())
if (!context->initPreprocessor())
return 1;
DefineExtensionMacros(context->extensionBehavior);
if (glslang_initialize(context))
return 1;
......@@ -1496,94 +1523,11 @@ int PaParseStrings(int count, const char* const string[], const int length[],
if (!error)
error = glslang_parse(context);
glslang_finalize(context);
FinalizePreprocessor();
return (error == 0) && (context->numErrors == 0) ? 0 : 1;
}
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 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);
}
bool InitializeGlobalParseContext()
{
if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
assert(0 && "InitializeGlobalParseContext(): Parse Context index not initalised");
return false;
}
TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(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);
glslang_finalize(context);
context->destroyPreprocessor();
return true;
}
bool FreeParseContext()
{
if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
assert(0 && "FreeParseContext(): Parse Context index not initalised");
return false;
}
TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex));
if (lpParseContext)
delete lpParseContext;
return true;
return (error == 0) && (context->numErrors == 0) ? 0 : 1;
}
TParseContextPointer& GetGlobalParseContext()
{
//
// Minimal error checking for speed
//
TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex));
return lpParseContext->lpGlobalParseContext;
}
......@@ -6,7 +6,8 @@
#ifndef _PARSER_HELPER_INCLUDED_
#define _PARSER_HELPER_INCLUDED_
#include "compiler/ExtensionBehavior.h"
#include "compiler/Diagnostics.h"
#include "compiler/DirectiveHandler.h"
#include "compiler/localintermediate.h"
#include "compiler/ShHandle.h"
#include "compiler/SymbolTable.h"
......@@ -18,13 +19,6 @@ struct TMatrixFields {
int col;
};
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.
......@@ -33,8 +27,8 @@ struct TParseContext {
TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, ShShaderType type, ShShaderSpec spec, int options, bool checksPrecErrors, const char* sourcePath, TInfoSink& is) :
intermediate(interm),
symbolTable(symt),
extensionBehavior(ext),
infoSink(is),
diagnostics(is),
directiveHandler(ext, diagnostics),
shaderType(type),
shaderSpec(spec),
compileOptions(options),
......@@ -48,12 +42,11 @@ struct TParseContext {
currentFunctionType(NULL),
functionReturnsValue(false),
checksPrecisionErrors(checksPrecErrors),
contextPragma(true, false),
scanner(NULL) { }
TIntermediate& intermediate; // to hold and build a parse tree
TSymbolTable& symbolTable; // symbol table that goes with the language currently being parsed
TExtensionBehavior& extensionBehavior; // mapping between supported extensions and current behavior.
TInfoSink& infoSink;
TDiagnostics diagnostics;
TDirectiveHandler directiveHandler;
ShShaderType shaderType; // vertex or fragment language (future: pack or unpack)
ShShaderSpec shaderSpec; // The language specification compiler conforms to - GLES2 or WebGL.
int compileOptions;
......@@ -67,15 +60,18 @@ struct TParseContext {
const TType* currentFunctionType; // the return type of the function that's currently being parsed
bool functionReturnsValue; // true if a non-void function has a return
bool checksPrecisionErrors; // true if an error will be generated when a variable is declared without precision, explicit or implicit.
struct TPragma contextPragma;
TString HashErrMsg;
bool AfterEOF;
void* scanner;
bool initPreprocessor();
void destroyPreprocessor();
void error(TSourceLoc loc, const char *reason, const char* token,
const char* extraInfoFormat, ...);
void warning(TSourceLoc loc, const char* reason, const char* token,
const char* extraInfoFormat, ...);
void trace(const char* str);
void recover();
bool parseVectorFields(const TString&, int vecSize, TVectorFields&, int line);
......@@ -105,7 +101,12 @@ struct TParseContext {
bool nonInitErrorCheck(int line, TString& identifier, TPublicType& type, TVariable*& variable);
bool paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type);
bool extensionErrorCheck(int line, const TString&);
bool supportsExtension(const char* extension);
void handleExtensionDirective(int line, const char* extName, const char* behavior);
const TPragma& pragma() const { return directiveHandler.pragma(); }
void handlePragmaDirective(int line, const char* name, const char* value);
bool containsSampler(TType& type);
bool areAllChildConst(TIntermAggregate* aggrNode);
......@@ -135,13 +136,4 @@ struct TParseContext {
int PaParseStrings(int count, const char* const string[], const int length[],
TParseContext* context);
typedef TParseContext* TParseContextPointer;
extern TParseContextPointer& GetGlobalParseContext();
#define GlobalParseContext GetGlobalParseContext()
typedef struct TThreadParseContextRec
{
TParseContext *lpGlobalParseContext;
} TThreadParseContext;
#endif // _PARSER_HELPER_INCLUDED_
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef COMPILER_PRAGMA_H_
#define COMPILER_PRAGMA_H_
struct TPragma {
// By default optimization is turned on and debug is turned off.
TPragma() : optimize(true), debug(false) { }
TPragma(bool o, bool d) : optimize(o), debug(d) { }
bool optimize;
bool debug;
};
#endif // COMPILER_PRAGMA_H_
......@@ -6,6 +6,7 @@
#include "compiler/ValidateLimitations.h"
#include "compiler/InfoSink.h"
#include "compiler/InitializeParseContext.h"
#include "compiler/ParseHelper.h"
namespace {
......
......@@ -11,6 +11,7 @@
#include <stdarg.h>
#include <stdio.h>
#include "compiler/InitializeParseContext.h"
#include "compiler/ParseHelper.h"
static const int kTraceBufferLen = 1024;
......@@ -28,7 +29,7 @@ void Trace(const char *format, ...) {
vsnprintf(buf, kTraceBufferLen, format, args);
va_end(args);
parseContext->infoSink.debug << buf;
parseContext->trace(buf);
}
}
} // extern "C"
......
......@@ -283,7 +283,7 @@ extern "C" {
void CPPDebugLogMsg(const char *msg)
{
SETUP_CONTEXT(cpp);
context->infoSink.debug.message(EPrefixNone, msg);
context->trace(msg);
}
void CPPWarningToInfoLog(const char *msg)
......@@ -299,7 +299,7 @@ void CPPShInfoLogMsg(const char *msg)
context->recover();
}
void CPPErrorToInfoLog(char *msg)
void CPPErrorToInfoLog(const char *msg)
{
SETUP_CONTEXT(cpp);
context->error(yylineno, msg, "", "");
......@@ -357,85 +357,12 @@ void DecLineNumber()
void HandlePragma(const char **tokens, int numTokens)
{
SETUP_CONTEXT(cpp);
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"))
context->contextPragma.optimize = true;
else if (!strcmp(tokens[2], "off"))
context->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"))
context->contextPragma.debug = true;
else if (!strcmp(tokens[2], "off"))
context->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
}
if (numTokens != 4) return;
if (strcmp(tokens[1], "(") != 0) return;
if (strcmp(tokens[3], ")") != 0) return;
context->handlePragmaDirective(yylineno, tokens[0], tokens[2]);
}
void StoreStr(char *string)
......@@ -460,58 +387,10 @@ void ResetTString(void)
context->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)
{
SETUP_CONTEXT(cpp);
TBehavior behaviorVal = GetBehavior(behavior);
TMap<TString, TBehavior>:: 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 = context->extensionBehavior.begin(); iter != context->extensionBehavior.end(); ++iter)
iter->second = behaviorVal;
}
} else {
iter = context->extensionBehavior.find(TString(extName));
if (iter == context->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";
context->infoSink.info.message(EPrefixWarning, msg.c_str(), yylineno);
break;
default:
break;
}
return;
} else
iter->second = behaviorVal;
}
context->handleExtensionDirective(yylineno, extName, behavior);
}
} // extern "C"
......
......@@ -2116,9 +2116,8 @@ function_definition
// store the pragma information for debug and optimize and other vendor specific
// information. This information can be queried from the parse tree
$$->getAsAggregate()->setOptimize(context->contextPragma.optimize);
$$->getAsAggregate()->setDebug(context->contextPragma.debug);
$$->getAsAggregate()->addToPragmaTable(context->contextPragma.pragmaTable);
$$->getAsAggregate()->setOptimize(context->pragma().optimize);
$$->getAsAggregate()->setDebug(context->pragma().debug);
if ($3 && $3->getAsAggregate())
$$->getAsAggregate()->setEndLine($3->getAsAggregate()->getEndLine());
......
#line 17 "./compiler/glslang.l"
#line 17 "./glslang.l"
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
......@@ -21,7 +21,7 @@
#line 25 "./compiler/glslang_lex.cpp"
#line 25 "./glslang_lex.cpp"
#define YY_INT_ALIGNED short int
......@@ -2959,7 +2959,7 @@ extern "C" {
void CPPDebugLogMsg(const char *msg)
{
SETUP_CONTEXT(cpp);
context->infoSink.debug.message(EPrefixNone, msg);
context->trace(msg);
}
void CPPWarningToInfoLog(const char *msg)
......@@ -3033,85 +3033,12 @@ void DecLineNumber()
void HandlePragma(const char **tokens, int numTokens)
{
SETUP_CONTEXT(cpp);
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"))
context->contextPragma.optimize = true;
else if (!strcmp(tokens[2], "off"))
context->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"))
context->contextPragma.debug = true;
else if (!strcmp(tokens[2], "off"))
context->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
}
if (numTokens != 4) return;
if (strcmp(tokens[1], "(") != 0) return;
if (strcmp(tokens[3], ")") != 0) return;
context->handlePragmaDirective(yylineno, tokens[0], tokens[2]);
}
void StoreStr(char *string)
......@@ -3136,58 +3063,10 @@ void ResetTString(void)
context->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)
{
SETUP_CONTEXT(cpp);
TBehavior behaviorVal = GetBehavior(behavior);
TMap<TString, TBehavior>:: 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 = context->extensionBehavior.begin(); iter != context->extensionBehavior.end(); ++iter)
iter->second = behaviorVal;
}
} else {
iter = context->extensionBehavior.find(TString(extName));
if (iter == context->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";
context->infoSink.info.message(EPrefixWarning, msg.c_str(), yylineno);
break;
default:
break;
}
return;
} else
iter->second = behaviorVal;
}
context->handleExtensionDirective(yylineno, extName, behavior);
}
} // extern "C"
......
......@@ -4514,9 +4514,8 @@ yyreduce:
// store the pragma information for debug and optimize and other vendor specific
// information. This information can be queried from the parse tree
(yyval.interm.intermNode)->getAsAggregate()->setOptimize(context->contextPragma.optimize);
(yyval.interm.intermNode)->getAsAggregate()->setDebug(context->contextPragma.debug);
(yyval.interm.intermNode)->getAsAggregate()->addToPragmaTable(context->contextPragma.pragmaTable);
(yyval.interm.intermNode)->getAsAggregate()->setOptimize(context->pragma().optimize);
(yyval.interm.intermNode)->getAsAggregate()->setDebug(context->pragma().debug);
if ((yyvsp[(3) - (3)].interm.intermNode) && (yyvsp[(3) - (3)].interm.intermNode)->getAsAggregate())
(yyval.interm.intermNode)->getAsAggregate()->setEndLine((yyvsp[(3) - (3)].interm.intermNode)->getAsAggregate()->getEndLine());
......
......@@ -433,15 +433,15 @@ protected:
typedef TVector<TIntermNode*> TIntermSequence;
typedef TVector<int> TQualifierList;
typedef TMap<TString, TString> TPragmaTable;
//
// Nodes that operate on an arbitrary sized set of children.
//
class TIntermAggregate : public TIntermOperator {
public:
TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), pragmaTable(0), endLine(0), useEmulatedFunction(false) { }
TIntermAggregate(TOperator o) : TIntermOperator(o), pragmaTable(0), useEmulatedFunction(false) { }
~TIntermAggregate() { delete pragmaTable; }
TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), endLine(0), useEmulatedFunction(false) { }
TIntermAggregate(TOperator o) : TIntermOperator(o), useEmulatedFunction(false) { }
~TIntermAggregate() { }
virtual TIntermAggregate* getAsAggregate() { return this; }
virtual void traverse(TIntermTraverser*);
......@@ -458,8 +458,7 @@ public:
bool getOptimize() { return optimize; }
void setDebug(bool d) { debug = d; }
bool getDebug() { return debug; }
void addToPragmaTable(const TPragmaTable& pTable);
const TPragmaTable& getPragmaTable() const { return *pragmaTable; }
void setEndLine(TSourceLoc line) { endLine = line; }
TSourceLoc getEndLine() const { return endLine; }
......@@ -475,7 +474,6 @@ protected:
bool optimize;
bool debug;
TPragmaTable *pragmaTable;
TSourceLoc endLine;
// If set to true, replace the built-in function call with an emulated one
......
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include <stdlib.h>
#include <string.h>
extern "C" {
#include "compiler/preprocessor/lexer_glue.h"
#include "compiler/preprocessor/slglobals.h"
#include "compiler/preprocessor/scanner.h"
}
#include "compiler/preprocessor/new/Diagnostics.h"
#include "compiler/preprocessor/new/Token.h"
#include "compiler/preprocessor/new/Tokenizer.h"
class Diagnostics : public pp::Diagnostics
{
protected:
virtual void print(ID id,
const pp::SourceLocation& loc,
const std::string& text)
{
// TODO(alokp): Implement me.
}
};
struct InputSrcLexer
{
InputSrc base;
pp::Diagnostics* diagnostics;
pp::Lexer* lexer;
};
static bool CopySymbolName(const std::string& name, yystypepp* yylvalpp)
{
if (name.length() > MAX_SYMBOL_NAME_LEN)
{
CPPErrorToInfoLog("BUFFER OVERFLOW");
return false;
}
strcpy(yylvalpp->symbol_name, name.c_str());
return true;
}
static int lex(InputSrc* in, yystypepp* yylvalpp)
{
InputSrcLexer* src = ((InputSrcLexer *)in);
int ret = 0;
pp::Token token;
src->lexer->lex(&token);
switch (token.type)
{
case 0: // EOF
delete src->lexer;
delete src->diagnostics;
free(src);
cpp->currentInput = 0;
ret = EOF;
break;
case pp::Token::IDENTIFIER:
if (CopySymbolName(token.value, yylvalpp))
{
yylvalpp->sc_ident = LookUpAddString(atable, token.value.c_str());
}
ret = CPP_IDENTIFIER;
break;
case pp::Token::CONST_INT:
if (CopySymbolName(token.value, yylvalpp))
{
yylvalpp->sc_int = atoi(token.value.c_str());
}
ret = CPP_INTCONSTANT;
break;
case pp::Token::CONST_FLOAT:
CopySymbolName(token.value, yylvalpp);
ret = CPP_FLOATCONSTANT;
break;
case pp::Token::OP_INC:
ret = CPP_INC_OP;
break;
case pp::Token::OP_DEC:
ret = CPP_DEC_OP;
break;
case pp::Token::OP_RIGHT:
ret = CPP_RIGHT_OP;
break;
case pp::Token::OP_LE:
ret = CPP_LE_OP;
break;
case pp::Token::OP_GE:
ret = CPP_GE_OP;
break;
case pp::Token::OP_EQ:
ret = CPP_EQ_OP;
break;
case pp::Token::OP_NE:
ret = CPP_NE_OP;
break;
case pp::Token::OP_AND:
ret = CPP_AND_OP;
break;
case pp::Token::OP_XOR:
ret = CPP_XOR_OP;
break;
case pp::Token::OP_OR:
ret = CPP_OR_OP;
break;
case pp::Token::OP_ADD_ASSIGN:
ret = CPP_ADD_ASSIGN;
break;
case pp::Token::OP_SUB_ASSIGN:
ret = CPP_SUB_ASSIGN;
break;
case pp::Token::OP_MUL_ASSIGN:
ret = CPP_MUL_ASSIGN;
break;
case pp::Token::OP_DIV_ASSIGN:
ret = CPP_DIV_ASSIGN;
break;
case pp::Token::OP_MOD_ASSIGN:
ret = CPP_MOD_ASSIGN;
break;
case pp::Token::OP_LEFT_ASSIGN:
ret = CPP_LEFT_ASSIGN;
break;
case pp::Token::OP_RIGHT_ASSIGN:
ret = CPP_RIGHT_ASSIGN;
break;
case pp::Token::OP_AND_ASSIGN:
ret = CPP_AND_ASSIGN;
break;
case pp::Token::OP_XOR_ASSIGN:
ret = CPP_XOR_ASSIGN;
break;
case pp::Token::OP_OR_ASSIGN:
ret = CPP_OR_ASSIGN;
break;
default:
break;
}
SetLineNumber(token.location.line);
SetStringNumber(token.location.file);
return ret;
}
InputSrc* LexerInputSrc(int count, const char* const string[], const int length[])
{
Diagnostics* diagnostics = new Diagnostics;
pp::Tokenizer* lexer = new pp::Tokenizer(diagnostics);
if (!lexer->init(count, string, length))
{
delete lexer;
delete diagnostics;
return 0;
}
InputSrcLexer* in = (InputSrcLexer *) malloc(sizeof(InputSrcLexer));
memset(in, 0, sizeof(InputSrcLexer));
in->base.line = 1;
in->base.scan = lex;
in->diagnostics = diagnostics;
in->lexer = lexer;
return &in->base;
}
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef COMPILER_PREPROCESSOR_LEXER_GLUE_H_
#define COMPILER_PREPROCESSOR_LEXER_GLUE_H_
struct InputSrc;
InputSrc* LexerInputSrc(int count, const char* const string[], const int length[]);
#endif // COMPILER_PREPROCESSOR_LEXER_GLUE_H_
......@@ -59,7 +59,6 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endif
#include "compiler/preprocessor/slglobals.h"
#include "compiler/preprocessor/lexer_glue.h"
#include "compiler/util.h"
typedef struct StringInputSrc {
......@@ -129,22 +128,13 @@ int FreeScanner(void)
return (FreeCPP());
}
// Define this to 1 to use the new lexer.
#define CPP_USE_NEW_LEXER 0
int InitScannerInput(CPPStruct *cpp, int count, const char* const string[], const int length[])
{
#if CPP_USE_NEW_LEXER
InputSrc* in = LexerInputSrc(count, string, length);
if (!in) return 1;
cpp->currentInput = in;
#else
cpp->PaWhichStr = 0;
cpp->PaArgv = string;
cpp->PaArgc = count;
cpp->PaStrLen = length;
ScanFromString(string[0]);
#endif
return 0;
}
......
......@@ -105,7 +105,6 @@ 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(const char *);
#endif // !defined(__SYMBOLS_H)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment