blob: 094627e422de7c75e9c43ae7dcb9cf51b6fd7ed9 [file] [log] [blame] [edit]
/*
// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
This file contains the Lex specification for GLSL ES preprocessor.
Based on Microsoft Visual Studio 2010 Preprocessor Grammar:
http://msdn.microsoft.com/en-us/library/2scxys89.aspx
IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh.
*/
%top{
// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
}
%{
#include "Tokenizer.h"
#include "Diagnostics.h"
#include "Token.h"
#if defined(__GNUC__)
// Triggered by the auto-generated yy_fatal_error function.
#pragma GCC diagnostic ignored "-Wmissing-noreturn"
#endif
typedef std::string YYSTYPE;
typedef pp::SourceLocation YYLTYPE;
// Use the unused yycolumn variable to track file (string) number.
#define yyfileno yycolumn
#define YY_USER_INIT \
do { \
yyfileno = 0; \
yylineno = 1; \
yyextra->leadingSpace = false; \
yyextra->lineStart = true; \
} while(0);
#define YY_USER_ACTION \
do \
{ \
pp::Input* input = &yyextra->input; \
pp::Input::Location* scanLoc = &yyextra->scanLoc; \
while ((scanLoc->sIndex < input->count()) && \
(scanLoc->cIndex >= input->length(scanLoc->sIndex))) \
{ \
scanLoc->cIndex -= input->length(scanLoc->sIndex++); \
++yyfileno; yylineno = 1; \
} \
yylloc->file = yyfileno; \
yylloc->line = yylineno; \
scanLoc->cIndex += yyleng; \
} while(0);
#define YY_INPUT(buf, result, maxSize) \
result = yyextra->input.read(buf, maxSize);
%}
%option noyywrap nounput never-interactive
%option reentrant bison-bridge bison-locations
%option prefix="pp"
%option extra-type="pp::Tokenizer::Context*"
%x COMMENT
NEWLINE \n|\r|\r\n
IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]*
PUNCTUATOR [][<>(){}.+-/*%^|&~=!:;,?]
DECIMAL_CONSTANT [1-9][0-9]*[uU]?
OCTAL_CONSTANT 0[0-7]*[uU]?
HEXADECIMAL_CONSTANT 0[xX][0-9a-fA-F]+[uU]?
DIGIT [0-9]
EXPONENT_PART [eE][+-]?{DIGIT}+
FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".")
%%
/* Line comment */
"//"[^\r\n]*
/* Block comment */
/* Line breaks are just counted - not returned. */
/* The comment is replaced by a single space. */
"/*" { BEGIN(COMMENT); }
<COMMENT>[^*\r\n]+
<COMMENT>"*"
<COMMENT>{NEWLINE} { ++yylineno; }
<COMMENT>"*/" {
yyextra->leadingSpace = true;
BEGIN(INITIAL);
}
# {
// # is only valid at start of line for preprocessor directives.
yylval->assign(1, yytext[0]);
return yyextra->lineStart ? pp::Token::PP_HASH : pp::Token::PP_OTHER;
}
{IDENTIFIER} {
yylval->assign(yytext, yyleng);
return pp::Token::IDENTIFIER;
}
({DECIMAL_CONSTANT}[uU]?)|({OCTAL_CONSTANT}[uU]?)|({HEXADECIMAL_CONSTANT}[uU]?) {
yylval->assign(yytext, yyleng);
return pp::Token::CONST_INT;
}
({DIGIT}+{EXPONENT_PART}[fF]?)|({FRACTIONAL_CONSTANT}{EXPONENT_PART}?[fF]?) {
yylval->assign(yytext, yyleng);
return pp::Token::CONST_FLOAT;
}
/* Anything that starts with a {DIGIT} or .{DIGIT} must be a number. */
/* Rule to catch all invalid integers and floats. */
({DIGIT}+[_a-zA-Z0-9.]*)|("."{DIGIT}+[_a-zA-Z0-9.]*) {
yylval->assign(yytext, yyleng);
return pp::Token::PP_NUMBER;
}
"++" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_INC;
}
"--" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_DEC;
}
"<<" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_LEFT;
}
">>" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_RIGHT;
}
"<=" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_LE;
}
">=" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_GE;
}
"==" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_EQ;
}
"!=" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_NE;
}
"&&" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_AND;
}
"^^" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_XOR;
}
"||" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_OR;
}
"+=" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_ADD_ASSIGN;
}
"-=" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_SUB_ASSIGN;
}
"*=" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_MUL_ASSIGN;
}
"/=" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_DIV_ASSIGN;
}
"%=" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_MOD_ASSIGN;
}
"<<=" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_LEFT_ASSIGN;
}
">>=" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_RIGHT_ASSIGN;
}
"&=" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_AND_ASSIGN;
}
"^=" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_XOR_ASSIGN;
}
"|=" {
yylval->assign(yytext, yyleng);
return pp::Token::OP_OR_ASSIGN;
}
{PUNCTUATOR} {
yylval->assign(1, yytext[0]);
return yytext[0];
}
[ \t\v\f]+ { yyextra->leadingSpace = true; }
{NEWLINE} {
++yylineno;
yylval->assign(1, '\n');
return '\n';
}
\\{NEWLINE} { ++yylineno; }
. {
yylval->assign(1, yytext[0]);
return pp::Token::PP_OTHER;
}
<*><<EOF>> {
// YY_USER_ACTION is not invoked for handling EOF.
// Set the location for EOF token manually.
pp::Input* input = &yyextra->input;
pp::Input::Location* scanLoc = &yyextra->scanLoc;
int sIndexMax = std::max(0, input->count() - 1);
if (scanLoc->sIndex != sIndexMax)
{
// We can only reach here if there are empty strings at the
// end of the input.
scanLoc->sIndex = sIndexMax; scanLoc->cIndex = 0;
yyfileno = sIndexMax; yylineno = 1;
}
yylloc->file = yyfileno;
yylloc->line = yylineno;
yylval->clear();
if (YY_START == COMMENT)
{
yyextra->diagnostics->report(pp::Diagnostics::EOF_IN_COMMENT,
pp::SourceLocation(yyfileno, yylineno),
"");
}
yyterminate();
}
%%
namespace pp {
// TODO(alokp): Maximum token length should ideally be specified by
// the preprocessor client, i.e., the compiler.
const size_t Tokenizer::kMaxTokenLength = 256;
Tokenizer::Tokenizer(Diagnostics* diagnostics) : mHandle(0)
{
mContext.diagnostics = diagnostics;
}
Tokenizer::~Tokenizer()
{
destroyScanner();
}
bool Tokenizer::init(int count, const char* const string[], const int length[])
{
if (count < 0) return false;
if ((count > 0) && (string == 0)) return false;
mContext.input = Input(count, string, length);
return initScanner();
}
void Tokenizer::setFileNumber(int file)
{
// We use column number as file number.
// See macro yyfileno.
yyset_column(file, mHandle);
}
void Tokenizer::setLineNumber(int line)
{
yyset_lineno(line, mHandle);
}
void Tokenizer::lex(Token* token)
{
token->type = yylex(&token->text, &token->location, mHandle);
if (token->text.size() > kMaxTokenLength)
{
mContext.diagnostics->report(Diagnostics::TOKEN_TOO_LONG,
token->location, token->text);
token->text.erase(kMaxTokenLength);
}
token->flags = 0;
token->setAtStartOfLine(mContext.lineStart);
mContext.lineStart = token->type == '\n';
token->setHasLeadingSpace(mContext.leadingSpace);
mContext.leadingSpace = false;
}
bool Tokenizer::initScanner()
{
if ((mHandle == NULL) && yylex_init_extra(&mContext, &mHandle))
return false;
yyrestart(0, mHandle);
return true;
}
void Tokenizer::destroyScanner()
{
if (mHandle == NULL)
return;
yylex_destroy(mHandle);
mHandle = NULL;
}
} // namespace pp