Files
qt-creator/src/libs/glsl/glsllexer.cpp

402 lines
9.2 KiB
C++
Raw Normal View History

/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
2010-11-10 12:32:34 +01:00
#include "glsllexer.h"
#include "glslparser.h"
#include "glslengine.h"
2010-11-10 12:32:34 +01:00
#include <cctype>
#include <iostream>
2010-11-10 16:20:37 +01:00
#include <cstdio>
2010-11-10 12:32:34 +01:00
using namespace GLSL;
Lexer::Lexer(Engine *engine, const char *source, unsigned size)
: _engine(engine),
_source(source),
2010-11-10 12:32:34 +01:00
_it(source),
_size(size),
_yychar('\n'),
_lineno(0),
_state(0),
_variant(Variant_Mask & ~Variant_Reserved), // everything except reserved
_scanKeywords(true),
_scanComments(false)
2010-11-10 12:32:34 +01:00
{
}
Lexer::~Lexer()
{
}
void Lexer::yyinp()
{
_yychar = (unsigned char) *_it++;
if (_yychar == '\n')
++_lineno;
2010-11-10 12:32:34 +01:00
}
int Lexer::yylex(Token *tk)
{
const char *pos = 0;
int line = 0;
_yyval.ptr = 0;
2010-11-10 12:32:34 +01:00
const int kind = yylex_helper(&pos, &line);
tk->kind = kind;
tk->position = pos - _source;
tk->length = _it - pos - 1;
tk->line = line;
tk->ptr = _yyval.ptr;
2010-11-10 12:32:34 +01:00
return kind;
}
enum {
State_normal,
State_comment
};
2010-11-10 12:32:34 +01:00
int Lexer::yylex_helper(const char **position, int *line)
{
2010-11-10 16:20:37 +01:00
again:
while (std::isspace(_yychar))
yyinp();
2010-11-10 12:32:34 +01:00
*position = _it - 1;
*line = _lineno;
if (_yychar == 0)
return Parser::EOF_SYMBOL;
if (_state == State_comment) {
while (_yychar) {
if (_yychar == '*') {
yyinp();
if (_yychar == '/') {
yyinp();
_state = State_normal;
break;
}
} else {
yyinp();
}
}
return Parser::T_COMMENT;
}
2010-11-10 12:32:34 +01:00
const int ch = _yychar;
yyinp();
switch (ch) {
case '#':
for (; _yychar; yyinp()) {
if (_yychar == '\n')
break;
}
goto again;
2010-11-10 16:20:37 +01:00
// one of `!', `!='
2010-11-10 12:32:34 +01:00
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;
}
if (_scanComments)
return Parser::T_COMMENT;
2010-11-10 12:32:34 +01:00
goto again;
} else if (_yychar == '*') {
yyinp();
while (_yychar) {
if (_yychar == '*') {
yyinp();
if (_yychar == '/') {
yyinp();
if (_scanComments)
return Parser::T_COMMENT;
2010-11-10 12:32:34 +01:00
goto again;
}
} else {
yyinp();
}
}
if (_scanComments) {
_state = State_comment;
return Parser::T_COMMENT;
}
2010-11-10 12:32:34 +01:00
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();
}
if (_scanKeywords) {
const int k = findKeyword(word, _it - word - 1);
if (k != Parser::T_IDENTIFIER)
return k;
}
if (_engine)
_yyval.string = _engine->identifier(word, _it - word - 1);
return Parser::T_IDENTIFIER;
2010-11-10 12:32:34 +01:00
} else if (std::isdigit(ch)) {
const char *word = _it - 2;
2010-11-10 12:32:34 +01:00
while (std::isalnum(_yychar) || _yychar == '.') {
yyinp();
}
if (_engine)
_yyval.string = _engine->identifier(word, _it - word - 1);
2010-11-10 12:32:34 +01:00
return Parser::T_NUMBER;
}
} // switch
return Parser::T_ERROR;
}
int Lexer::findKeyword(const char *word, int length) const
{
int t = classify(word, length);
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, length);
fprintf(stderr, "unsupported keyword `%s' at line %d\n",
keyword.c_str(), _lineno);
}
return t & ~Variant_Mask;
}