Commit bc70a688 authored by Roberto Raggi's avatar Roberto Raggi
Browse files

Imported our new GLSL front-end.

parent 89eb27d2
HEADERS += $$PWD/glsllexer.h $$PWD/glslparser.h glslparsertable_p.h $$PWD/glslast.h
SOURCES += $$PWD/glslkeywords.cpp $$PWD/glslparser.cpp $$PWD/glslparsertable.cpp \
$$PWD/glsllexer.cpp $$PWD/glslast.cpp $$PWD/glsldump.cpp $$PWD/glsldelete.cpp
OTHER_FILES = $$PWD/specs/glsl.g.in \
$$PWD/specs/grammar.txt
This diff is collapsed.
TEMPLATE = lib
CONFIG += dll
TARGET = GLSL
DEFINES += GLSL_BUILD_DIR QT_CREATOR
include(../../qtcreatorlibrary.pri)
include(glsl-lib.pri)
include(../utils/utils.pri)
#include "glslast.h"
using namespace GLSL;
AST::AST()
{
}
AST::~AST()
{
}
#ifndef GLSLAST_H
#define GLSLAST_H
#include <vector>
namespace GLSL {
class AST;
class Operand;
class Operator;
class AST
{
public:
AST();
virtual ~AST();
virtual Operand *asOperand() { return 0; }
virtual Operator *asOperator() { return 0; }
};
class Operand: public AST
{
public:
Operand(int location)
: location(location) {}
virtual Operand *asOperand() { return this; }
public: // attributes
int location;
};
class Operator: public AST, public std::vector<AST *>
{
typedef std::vector<AST *> _Base;
public:
template <typename It>
Operator(int ruleno, It begin, It end)
: _Base(begin, end), ruleno(ruleno) {}
virtual Operator *asOperator() { return this; }
public: // attributes
int ruleno;
};
} // namespace GLSL
#endif // GLSLAST_H
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#include "glsllexer.h"
#include "glslparser.h"
#include <cctype>
#include <iostream>
using namespace GLSL;
Lexer::Lexer(const char *source, unsigned size)
: _source(source),
_it(source),
_end(source + size),
_size(size),
_yychar('\n'),
_lineno(0),
_variant(Variant_Mask & ~Variant_Reserved) // everything except reserved
{
}
Lexer::~Lexer()
{
}
void Lexer::yyinp()
{
if (_it != _end) {
_yychar = *_it++;
if (_yychar == '\n')
++_lineno;
} else
_yychar = 0;
}
int Lexer::yylex(Token *tk)
{
const char *pos = 0;
int line = 0;
const int kind = yylex_helper(&pos, &line);
tk->kind = kind;
tk->position = pos - _source;
tk->length = _it - pos - 1;
tk->line = line;
tk->matchingBrace = 0;
return kind;
}
int Lexer::yylex_helper(const char **position, int *line)
{
again:
while (std::isspace(_yychar))
yyinp();
*position = _it - 1;
*line = _lineno;
if (_yychar == 0)
return Parser::EOF_SYMBOL;
const int ch = _yychar;
yyinp();
switch (ch) {
case '#':
for (; _yychar; yyinp()) {
if (_yychar == '\n')
break;
}
goto again;
// one of `!', `!='
case '!':
if (_yychar == '=') {
yyinp();
return Parser::T_NE_OP;
}
return Parser::T_BANG;
// one of
// %
// %=
case '%':
if (_yychar == '=') {
yyinp();
return Parser::T_MOD_ASSIGN;
}
return Parser::T_PERCENT;
// one of
// &
// &&
// &=
case '&':
if (_yychar == '=') {
yyinp();
return Parser::T_AND_ASSIGN;
} else if (_yychar == '&') {
yyinp();
return Parser::T_AND_OP;
}
return Parser::T_AMPERSAND;
// (
case '(':
return Parser::T_LEFT_PAREN;
// )
case ')':
return Parser::T_RIGHT_PAREN;
// one of
// *
// *=
case '*':
if (_yychar == '=') {
yyinp();
return Parser::T_MUL_ASSIGN;
}
return Parser::T_STAR;
// one of
// ++
// +=
// +
case '+':
if (_yychar == '=') {
yyinp();
return Parser::T_ADD_ASSIGN;
} else if (_yychar == '+') {
yyinp();
return Parser::T_INC_OP;
}
return Parser::T_PLUS;
// ,
case ',':
return Parser::T_COMMA;
// one of
// -
// --
// -=
case '-':
if (_yychar == '=') {
yyinp();
return Parser::T_SUB_ASSIGN;
} else if (_yychar == '-') {
yyinp();
return Parser::T_DEC_OP;
}
return Parser::T_DASH;
// one of
// .
// float constant
case '.':
if (std::isdigit(_yychar)) {
while (std::isalnum(_yychar)) {
yyinp();
}
return Parser::T_NUMBER;
}
return Parser::T_DOT;
// one of
// /
// /=
// comment
case '/':
if (_yychar == '/') {
for (; _yychar; yyinp()) {
if (_yychar == '\n')
break;
}
goto again;
} else if (_yychar == '*') {
yyinp();
while (_yychar) {
if (_yychar == '*') {
yyinp();
if (_yychar == '/') {
yyinp();
goto again;
}
} else {
yyinp();
}
}
goto again;
} else if (_yychar == '=') {
yyinp();
return Parser::T_DIV_ASSIGN;
}
return Parser::T_SLASH;
// :
case ':':
return Parser::T_COLON;
// ;
case ';':
return Parser::T_SEMICOLON;
// one of
// <
// <=
// <<
// <<=
case '<':
if (_yychar == '=') {
yyinp();
return Parser::T_LE_OP;
} else if (_yychar == '<') {
yyinp();
if (_yychar == '=') {
yyinp();
return Parser::T_LEFT_ASSIGN;
}
return Parser::T_LEFT_OP;
}
return Parser::T_LEFT_ANGLE;
// one of
// =
// ==
case '=':
if (_yychar == '=') {
yyinp();
return Parser::T_EQ_OP;
}
return Parser::T_EQUAL;
// one of
// >
// >=
// >>=
// >>
case '>':
if (_yychar == '=') {
yyinp();
return Parser::T_GE_OP;
} else if (_yychar == '>') {
yyinp();
if (_yychar == '=') {
yyinp();
return Parser::T_RIGHT_ASSIGN;
}
return Parser::T_RIGHT_OP;
}
return Parser::T_RIGHT_ANGLE;
// ?
case '?':
return Parser::T_QUESTION;
// [
case '[':
return Parser::T_LEFT_BRACKET;
// ]
case ']':
return Parser::T_RIGHT_BRACKET;
// one of
// ^
// ^=
case '^':
if (_yychar == '=') {
yyinp();
return Parser::T_XOR_ASSIGN;
}
return Parser::T_XOR_OP;
// {
case '{':
return Parser::T_LEFT_BRACE;
// one of
// |
// |=
// ||
case '|':
if (_yychar == '=') {
yyinp();
return Parser::T_OR_ASSIGN;
} else if (_yychar == '|') {
yyinp();
return Parser::T_OR_OP;
}
return Parser::T_VERTICAL_BAR;
// }
case '}':
return Parser::T_RIGHT_BRACE;
// ~
case '~':
return Parser::T_TILDE;
default:
if (std::isalpha(ch) || ch == '_') {
const char *word = _it - 2;
while (std::isalnum(_yychar) || _yychar == '_') {
yyinp();
}
int t = classify(word, _it - word -1);
if (!(t & Variant_Mask))
return t;
if ((_variant & t & Variant_Mask) == 0) {
// TODO: issue a proper error for the unsupported keyword
std::string keyword(word, _it - word -1);
fprintf(stderr, "unsupported keyword `%s' at line %d\n",
keyword.c_str(), _lineno);
}
return t & ~Variant_Mask;
} else if (std::isdigit(ch)) {
while (std::isalnum(_yychar) || _yychar == '.') {
yyinp();
}
return Parser::T_NUMBER;
}
} // switch
return Parser::T_ERROR;
}
#ifndef GLSLLEXER_H
#define GLSLLEXER_H
namespace GLSL {
class Token
{
public:
int kind;
int position;
int length;
int line; // ### remove
union {
int matchingBrace;
void *ptr;
};
Token()
: kind(0), position(0), length(0), line(0), ptr(0) {}
bool is(int k) const { return k == kind; }
bool isNot(int k) const { return k != kind; }
};
class Lexer
{
public:
Lexer(const char *source, unsigned size);
~Lexer();
enum
{
// Extra flag bits added to tokens by Lexer::classify() that
// indicate which variant of GLSL the keyword belongs to.
Variant_GLSL_120 = 0x00010000, // 1.20 and higher
Variant_GLSL_150 = 0x00020000, // 1.50 and higher
Variant_GLSL_400 = 0x00040000, // 4.00 and higher
Variant_GLSL_ES_100 = 0x00080000, // ES 1.00 and higher
Variant_GLSL_Qt = 0x00100000,
Variant_VertexShader = 0x00200000,
Variant_FragmentShader = 0x00400000,
Variant_Reserved = 0x80000000,
Variant_Mask = 0xFFFF0000
};
int variant() const { return _variant; }
void setVariant(int flags) { _variant = flags; }
int yylex(Token *tk);
private:
static int classify(const char *s, int len);
void yyinp();
int yylex_helper(const char **position, int *line);
private:
const char *_source;
const char *_it;
const char *_end;
int _size;
int _yychar;
int _lineno;
int _variant;
};
} // end of namespace GLSL
#endif // GLSLLEXER_H
#include "glslparser.h"
#include <iostream>
using namespace GLSL;
namespace GLSL {
void dumpAST(AST *);
void deleteAST(AST *ast);
}
Parser::Parser(const char *source, unsigned size, int variant)
: _tos(-1), _index(0)
{
_tokens.reserve(1024);
_stateStack.resize(128);
_locationStack.resize(128);
_astStack.resize(128);
_tokens.push_back(Token()); // invalid token
std::stack<int> parenStack;
std::stack<int> bracketStack;
std::stack<int> braceStack;
Lexer lexer(source, size);
lexer.setVariant(variant);
Token tk;
do {
lexer.yylex(&tk);
switch (tk.kind) {
case T_LEFT_PAREN:
parenStack.push(_tokens.size());
break;
case T_LEFT_BRACKET:
bracketStack.push(_tokens.size());
break;
case T_LEFT_BRACE:
braceStack.push(_tokens.size());
break;
case T_RIGHT_PAREN:
if (! parenStack.empty()) {
_tokens[parenStack.top()].matchingBrace = _tokens.size();
parenStack.pop();
}
break;
case T_RIGHT_BRACKET:
if (! bracketStack.empty()) {
_tokens[bracketStack.top()].matchingBrace = _tokens.size();
bracketStack.pop();
}
break;
case T_RIGHT_BRACE:
if (! braceStack.empty()) {
_tokens[braceStack.top()].matchingBrace = _tokens.size();
braceStack.pop();
}
break;
default:
break;
}
_tokens.push_back(tk);
} while (tk.isNot(EOF_SYMBOL));
_index = 1;
}
Parser::~Parser()
{
}
void Parser::dump(AST *ast)
{
dumpAST(ast);
}
bool Parser::parse()
{
int action = 0;
int yytoken = -1;
int yyloc = -1;
Operand *opd = 0;
_tos = -1;
do {
if (yytoken == -1 && -TERMINAL_COUNT != action_index[action]) {
yyloc = consumeToken();
yytoken = tokenKind(yyloc);
if (yytoken == T_IDENTIFIER && t_action(action, T_TYPE_NAME) != 0) {
const Token &la = tokenAt(_index);
if (la.is(T_IDENTIFIER)) {
yytoken = T_TYPE_NAME;
} else if (la.is(T_LEFT_BRACKET) && la.matchingBrace != 0 &&
tokenAt(la.matchingBrace + 1).is(T_IDENTIFIER)) {
yytoken = T_TYPE_NAME;
}
}
opd = new Operand(yyloc);
}
if (unsigned(++_tos) == _stateStack.size()) {
_stateStack.resize(_tos * 2);
_locationStack.resize(_tos * 2);
_astStack.resize(_tos * 2);
}
_stateStack[_tos] = action;
action = t_action(action, yytoken);
if (action > 0) {
if (action == ACCEPT_STATE) {
--_tos;
dump(_astStack[0]);
deleteAST(_astStack[0]);
return true;
}
_astStack[_tos] = opd;
_locationStack[_tos] = yyloc;
yytoken = -1;
} else if (action < 0) {
const int ruleno = -action - 1;
const int N = rhs[ruleno];
_tos -= N;
if (N == 0)
_astStack[_tos] = 0;
else
_astStack[_tos] = new Operator(ruleno, &_astStack[_tos], &_astStack[_tos + N]);
action = nt_action(_stateStack[_tos], lhs[ruleno] - TERMINAL_COUNT);