blob: 7bb2f3ba9a5a50ed9be1ff4dd8f9cb874d28806f [file] [log] [blame]
/*
//
// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
*/
/* 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 <stdio.h>
#include <stdlib.h>
#include "compiler/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);
extern int yyparse(void*);
#define YY_DECL int yylex(YYSTYPE* pyylval, void* parseContextLocal)
#define parseContext (*((TParseContext*)(parseContextLocal)))
#define YY_INPUT(buf,result,max_size) (result = yy_input(buf, max_size))
%}
/*
TODO(alokp): yylineno is only here to support old flex.exe in compiler/tools.
Remove it when we can exclusively use the newer version.
*/
%option yylineno
%option noyywrap
%option never-interactive
%x FIELDS
%%
<*>"//"[^\n]*"\n" { /* ?? carriage and/or line-feed? */ };
"invariant" { pyylval->lex.line = yylineno; return(INVARIANT); }
"highp" { pyylval->lex.line = yylineno; return(HIGH_PRECISION); }
"mediump" { pyylval->lex.line = yylineno; return(MEDIUM_PRECISION); }
"lowp" { pyylval->lex.line = yylineno; return(LOW_PRECISION); }
"precision" { pyylval->lex.line = yylineno; return(PRECISION); }
"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); }
"sampler2D" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER2D; }
"samplerCube" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLERCUBE; }
"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; }
"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<float>(atof(yytext)); return(FLOATCONSTANT); }
{D}+"."{D}*({E})? { pyylval->lex.line = yylineno; pyylval->lex.f = static_cast<float>(atof(yytext)); return(FLOATCONSTANT); }
"."{D}+({E})? { pyylval->lex.line = yylineno; pyylval->lex.f = static_cast<float>(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); }
<FIELDS>{L}({L}|{D})* {
BEGIN(INITIAL);
pyylval->lex.line = yylineno;
pyylval->lex.string = NewPoolTString(yytext);
return FIELD_SELECTION; }
<FIELDS>[ \t\v\f\r] {}
[ \t\v\n\f\r] { }
<*><<EOF>> { (&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 "compiler/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)
{
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 = yyparse((void*)(&parseContextLocal));
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<TVariable*>(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<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 = ((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;
}