2451 lines
77 KiB
Plaintext
2451 lines
77 KiB
Plaintext
/*
|
|
Copyright (c) 2010-2013, Intel Corporation
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are
|
|
met:
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
* Neither the name of Intel Corporation nor the names of its
|
|
contributors may be used to endorse or promote products derived from
|
|
this software without specific prior written permission.
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
|
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
%locations
|
|
|
|
/* supress shift-reduces conflict message for dangling else */
|
|
/* one for 'if', one for 'cif' */
|
|
%expect 2
|
|
|
|
%define parse.error verbose
|
|
|
|
%code requires {
|
|
|
|
#define yytnamerr lYYTNameErr
|
|
|
|
|
|
#define YYLTYPE SourcePos
|
|
|
|
# define YYLLOC_DEFAULT(Current, Rhs, N) \
|
|
do \
|
|
if (N) \
|
|
{ \
|
|
(Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
|
|
(Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
|
|
(Current).last_line = YYRHSLOC (Rhs, N).last_line; \
|
|
(Current).last_column = YYRHSLOC (Rhs, N).last_column; \
|
|
(Current).name = YYRHSLOC (Rhs, 1).name ; \
|
|
} \
|
|
else \
|
|
{ /* empty RHS */ \
|
|
(Current).first_line = (Current).last_line = \
|
|
YYRHSLOC (Rhs, 0).last_line; \
|
|
(Current).first_column = (Current).last_column = \
|
|
YYRHSLOC (Rhs, 0).last_column; \
|
|
(Current).name = NULL; /* new */ \
|
|
} \
|
|
while (0)
|
|
|
|
struct ForeachDimension;
|
|
|
|
}
|
|
|
|
|
|
%{
|
|
|
|
#include "ispc.h"
|
|
#include "type.h"
|
|
#include "module.h"
|
|
#include "decl.h"
|
|
#include "expr.h"
|
|
#include "sym.h"
|
|
#include "stmt.h"
|
|
#include "util.h"
|
|
|
|
#include <stdio.h>
|
|
#if ISPC_LLVM_VERSION == ISPC_LLVM_3_2
|
|
#include <llvm/Constants.h>
|
|
#else
|
|
#include <llvm/IR/Constants.h>
|
|
#endif
|
|
|
|
#define UNIMPLEMENTED \
|
|
Error(yylloc, "Unimplemented parser functionality %s:%d", \
|
|
__FILE__, __LINE__);
|
|
|
|
union YYSTYPE;
|
|
extern int yylex();
|
|
|
|
extern char *yytext;
|
|
|
|
void yyerror(const char *s);
|
|
|
|
static int lYYTNameErr(char *yyres, const char *yystr);
|
|
|
|
static void lSuggestBuiltinAlternates();
|
|
static void lSuggestParamListAlternates();
|
|
|
|
static void lAddDeclaration(DeclSpecs *ds, Declarator *decl);
|
|
static void lAddFunctionParams(Declarator *decl);
|
|
static void lAddMaskToSymbolTable(SourcePos pos);
|
|
static void lAddThreadIndexCountToSymbolTable(SourcePos pos);
|
|
static std::string lGetAlternates(std::vector<std::string> &alternates);
|
|
static const char *lGetStorageClassString(StorageClass sc);
|
|
static bool lGetConstantInt(Expr *expr, int *value, SourcePos pos, const char *usage);
|
|
static EnumType *lCreateEnumType(const char *name, std::vector<Symbol *> *enums,
|
|
SourcePos pos);
|
|
static void lFinalizeEnumeratorSymbols(std::vector<Symbol *> &enums,
|
|
const EnumType *enumType);
|
|
|
|
static const char *lBuiltinTokens[] = {
|
|
"assert", "bool", "break", "case", "cdo", "cfor", "cif", "cwhile", "const",
|
|
"continue", "default", "do", "delete", "double", "else", "enum", "export",
|
|
"extern", "false", "float", "floating", "for", "foreach", "foreach_active",
|
|
"foreach_tiled", "foreach_unique", "goto", "if", "in", "inline", "int",
|
|
"int8", "int16", "int32", "int64", "integer", "launch", "new", "NULL",
|
|
"number", "print", "return", "signed", "sizeof", "static", "struct",
|
|
"switch", "sync", "task", "true", "typedef", "uniform", "unmasked",
|
|
"unsigned", "varying", "void", "while", NULL
|
|
};
|
|
|
|
static const char *lParamListTokens[] = {
|
|
"bool", "const", "double", "enum", "false", "float", "floating", "int",
|
|
"int8", "int16", "int32", "int64", "integer", "number", "signed", "struct",
|
|
"true", "uniform", "unsigned", "varying", "void", NULL
|
|
};
|
|
|
|
struct ForeachDimension {
|
|
ForeachDimension(Symbol *s = NULL, Expr *b = NULL, Expr *e = NULL) {
|
|
sym = s;
|
|
beginExpr = b;
|
|
endExpr = e;
|
|
}
|
|
Symbol *sym;
|
|
Expr *beginExpr, *endExpr;
|
|
};
|
|
|
|
%}
|
|
|
|
%union {
|
|
uint64_t intVal;
|
|
float floatVal;
|
|
double doubleVal;
|
|
std::string *stringVal;
|
|
const char *constCharPtr;
|
|
|
|
Expr *expr;
|
|
ExprList *exprList;
|
|
const Type *type;
|
|
std::vector<std::pair<const Type *, SourcePos> > *typeList;
|
|
const AtomicType *atomicType;
|
|
const PolyType *polyType;
|
|
int typeQualifier;
|
|
StorageClass storageClass;
|
|
Stmt *stmt;
|
|
DeclSpecs *declSpecs;
|
|
Declaration *declaration;
|
|
std::vector<Declarator *> *declarators;
|
|
std::vector<Declaration *> *declarationList;
|
|
Declarator *declarator;
|
|
std::vector<Declarator *> *structDeclaratorList;
|
|
StructDeclaration *structDeclaration;
|
|
std::vector<StructDeclaration *> *structDeclarationList;
|
|
const EnumType *enumType;
|
|
Symbol *symbol;
|
|
std::vector<Symbol *> *symbolList;
|
|
ForeachDimension *foreachDimension;
|
|
std::vector<ForeachDimension *> *foreachDimensionList;
|
|
std::pair<std::string, SourcePos> *declspecPair;
|
|
std::vector<std::pair<std::string, SourcePos> > *declspecList;
|
|
}
|
|
|
|
|
|
%token TOKEN_INT8_CONSTANT TOKEN_UINT8_CONSTANT
|
|
%token TOKEN_INT16_CONSTANT TOKEN_UINT16_CONSTANT
|
|
%token TOKEN_INT32_CONSTANT TOKEN_UINT32_CONSTANT
|
|
%token TOKEN_INT64_CONSTANT TOKEN_UINT64_CONSTANT
|
|
%token TOKEN_INT32DOTDOTDOT_CONSTANT TOKEN_UINT32DOTDOTDOT_CONSTANT
|
|
%token TOKEN_INT64DOTDOTDOT_CONSTANT TOKEN_UINT64DOTDOTDOT_CONSTANT
|
|
%token TOKEN_FLOAT_CONSTANT TOKEN_DOUBLE_CONSTANT TOKEN_STRING_C_LITERAL
|
|
%token TOKEN_IDENTIFIER TOKEN_STRING_LITERAL TOKEN_TYPE_NAME TOKEN_NULL
|
|
%token TOKEN_PTR_OP TOKEN_INC_OP TOKEN_DEC_OP TOKEN_LEFT_OP TOKEN_RIGHT_OP
|
|
%token TOKEN_LE_OP TOKEN_GE_OP TOKEN_EQ_OP TOKEN_NE_OP
|
|
%token TOKEN_AND_OP TOKEN_OR_OP TOKEN_MUL_ASSIGN TOKEN_DIV_ASSIGN TOKEN_MOD_ASSIGN
|
|
%token TOKEN_ADD_ASSIGN TOKEN_SUB_ASSIGN TOKEN_LEFT_ASSIGN TOKEN_RIGHT_ASSIGN
|
|
%token TOKEN_AND_ASSIGN TOKEN_OR_ASSIGN TOKEN_XOR_ASSIGN
|
|
%token TOKEN_SIZEOF TOKEN_NEW TOKEN_DELETE TOKEN_IN
|
|
|
|
%token TOKEN_EXTERN TOKEN_EXPORT TOKEN_STATIC TOKEN_INLINE TOKEN_TASK TOKEN_DECLSPEC
|
|
%token TOKEN_UNIFORM TOKEN_VARYING TOKEN_TYPEDEF TOKEN_SOA TOKEN_UNMASKED
|
|
%token TOKEN_CHAR TOKEN_INT TOKEN_SIGNED TOKEN_UNSIGNED TOKEN_FLOAT TOKEN_DOUBLE
|
|
%token TOKEN_INTEGER TOKEN_FLOATING TOKEN_NUMBER
|
|
%token TOKEN_INT8 TOKEN_INT16 TOKEN_INT64 TOKEN_CONST TOKEN_VOID TOKEN_BOOL
|
|
%token TOKEN_ENUM TOKEN_STRUCT TOKEN_TRUE TOKEN_FALSE
|
|
|
|
%token TOKEN_CASE TOKEN_DEFAULT TOKEN_IF TOKEN_ELSE TOKEN_SWITCH
|
|
%token TOKEN_WHILE TOKEN_DO TOKEN_LAUNCH TOKEN_FOREACH TOKEN_FOREACH_TILED
|
|
%token TOKEN_FOREACH_UNIQUE TOKEN_FOREACH_ACTIVE TOKEN_DOTDOTDOT
|
|
%token TOKEN_FOR TOKEN_GOTO TOKEN_CONTINUE TOKEN_BREAK TOKEN_RETURN
|
|
%token TOKEN_CIF TOKEN_CDO TOKEN_CFOR TOKEN_CWHILE
|
|
%token TOKEN_SYNC TOKEN_PRINT TOKEN_ASSERT
|
|
|
|
%type <expr> primary_expression postfix_expression integer_dotdotdot
|
|
%type <expr> unary_expression cast_expression funcall_expression launch_expression
|
|
%type <expr> multiplicative_expression additive_expression shift_expression
|
|
%type <expr> relational_expression equality_expression and_expression
|
|
%type <expr> exclusive_or_expression inclusive_or_expression
|
|
%type <expr> logical_and_expression logical_or_expression new_expression
|
|
%type <expr> conditional_expression assignment_expression expression
|
|
%type <expr> initializer constant_expression for_test
|
|
%type <exprList> argument_expression_list initializer_list
|
|
|
|
%type <stmt> statement labeled_statement compound_statement for_init_statement
|
|
%type <stmt> expression_statement selection_statement iteration_statement
|
|
%type <stmt> jump_statement statement_list declaration_statement print_statement
|
|
%type <stmt> assert_statement sync_statement delete_statement unmasked_statement
|
|
|
|
%type <declaration> declaration parameter_declaration
|
|
%type <declarators> init_declarator_list
|
|
%type <declarationList> parameter_list parameter_type_list
|
|
%type <declarator> declarator pointer reference
|
|
%type <declarator> init_declarator direct_declarator struct_declarator
|
|
%type <declarator> abstract_declarator direct_abstract_declarator
|
|
|
|
%type <structDeclaratorList> struct_declarator_list
|
|
%type <structDeclaration> struct_declaration
|
|
%type <structDeclarationList> struct_declaration_list
|
|
|
|
%type <symbolList> enumerator_list
|
|
%type <symbol> enumerator foreach_identifier foreach_active_identifier
|
|
%type <enumType> enum_specifier
|
|
|
|
%type <type> specifier_qualifier_list struct_or_union_specifier
|
|
%type <type> struct_or_union_and_name
|
|
%type <type> type_specifier type_name rate_qualified_type_specifier
|
|
%type <type> short_vec_specifier
|
|
%type <typeList> type_specifier_list
|
|
%type <atomicType> atomic_var_type_specifier
|
|
%type <polyType> poly_type_specifier poly_quant_type_specifier
|
|
|
|
%type <typeQualifier> type_qualifier type_qualifier_list
|
|
%type <storageClass> storage_class_specifier
|
|
%type <declSpecs> declaration_specifiers
|
|
|
|
%type <stringVal> string_constant
|
|
%type <constCharPtr> struct_or_union_name enum_identifier goto_identifier
|
|
%type <constCharPtr> foreach_unique_identifier
|
|
|
|
%type <intVal> int_constant soa_width_specifier rate_qualified_new
|
|
|
|
%type <foreachDimension> foreach_dimension_specifier
|
|
%type <foreachDimensionList> foreach_dimension_list
|
|
|
|
%type <declspecPair> declspec_item
|
|
%type <declspecList> declspec_specifier declspec_list
|
|
|
|
%start translation_unit
|
|
%%
|
|
|
|
string_constant
|
|
: TOKEN_STRING_LITERAL { $$ = new std::string(*yylval.stringVal); }
|
|
| string_constant TOKEN_STRING_LITERAL
|
|
{
|
|
std::string s = *((std::string *)$1);
|
|
s += *yylval.stringVal;
|
|
$$ = new std::string(s);
|
|
}
|
|
;
|
|
|
|
primary_expression
|
|
: TOKEN_IDENTIFIER {
|
|
const char *name = yylval.stringVal->c_str();
|
|
Symbol *s = m->symbolTable->LookupVariable(name);
|
|
$$ = NULL;
|
|
if (s)
|
|
$$ = new SymbolExpr(s, @1);
|
|
else {
|
|
std::vector<Symbol *> funs;
|
|
m->symbolTable->LookupFunction(name, &funs);
|
|
if (funs.size() > 0)
|
|
$$ = new FunctionSymbolExpr(name, funs, @1);
|
|
}
|
|
if ($$ == NULL) {
|
|
std::vector<std::string> alternates =
|
|
m->symbolTable->ClosestVariableOrFunctionMatch(name);
|
|
std::string alts = lGetAlternates(alternates);
|
|
Error(@1, "Undeclared symbol \"%s\".%s", name, alts.c_str());
|
|
}
|
|
}
|
|
| TOKEN_INT8_CONSTANT {
|
|
$$ = new ConstExpr(AtomicType::UniformInt8->GetAsConstType(),
|
|
(int8_t)yylval.intVal, @1);
|
|
}
|
|
| TOKEN_UINT8_CONSTANT {
|
|
$$ = new ConstExpr(AtomicType::UniformUInt8->GetAsConstType(),
|
|
(uint8_t)yylval.intVal, @1);
|
|
}
|
|
| TOKEN_INT16_CONSTANT {
|
|
$$ = new ConstExpr(AtomicType::UniformInt16->GetAsConstType(),
|
|
(int16_t)yylval.intVal, @1);
|
|
}
|
|
| TOKEN_UINT16_CONSTANT {
|
|
$$ = new ConstExpr(AtomicType::UniformUInt16->GetAsConstType(),
|
|
(uint16_t)yylval.intVal, @1);
|
|
}
|
|
| TOKEN_INT32_CONSTANT {
|
|
$$ = new ConstExpr(AtomicType::UniformInt32->GetAsConstType(),
|
|
(int32_t)yylval.intVal, @1);
|
|
}
|
|
| TOKEN_UINT32_CONSTANT {
|
|
$$ = new ConstExpr(AtomicType::UniformUInt32->GetAsConstType(),
|
|
(uint32_t)yylval.intVal, @1);
|
|
}
|
|
| TOKEN_INT64_CONSTANT {
|
|
$$ = new ConstExpr(AtomicType::UniformInt64->GetAsConstType(),
|
|
(int64_t)yylval.intVal, @1);
|
|
}
|
|
| TOKEN_UINT64_CONSTANT {
|
|
$$ = new ConstExpr(AtomicType::UniformUInt64->GetAsConstType(),
|
|
(uint64_t)yylval.intVal, @1);
|
|
}
|
|
| TOKEN_FLOAT_CONSTANT {
|
|
$$ = new ConstExpr(AtomicType::UniformFloat->GetAsConstType(),
|
|
yylval.floatVal, @1);
|
|
}
|
|
| TOKEN_DOUBLE_CONSTANT {
|
|
$$ = new ConstExpr(AtomicType::UniformDouble->GetAsConstType(),
|
|
yylval.doubleVal, @1);
|
|
}
|
|
| TOKEN_TRUE {
|
|
$$ = new ConstExpr(AtomicType::UniformBool->GetAsConstType(), true, @1);
|
|
}
|
|
| TOKEN_FALSE {
|
|
$$ = new ConstExpr(AtomicType::UniformBool->GetAsConstType(), false, @1);
|
|
}
|
|
| TOKEN_NULL {
|
|
$$ = new NullPointerExpr(@1);
|
|
}
|
|
/* | TOKEN_STRING_LITERAL
|
|
{ UNIMPLEMENTED }*/
|
|
| '(' expression ')' { $$ = $2; }
|
|
| '(' error ')' { $$ = NULL; }
|
|
;
|
|
|
|
launch_expression
|
|
: TOKEN_LAUNCH postfix_expression '(' argument_expression_list ')'
|
|
{
|
|
ConstExpr *oneExpr = new ConstExpr(AtomicType::UniformInt32, (int32_t)1, @2);
|
|
Expr *launchCount[3] = {oneExpr, oneExpr, oneExpr};
|
|
$$ = new FunctionCallExpr($2, $4, Union(@2, @5), true, launchCount);
|
|
}
|
|
| TOKEN_LAUNCH postfix_expression '(' ')'
|
|
{
|
|
ConstExpr *oneExpr = new ConstExpr(AtomicType::UniformInt32, (int32_t)1, @2);
|
|
Expr *launchCount[3] = {oneExpr, oneExpr, oneExpr};
|
|
$$ = new FunctionCallExpr($2, new ExprList(Union(@3,@4)), Union(@2, @4), true, launchCount);
|
|
}
|
|
|
|
| TOKEN_LAUNCH '[' assignment_expression ']' postfix_expression '(' argument_expression_list ')'
|
|
{
|
|
ConstExpr *oneExpr = new ConstExpr(AtomicType::UniformInt32, (int32_t)1, @5);
|
|
Expr *launchCount[3] = {$3, oneExpr, oneExpr};
|
|
$$ = new FunctionCallExpr($5, $7, Union(@5,@8), true, launchCount);
|
|
}
|
|
| TOKEN_LAUNCH '[' assignment_expression ']' postfix_expression '(' ')'
|
|
{
|
|
ConstExpr *oneExpr = new ConstExpr(AtomicType::UniformInt32, (int32_t)1, @5);
|
|
Expr *launchCount[3] = {$3, oneExpr, oneExpr};
|
|
$$ = new FunctionCallExpr($5, new ExprList(Union(@5,@6)), Union(@5,@7), true, launchCount);
|
|
}
|
|
|
|
| TOKEN_LAUNCH '[' assignment_expression ',' assignment_expression ']' postfix_expression '(' argument_expression_list ')'
|
|
{
|
|
ConstExpr *oneExpr = new ConstExpr(AtomicType::UniformInt32, (int32_t)1, @7);
|
|
Expr *launchCount[3] = {$3, $5, oneExpr};
|
|
$$ = new FunctionCallExpr($7, $9, Union(@7,@10), true, launchCount);
|
|
}
|
|
| TOKEN_LAUNCH '[' assignment_expression ',' assignment_expression ']' postfix_expression '(' ')'
|
|
{
|
|
ConstExpr *oneExpr = new ConstExpr(AtomicType::UniformInt32, (int32_t)1, @7);
|
|
Expr *launchCount[3] = {$3, $5, oneExpr};
|
|
$$ = new FunctionCallExpr($7, new ExprList(Union(@7,@8)), Union(@7,@9), true, launchCount);
|
|
}
|
|
| TOKEN_LAUNCH '[' assignment_expression ']' '[' assignment_expression ']' postfix_expression '(' argument_expression_list ')'
|
|
{
|
|
ConstExpr *oneExpr = new ConstExpr(AtomicType::UniformInt32, (int32_t)1, @8);
|
|
Expr *launchCount[3] = {$6, $3, oneExpr};
|
|
$$ = new FunctionCallExpr($8, $10, Union(@8,@11), true, launchCount);
|
|
}
|
|
| TOKEN_LAUNCH '[' assignment_expression ']' '[' assignment_expression ']' postfix_expression '(' ')'
|
|
{
|
|
ConstExpr *oneExpr = new ConstExpr(AtomicType::UniformInt32, (int32_t)1, @8);
|
|
Expr *launchCount[3] = {$6, $3, oneExpr};
|
|
$$ = new FunctionCallExpr($8, new ExprList(Union(@8,@9)), Union(@8,@10), true, launchCount);
|
|
}
|
|
|
|
| TOKEN_LAUNCH '[' assignment_expression ',' assignment_expression ',' assignment_expression ']' postfix_expression '(' argument_expression_list ')'
|
|
{
|
|
Expr *launchCount[3] = {$3, $5, $7};
|
|
$$ = new FunctionCallExpr($9, $11, Union(@9,@12), true, launchCount);
|
|
}
|
|
| TOKEN_LAUNCH '[' assignment_expression ',' assignment_expression ',' assignment_expression ']' postfix_expression '(' ')'
|
|
{
|
|
Expr *launchCount[3] = {$3, $5, $7};
|
|
$$ = new FunctionCallExpr($9, new ExprList(Union(@9,@10)), Union(@9,@11), true, launchCount);
|
|
}
|
|
| TOKEN_LAUNCH '[' assignment_expression ']' '[' assignment_expression ']' '[' assignment_expression ']' postfix_expression '(' argument_expression_list ')'
|
|
{
|
|
Expr *launchCount[3] = {$9, $6, $3};
|
|
$$ = new FunctionCallExpr($11, $13, Union(@11,@14), true, launchCount);
|
|
}
|
|
| TOKEN_LAUNCH '[' assignment_expression ']' '[' assignment_expression ']' '[' assignment_expression ']' postfix_expression '(' ')'
|
|
{
|
|
Expr *launchCount[3] = {$9, $6, $3};
|
|
$$ = new FunctionCallExpr($11, new ExprList(Union(@11,@12)), Union(@11,@13), true, launchCount);
|
|
}
|
|
|
|
|
|
| TOKEN_LAUNCH '<' postfix_expression '(' argument_expression_list ')' '>'
|
|
{
|
|
Error(Union(@2, @7), "\"launch\" expressions no longer take '<' '>' "
|
|
"around function call expression.");
|
|
$$ = NULL;
|
|
}
|
|
| TOKEN_LAUNCH '<' postfix_expression '(' ')' '>'
|
|
{
|
|
Error(Union(@2, @6), "\"launch\" expressions no longer take '<' '>' "
|
|
"around function call expression.");
|
|
$$ = NULL;
|
|
}
|
|
| TOKEN_LAUNCH '[' assignment_expression ']' '<' postfix_expression '(' argument_expression_list ')' '>'
|
|
{
|
|
Error(Union(@5, @10), "\"launch\" expressions no longer take '<' '>' "
|
|
"around function call expression.");
|
|
$$ = NULL;
|
|
}
|
|
| TOKEN_LAUNCH '[' assignment_expression ']' '<' postfix_expression '(' ')' '>'
|
|
{
|
|
Error(Union(@5, @9), "\"launch\" expressions no longer take '<' '>' "
|
|
"around function call expression.");
|
|
$$ = NULL;
|
|
}
|
|
;
|
|
|
|
postfix_expression
|
|
: primary_expression
|
|
| postfix_expression '[' expression ']'
|
|
{ $$ = new IndexExpr($1, $3, Union(@1,@4)); }
|
|
| postfix_expression '[' error ']'
|
|
{ $$ = NULL; }
|
|
| launch_expression
|
|
| postfix_expression '.' TOKEN_IDENTIFIER
|
|
{ $$ = MemberExpr::create($1, yytext, Union(@1,@3), @3, false); }
|
|
| postfix_expression TOKEN_PTR_OP TOKEN_IDENTIFIER
|
|
{ $$ = MemberExpr::create($1, yytext, Union(@1,@3), @3, true); }
|
|
| postfix_expression TOKEN_INC_OP
|
|
{ $$ = new UnaryExpr(UnaryExpr::PostInc, $1, Union(@1,@2)); }
|
|
| postfix_expression TOKEN_DEC_OP
|
|
{ $$ = new UnaryExpr(UnaryExpr::PostDec, $1, Union(@1,@2)); }
|
|
;
|
|
|
|
funcall_expression
|
|
: postfix_expression
|
|
| postfix_expression '(' ')'
|
|
{ $$ = new FunctionCallExpr($1, new ExprList(Union(@1,@2)), Union(@1,@3)); }
|
|
| postfix_expression '(' argument_expression_list ')'
|
|
{ $$ = new FunctionCallExpr($1, $3, Union(@1,@4)); }
|
|
| postfix_expression '(' error ')'
|
|
{ $$ = NULL; }
|
|
;
|
|
|
|
argument_expression_list
|
|
: assignment_expression { $$ = new ExprList($1, @1); }
|
|
| argument_expression_list ',' assignment_expression
|
|
{
|
|
ExprList *argList = llvm::dyn_cast<ExprList>($1);
|
|
if (argList == NULL) {
|
|
AssertPos(@1, m->errorCount > 0);
|
|
argList = new ExprList(@3);
|
|
}
|
|
argList->exprs.push_back($3);
|
|
argList->pos = Union(argList->pos, @3);
|
|
$$ = argList;
|
|
}
|
|
;
|
|
|
|
unary_expression
|
|
: funcall_expression
|
|
| TOKEN_INC_OP unary_expression
|
|
{ $$ = new UnaryExpr(UnaryExpr::PreInc, $2, Union(@1, @2)); }
|
|
| TOKEN_DEC_OP unary_expression
|
|
{ $$ = new UnaryExpr(UnaryExpr::PreDec, $2, Union(@1, @2)); }
|
|
| '&' unary_expression
|
|
{ $$ = new AddressOfExpr($2, Union(@1, @2)); }
|
|
| '*' unary_expression
|
|
{ $$ = new PtrDerefExpr($2, Union(@1, @2)); }
|
|
| '+' cast_expression
|
|
{ $$ = $2; }
|
|
| '-' cast_expression
|
|
{ $$ = new UnaryExpr(UnaryExpr::Negate, $2, Union(@1, @2)); }
|
|
| '~' cast_expression
|
|
{ $$ = new UnaryExpr(UnaryExpr::BitNot, $2, Union(@1, @2)); }
|
|
| '!' cast_expression
|
|
{ $$ = new UnaryExpr(UnaryExpr::LogicalNot, $2, Union(@1, @2)); }
|
|
| TOKEN_SIZEOF unary_expression
|
|
{ $$ = new SizeOfExpr($2, Union(@1, @2)); }
|
|
| TOKEN_SIZEOF '(' type_name ')'
|
|
{ $$ = new SizeOfExpr($3, Union(@1, @4)); }
|
|
;
|
|
|
|
cast_expression
|
|
: unary_expression
|
|
| '(' type_name ')' cast_expression
|
|
{
|
|
$$ = new TypeCastExpr($2, $4, Union(@1,@4));
|
|
}
|
|
;
|
|
|
|
multiplicative_expression
|
|
: cast_expression
|
|
| multiplicative_expression '*' cast_expression
|
|
{ $$ = MakeBinaryExpr(BinaryExpr::Mul, $1, $3, Union(@1, @3)); }
|
|
| multiplicative_expression '/' cast_expression
|
|
{ $$ = MakeBinaryExpr(BinaryExpr::Div, $1, $3, Union(@1, @3)); }
|
|
| multiplicative_expression '%' cast_expression
|
|
{ $$ = MakeBinaryExpr(BinaryExpr::Mod, $1, $3, Union(@1, @3)); }
|
|
;
|
|
|
|
additive_expression
|
|
: multiplicative_expression
|
|
| additive_expression '+' multiplicative_expression
|
|
{ $$ = MakeBinaryExpr(BinaryExpr::Add, $1, $3, Union(@1, @3)); }
|
|
| additive_expression '-' multiplicative_expression
|
|
{ $$ = MakeBinaryExpr(BinaryExpr::Sub, $1, $3, Union(@1, @3)); }
|
|
;
|
|
|
|
shift_expression
|
|
: additive_expression
|
|
| shift_expression TOKEN_LEFT_OP additive_expression
|
|
{ $$ = MakeBinaryExpr(BinaryExpr::Shl, $1, $3, Union(@1, @3)); }
|
|
| shift_expression TOKEN_RIGHT_OP additive_expression
|
|
{ $$ = MakeBinaryExpr(BinaryExpr::Shr, $1, $3, Union(@1, @3)); }
|
|
;
|
|
|
|
relational_expression
|
|
: shift_expression
|
|
| relational_expression '<' shift_expression
|
|
{ $$ = new BinaryExpr(BinaryExpr::Lt, $1, $3, Union(@1, @3)); }
|
|
| relational_expression '>' shift_expression
|
|
{ $$ = new BinaryExpr(BinaryExpr::Gt, $1, $3, Union(@1, @3)); }
|
|
| relational_expression TOKEN_LE_OP shift_expression
|
|
{ $$ = new BinaryExpr(BinaryExpr::Le, $1, $3, Union(@1, @3)); }
|
|
| relational_expression TOKEN_GE_OP shift_expression
|
|
{ $$ = new BinaryExpr(BinaryExpr::Ge, $1, $3, Union(@1, @3)); }
|
|
;
|
|
|
|
equality_expression
|
|
: relational_expression
|
|
| equality_expression TOKEN_EQ_OP relational_expression
|
|
{ $$ = new BinaryExpr(BinaryExpr::Equal, $1, $3, Union(@1,@3)); }
|
|
| equality_expression TOKEN_NE_OP relational_expression
|
|
{ $$ = new BinaryExpr(BinaryExpr::NotEqual, $1, $3, Union(@1,@3)); }
|
|
;
|
|
|
|
and_expression
|
|
: equality_expression
|
|
| and_expression '&' equality_expression
|
|
{ $$ = new BinaryExpr(BinaryExpr::BitAnd, $1, $3, Union(@1, @3)); }
|
|
;
|
|
|
|
exclusive_or_expression
|
|
: and_expression
|
|
| exclusive_or_expression '^' and_expression
|
|
{ $$ = new BinaryExpr(BinaryExpr::BitXor, $1, $3, Union(@1, @3)); }
|
|
;
|
|
|
|
inclusive_or_expression
|
|
: exclusive_or_expression
|
|
| inclusive_or_expression '|' exclusive_or_expression
|
|
{ $$ = new BinaryExpr(BinaryExpr::BitOr, $1, $3, Union(@1, @3)); }
|
|
;
|
|
|
|
logical_and_expression
|
|
: inclusive_or_expression
|
|
| logical_and_expression TOKEN_AND_OP inclusive_or_expression
|
|
{ $$ = new BinaryExpr(BinaryExpr::LogicalAnd, $1, $3, Union(@1, @3)); }
|
|
;
|
|
|
|
logical_or_expression
|
|
: logical_and_expression
|
|
| logical_or_expression TOKEN_OR_OP logical_and_expression
|
|
{ $$ = new BinaryExpr(BinaryExpr::LogicalOr, $1, $3, Union(@1, @3)); }
|
|
;
|
|
|
|
conditional_expression
|
|
: logical_or_expression
|
|
| logical_or_expression '?' expression ':' conditional_expression
|
|
{ $$ = new SelectExpr($1, $3, $5, Union(@1,@5)); }
|
|
;
|
|
|
|
rate_qualified_new
|
|
: TOKEN_NEW { $$ = 0; }
|
|
| TOKEN_UNIFORM TOKEN_NEW { $$ = TYPEQUAL_UNIFORM; }
|
|
| TOKEN_VARYING TOKEN_NEW { $$ = TYPEQUAL_VARYING; }
|
|
;
|
|
|
|
rate_qualified_type_specifier
|
|
: type_specifier { $$ = $1; }
|
|
| TOKEN_UNIFORM type_specifier
|
|
{
|
|
if ($2 == NULL)
|
|
$$ = NULL;
|
|
else if ($2->IsVoidType()) {
|
|
Error(@1, "\"uniform\" qualifier is illegal with \"void\" type.");
|
|
$$ = NULL;
|
|
}
|
|
else
|
|
$$ = $2->GetAsUniformType();
|
|
}
|
|
| TOKEN_VARYING type_specifier
|
|
{
|
|
if ($2 == NULL)
|
|
$$ = NULL;
|
|
else if ($2->IsVoidType()) {
|
|
Error(@1, "\"varying\" qualifier is illegal with \"void\" type.");
|
|
$$ = NULL;
|
|
}
|
|
else
|
|
$$ = $2->GetAsVaryingType();
|
|
}
|
|
| soa_width_specifier type_specifier
|
|
{
|
|
if ($2 == NULL)
|
|
$$ = NULL;
|
|
else {
|
|
int soaWidth = (int)$1;
|
|
const StructType *st = CastType<StructType>($2);
|
|
if (st == NULL) {
|
|
Error(@1, "\"soa\" qualifier is illegal with non-struct type \"%s\".",
|
|
$2->GetString().c_str());
|
|
$$ = NULL;
|
|
}
|
|
else if (soaWidth <= 0 || (soaWidth & (soaWidth - 1)) != 0) {
|
|
Error(@1, "soa<%d> width illegal. Value must be positive power "
|
|
"of two.", soaWidth);
|
|
$$ = NULL;
|
|
}
|
|
else
|
|
$$ = st->GetAsSOAType(soaWidth);
|
|
}
|
|
}
|
|
;
|
|
|
|
new_expression
|
|
: conditional_expression
|
|
| rate_qualified_new rate_qualified_type_specifier
|
|
{
|
|
$$ = new NewExpr((int32_t)$1, $2, NULL, NULL, @1, Union(@1, @2));
|
|
}
|
|
| rate_qualified_new rate_qualified_type_specifier '(' initializer_list ')'
|
|
{
|
|
$$ = new NewExpr((int32_t)$1, $2, $4, NULL, @1, Union(@1, @2));
|
|
}
|
|
| rate_qualified_new rate_qualified_type_specifier '[' expression ']'
|
|
{
|
|
$$ = new NewExpr((int32_t)$1, $2, NULL, $4, @1, Union(@1, @4));
|
|
}
|
|
;
|
|
|
|
assignment_expression
|
|
: new_expression
|
|
| unary_expression '=' assignment_expression
|
|
{ $$ = new AssignExpr(AssignExpr::Assign, $1, $3, Union(@1, @3)); }
|
|
| unary_expression TOKEN_MUL_ASSIGN assignment_expression
|
|
{ $$ = new AssignExpr(AssignExpr::MulAssign, $1, $3, Union(@1, @3)); }
|
|
| unary_expression TOKEN_DIV_ASSIGN assignment_expression
|
|
{ $$ = new AssignExpr(AssignExpr::DivAssign, $1, $3, Union(@1, @3)); }
|
|
| unary_expression TOKEN_MOD_ASSIGN assignment_expression
|
|
{ $$ = new AssignExpr(AssignExpr::ModAssign, $1, $3, Union(@1, @3)); }
|
|
| unary_expression TOKEN_ADD_ASSIGN assignment_expression
|
|
{ $$ = new AssignExpr(AssignExpr::AddAssign, $1, $3, Union(@1, @3)); }
|
|
| unary_expression TOKEN_SUB_ASSIGN assignment_expression
|
|
{ $$ = new AssignExpr(AssignExpr::SubAssign, $1, $3, Union(@1, @3)); }
|
|
| unary_expression TOKEN_LEFT_ASSIGN assignment_expression
|
|
{ $$ = new AssignExpr(AssignExpr::ShlAssign, $1, $3, Union(@1, @3)); }
|
|
| unary_expression TOKEN_RIGHT_ASSIGN assignment_expression
|
|
{ $$ = new AssignExpr(AssignExpr::ShrAssign, $1, $3, Union(@1, @3)); }
|
|
| unary_expression TOKEN_AND_ASSIGN assignment_expression
|
|
{ $$ = new AssignExpr(AssignExpr::AndAssign, $1, $3, Union(@1, @3)); }
|
|
| unary_expression TOKEN_XOR_ASSIGN assignment_expression
|
|
{ $$ = new AssignExpr(AssignExpr::XorAssign, $1, $3, Union(@1, @3)); }
|
|
| unary_expression TOKEN_OR_ASSIGN assignment_expression
|
|
{ $$ = new AssignExpr(AssignExpr::OrAssign, $1, $3, Union(@1, @3)); }
|
|
;
|
|
|
|
expression
|
|
: assignment_expression
|
|
| expression ',' assignment_expression
|
|
{ $$ = new BinaryExpr(BinaryExpr::Comma, $1, $3, Union(@1, @3)); }
|
|
;
|
|
|
|
constant_expression
|
|
: conditional_expression
|
|
;
|
|
|
|
declaration_statement
|
|
: declaration
|
|
{
|
|
if ($1 == NULL) {
|
|
AssertPos(@1, m->errorCount > 0);
|
|
$$ = NULL;
|
|
}
|
|
else if ($1->declSpecs->storageClass == SC_TYPEDEF) {
|
|
for (unsigned int i = 0; i < $1->declarators.size(); ++i) {
|
|
if ($1->declarators[i] == NULL)
|
|
AssertPos(@1, m->errorCount > 0);
|
|
else
|
|
m->AddTypeDef($1->declarators[i]->name,
|
|
$1->declarators[i]->type,
|
|
$1->declarators[i]->pos);
|
|
}
|
|
$$ = NULL;
|
|
}
|
|
else {
|
|
$1->DeclareFunctions();
|
|
std::vector<VariableDeclaration> vars = $1->GetVariableDeclarations();
|
|
$$ = new DeclStmt(vars, @1);
|
|
}
|
|
}
|
|
;
|
|
|
|
declaration
|
|
: declaration_specifiers ';'
|
|
{
|
|
$$ = new Declaration($1);
|
|
}
|
|
| declaration_specifiers init_declarator_list ';'
|
|
{
|
|
$$ = new Declaration($1, $2);
|
|
}
|
|
;
|
|
|
|
soa_width_specifier
|
|
: TOKEN_SOA '<' int_constant '>'
|
|
{ $$ = $3; }
|
|
;
|
|
|
|
declspec_item
|
|
: TOKEN_IDENTIFIER
|
|
{
|
|
std::pair<std::string, SourcePos> *p = new std::pair<std::string, SourcePos>;
|
|
p->first = *(yylval.stringVal);
|
|
p->second = @1;
|
|
$$ = p;
|
|
}
|
|
;
|
|
|
|
declspec_list
|
|
: declspec_item
|
|
{
|
|
$$ = new std::vector<std::pair<std::string, SourcePos> >;
|
|
$$->push_back(*$1);
|
|
}
|
|
| declspec_list ',' declspec_item
|
|
{
|
|
if ($1 != NULL)
|
|
$1->push_back(*$3);
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
declspec_specifier
|
|
: TOKEN_DECLSPEC '(' declspec_list ')'
|
|
{
|
|
$$ = $3;
|
|
}
|
|
;
|
|
|
|
declaration_specifiers
|
|
: storage_class_specifier
|
|
{
|
|
$$ = new DeclSpecs(NULL, $1);
|
|
}
|
|
| storage_class_specifier declaration_specifiers
|
|
{
|
|
DeclSpecs *ds = (DeclSpecs *)$2;
|
|
if (ds != NULL) {
|
|
if (ds->storageClass != SC_NONE)
|
|
Error(@1, "Multiple storage class specifiers in a declaration are illegal. "
|
|
"(Have provided both \"%s\" and \"%s\".)",
|
|
lGetStorageClassString(ds->storageClass),
|
|
lGetStorageClassString($1));
|
|
else
|
|
ds->storageClass = $1;
|
|
}
|
|
$$ = ds;
|
|
}
|
|
| declspec_specifier
|
|
{
|
|
$$ = new DeclSpecs;
|
|
if ($1 != NULL)
|
|
$$->declSpecList = *$1;
|
|
}
|
|
| declspec_specifier declaration_specifiers
|
|
{
|
|
DeclSpecs *ds = (DeclSpecs *)$2;
|
|
std::vector<std::pair<std::string, SourcePos> > *declSpecList = $1;
|
|
if (ds != NULL && declSpecList != NULL) {
|
|
for (int i = 0; i < (int)declSpecList->size(); ++i)
|
|
ds->declSpecList.push_back((*declSpecList)[i]);
|
|
}
|
|
$$ = ds;
|
|
}
|
|
| soa_width_specifier
|
|
{
|
|
DeclSpecs *ds = new DeclSpecs;
|
|
ds->soaWidth = (int32_t)$1;
|
|
$$ = ds;
|
|
}
|
|
| soa_width_specifier declaration_specifiers
|
|
{
|
|
DeclSpecs *ds = (DeclSpecs *)$2;
|
|
if (ds != NULL) {
|
|
if (ds->soaWidth != 0)
|
|
Error(@1, "soa<> qualifier supplied multiple times in declaration.");
|
|
else
|
|
ds->soaWidth = (int32_t)$1;
|
|
}
|
|
$$ = ds;
|
|
}
|
|
| type_specifier
|
|
{
|
|
$$ = new DeclSpecs($1);
|
|
}
|
|
| type_specifier '<' int_constant '>'
|
|
{
|
|
DeclSpecs *ds = new DeclSpecs($1);
|
|
ds->vectorSize = (int32_t)$3;
|
|
$$ = ds;
|
|
}
|
|
| type_specifier declaration_specifiers
|
|
{
|
|
DeclSpecs *ds = (DeclSpecs *)$2;
|
|
if (ds != NULL) {
|
|
if (ds->baseType != NULL)
|
|
Error(@1, "Multiple types provided for declaration.");
|
|
ds->baseType = $1;
|
|
}
|
|
$$ = ds;
|
|
}
|
|
| type_qualifier
|
|
{
|
|
$$ = new DeclSpecs(NULL, SC_NONE, $1);
|
|
}
|
|
| type_qualifier declaration_specifiers
|
|
{
|
|
DeclSpecs *ds = (DeclSpecs *)$2;
|
|
if (ds != NULL)
|
|
ds->typeQualifiers |= $1;
|
|
$$ = ds;
|
|
}
|
|
;
|
|
|
|
init_declarator_list
|
|
: init_declarator
|
|
{
|
|
std::vector<Declarator *> *dl = new std::vector<Declarator *>;
|
|
if ($1 != NULL)
|
|
dl->push_back($1);
|
|
$$ = dl;
|
|
}
|
|
| init_declarator_list ',' init_declarator
|
|
{
|
|
std::vector<Declarator *> *dl = (std::vector<Declarator *> *)$1;
|
|
if (dl == NULL) {
|
|
AssertPos(@1, m->errorCount > 0);
|
|
dl = new std::vector<Declarator *>;
|
|
}
|
|
if ($3 != NULL)
|
|
dl->push_back($3);
|
|
$$ = dl;
|
|
}
|
|
;
|
|
|
|
init_declarator
|
|
: declarator
|
|
| declarator '=' initializer
|
|
{
|
|
if ($1 != NULL)
|
|
$1->initExpr = $3;
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
storage_class_specifier
|
|
: TOKEN_TYPEDEF { $$ = SC_TYPEDEF; }
|
|
| TOKEN_EXTERN { $$ = SC_EXTERN; }
|
|
| TOKEN_EXTERN TOKEN_STRING_C_LITERAL { $$ = SC_EXTERN_C; }
|
|
| TOKEN_STATIC { $$ = SC_STATIC; }
|
|
;
|
|
|
|
type_specifier
|
|
: atomic_var_type_specifier { $$ = $1; }
|
|
| poly_quant_type_specifier { $$ = $1; }
|
|
| TOKEN_TYPE_NAME
|
|
{
|
|
const Type *t = m->symbolTable->LookupType(yytext);
|
|
$$ = t;
|
|
}
|
|
| struct_or_union_specifier { $$ = $1; }
|
|
| enum_specifier { $$ = $1; }
|
|
;
|
|
|
|
type_specifier_list
|
|
: type_specifier
|
|
{
|
|
if ($1 == NULL)
|
|
$$ = NULL;
|
|
else {
|
|
std::vector<std::pair<const Type *, SourcePos> > *vec =
|
|
new std::vector<std::pair<const Type *, SourcePos> >;
|
|
vec->push_back(std::make_pair($1, @1));
|
|
$$ = vec;
|
|
}
|
|
}
|
|
| type_specifier_list ',' type_specifier
|
|
{
|
|
$$ = $1;
|
|
if ($1 == NULL)
|
|
Assert(m->errorCount > 0);
|
|
else
|
|
$$->push_back(std::make_pair($3, @3));
|
|
}
|
|
;
|
|
|
|
atomic_var_type_specifier
|
|
: TOKEN_VOID { $$ = AtomicType::Void; }
|
|
| TOKEN_BOOL { $$ = AtomicType::UniformBool->GetAsUnboundVariabilityType(); }
|
|
| TOKEN_INT8 { $$ = AtomicType::UniformInt8->GetAsUnboundVariabilityType(); }
|
|
| TOKEN_INT16 { $$ = AtomicType::UniformInt16->GetAsUnboundVariabilityType(); }
|
|
| TOKEN_INT { $$ = AtomicType::UniformInt32->GetAsUnboundVariabilityType(); }
|
|
| TOKEN_FLOAT { $$ = AtomicType::UniformFloat->GetAsUnboundVariabilityType(); }
|
|
| TOKEN_DOUBLE { $$ = AtomicType::UniformDouble->GetAsUnboundVariabilityType(); }
|
|
| TOKEN_INT64 { $$ = AtomicType::UniformInt64->GetAsUnboundVariabilityType(); }
|
|
;
|
|
|
|
poly_type_specifier
|
|
: TOKEN_FLOATING { $$ = PolyType::UniformFloating->GetAsUnboundVariabilityType(); }
|
|
| TOKEN_INTEGER { $$ = PolyType::UniformInteger->GetAsUnboundVariabilityType(); }
|
|
| TOKEN_NUMBER { $$ = PolyType::UniformNumber->GetAsUnboundVariabilityType(); }
|
|
;
|
|
|
|
poly_quant_type_specifier
|
|
: poly_type_specifier '$' int_constant
|
|
{
|
|
$$ = $1->Quantify($3);
|
|
}
|
|
| poly_type_specifier { $$ = $1; }
|
|
;
|
|
|
|
short_vec_specifier
|
|
: atomic_var_type_specifier '<' int_constant '>'
|
|
{
|
|
$$ = $1 ? new VectorType($1, (int32_t)$3) : NULL;
|
|
}
|
|
;
|
|
|
|
struct_or_union_name
|
|
: TOKEN_IDENTIFIER { $$ = strdup(yytext); }
|
|
| TOKEN_TYPE_NAME { $$ = strdup(yytext); }
|
|
;
|
|
|
|
struct_or_union_and_name
|
|
: struct_or_union struct_or_union_name
|
|
{
|
|
const Type *st = m->symbolTable->LookupType($2);
|
|
if (st == NULL) {
|
|
st = new UndefinedStructType($2, Variability::Unbound, false, @2);
|
|
m->symbolTable->AddType($2, st, @2);
|
|
$$ = st;
|
|
}
|
|
else {
|
|
if (CastType<StructType>(st) == NULL &&
|
|
CastType<UndefinedStructType>(st) == NULL) {
|
|
Error(@2, "Type \"%s\" is not a struct type! (%s)", $2,
|
|
st->GetString().c_str());
|
|
$$ = NULL;
|
|
}
|
|
else
|
|
$$ = st;
|
|
}
|
|
}
|
|
;
|
|
|
|
struct_or_union_specifier
|
|
: struct_or_union_and_name
|
|
| struct_or_union_and_name '{' struct_declaration_list '}'
|
|
{
|
|
if ($3 != NULL) {
|
|
llvm::SmallVector<const Type *, 8> elementTypes;
|
|
llvm::SmallVector<std::string, 8> elementNames;
|
|
llvm::SmallVector<SourcePos, 8> elementPositions;
|
|
GetStructTypesNamesPositions(*$3, &elementTypes, &elementNames,
|
|
&elementPositions);
|
|
const std::string &name = CastType<StructType>($1) ?
|
|
CastType<StructType>($1)->GetStructName() :
|
|
CastType<UndefinedStructType>($1)->GetStructName();
|
|
StructType *st = new StructType(name, elementTypes, elementNames,
|
|
elementPositions, false, Variability::Unbound, @1);
|
|
m->symbolTable->AddType(name.c_str(), st, @1);
|
|
$$ = st;
|
|
}
|
|
else
|
|
$$ = NULL;
|
|
}
|
|
| struct_or_union '{' struct_declaration_list '}'
|
|
{
|
|
if ($3 != NULL) {
|
|
llvm::SmallVector<const Type *, 8> elementTypes;
|
|
llvm::SmallVector<std::string, 8> elementNames;
|
|
llvm::SmallVector<SourcePos, 8> elementPositions;
|
|
GetStructTypesNamesPositions(*$3, &elementTypes, &elementNames,
|
|
&elementPositions);
|
|
$$ = new StructType("", elementTypes, elementNames, elementPositions,
|
|
false, Variability::Unbound, @1);
|
|
}
|
|
else
|
|
$$ = NULL;
|
|
}
|
|
| struct_or_union '{' '}'
|
|
{
|
|
llvm::SmallVector<const Type *, 8> elementTypes;
|
|
llvm::SmallVector<std::string, 8> elementNames;
|
|
llvm::SmallVector<SourcePos, 8> elementPositions;
|
|
$$ = new StructType("", elementTypes, elementNames, elementPositions,
|
|
false, Variability::Unbound, @1);
|
|
}
|
|
| struct_or_union_and_name '{' '}'
|
|
{
|
|
llvm::SmallVector<const Type *, 8> elementTypes;
|
|
llvm::SmallVector<std::string, 8> elementNames;
|
|
llvm::SmallVector<SourcePos, 8> elementPositions;
|
|
const std::string &name = CastType<StructType>($1) ?
|
|
CastType<StructType>($1)->GetStructName() :
|
|
CastType<UndefinedStructType>($1)->GetStructName();
|
|
StructType *st = new StructType(name, elementTypes,
|
|
elementNames, elementPositions,
|
|
false, Variability::Unbound, @1);
|
|
m->symbolTable->AddType(name.c_str(), st, @2);
|
|
$$ = st;
|
|
}
|
|
;
|
|
|
|
struct_or_union
|
|
: TOKEN_STRUCT
|
|
;
|
|
|
|
struct_declaration_list
|
|
: struct_declaration
|
|
{
|
|
std::vector<StructDeclaration *> *sdl = new std::vector<StructDeclaration *>;
|
|
if ($1 != NULL)
|
|
sdl->push_back($1);
|
|
$$ = sdl;
|
|
}
|
|
| struct_declaration_list struct_declaration
|
|
{
|
|
std::vector<StructDeclaration *> *sdl = (std::vector<StructDeclaration *> *)$1;
|
|
if (sdl == NULL) {
|
|
AssertPos(@1, m->errorCount > 0);
|
|
sdl = new std::vector<StructDeclaration *>;
|
|
}
|
|
if ($2 != NULL)
|
|
sdl->push_back($2);
|
|
$$ = sdl;
|
|
}
|
|
;
|
|
|
|
struct_declaration
|
|
: specifier_qualifier_list struct_declarator_list ';'
|
|
{ $$ = ($1 != NULL && $2 != NULL) ? new StructDeclaration($1, $2) : NULL; }
|
|
;
|
|
|
|
specifier_qualifier_list
|
|
: type_specifier specifier_qualifier_list
|
|
| type_specifier
|
|
| short_vec_specifier
|
|
| type_qualifier specifier_qualifier_list
|
|
{
|
|
if ($2 != NULL) {
|
|
if ($1 == TYPEQUAL_UNIFORM) {
|
|
if ($2->IsVoidType()) {
|
|
Error(@1, "\"uniform\" qualifier is illegal with \"void\" type.");
|
|
$$ = NULL;
|
|
}
|
|
else
|
|
$$ = $2->GetAsUniformType();
|
|
}
|
|
else if ($1 == TYPEQUAL_VARYING) {
|
|
if ($2->IsVoidType()) {
|
|
Error(@1, "\"varying\" qualifier is illegal with \"void\" type.");
|
|
$$ = NULL;
|
|
}
|
|
else
|
|
$$ = $2->GetAsVaryingType();
|
|
}
|
|
else if ($1 == TYPEQUAL_CONST)
|
|
$$ = $2->GetAsConstType();
|
|
else if ($1 == TYPEQUAL_SIGNED) {
|
|
if ($2->IsIntType() == false) {
|
|
Error(@1, "Can't apply \"signed\" qualifier to \"%s\" type.",
|
|
$2->ResolveUnboundVariability(Variability::Varying)->GetString().c_str());
|
|
$$ = $2;
|
|
}
|
|
}
|
|
else if ($1 == TYPEQUAL_UNSIGNED) {
|
|
const Type *t = $2->GetAsUnsignedType();
|
|
if (t)
|
|
$$ = t;
|
|
else {
|
|
Error(@1, "Can't apply \"unsigned\" qualifier to \"%s\" type. Ignoring.",
|
|
$2->ResolveUnboundVariability(Variability::Varying)->GetString().c_str());
|
|
$$ = $2;
|
|
}
|
|
}
|
|
else if ($1 == TYPEQUAL_INLINE) {
|
|
Error(@1, "\"inline\" qualifier is illegal outside of "
|
|
"function declarations.");
|
|
$$ = $2;
|
|
}
|
|
else if ($1 == TYPEQUAL_TASK) {
|
|
Error(@1, "\"task\" qualifier is illegal outside of "
|
|
"function declarations.");
|
|
$$ = $2;
|
|
}
|
|
else if ($1 == TYPEQUAL_UNMASKED) {
|
|
Error(@1, "\"unmasked\" qualifier is illegal outside of "
|
|
"function declarations.");
|
|
$$ = $2;
|
|
}
|
|
else if ($1 == TYPEQUAL_EXPORT) {
|
|
Error(@1, "\"export\" qualifier is illegal outside of "
|
|
"function declarations.");
|
|
$$ = $2;
|
|
}
|
|
else
|
|
FATAL("Unhandled type qualifier in parser.");
|
|
}
|
|
else {
|
|
if (m->errorCount == 0)
|
|
Error(@1, "Lost type qualifier in parser.");
|
|
$$ = NULL;
|
|
}
|
|
}
|
|
;
|
|
|
|
|
|
struct_declarator_list
|
|
: struct_declarator
|
|
{
|
|
std::vector<Declarator *> *sdl = new std::vector<Declarator *>;
|
|
if ($1 != NULL)
|
|
sdl->push_back($1);
|
|
$$ = sdl;
|
|
}
|
|
| struct_declarator_list ',' struct_declarator
|
|
{
|
|
std::vector<Declarator *> *sdl = (std::vector<Declarator *> *)$1;
|
|
if (sdl == NULL) {
|
|
AssertPos(@1, m->errorCount > 0);
|
|
sdl = new std::vector<Declarator *>;
|
|
}
|
|
if ($3 != NULL)
|
|
sdl->push_back($3);
|
|
$$ = sdl;
|
|
}
|
|
;
|
|
|
|
struct_declarator
|
|
: declarator { $$ = $1; }
|
|
/* bitfields
|
|
| ':' constant_expression
|
|
| declarator ':' constant_expression
|
|
*/
|
|
;
|
|
|
|
enum_identifier
|
|
: TOKEN_IDENTIFIER { $$ = strdup(yytext); }
|
|
|
|
enum_specifier
|
|
: TOKEN_ENUM '{' enumerator_list '}'
|
|
{
|
|
$$ = lCreateEnumType(NULL, $3, @1);
|
|
}
|
|
| TOKEN_ENUM enum_identifier '{' enumerator_list '}'
|
|
{
|
|
$$ = lCreateEnumType($2, $4, @2);
|
|
}
|
|
| TOKEN_ENUM '{' enumerator_list ',' '}'
|
|
{
|
|
$$ = lCreateEnumType(NULL, $3, @1);
|
|
}
|
|
| TOKEN_ENUM enum_identifier '{' enumerator_list ',' '}'
|
|
{
|
|
$$ = lCreateEnumType($2, $4, @2);
|
|
}
|
|
| TOKEN_ENUM enum_identifier
|
|
{
|
|
const Type *type = m->symbolTable->LookupType($2);
|
|
if (type == NULL) {
|
|
std::vector<std::string> alternates = m->symbolTable->ClosestEnumTypeMatch($2);
|
|
std::string alts = lGetAlternates(alternates);
|
|
Error(@2, "Enum type \"%s\" unknown.%s", $2, alts.c_str());
|
|
$$ = NULL;
|
|
}
|
|
else {
|
|
const EnumType *enumType = CastType<EnumType>(type);
|
|
if (enumType == NULL) {
|
|
Error(@2, "Type \"%s\" is not an enum type (%s).", $2,
|
|
type->GetString().c_str());
|
|
$$ = NULL;
|
|
}
|
|
else
|
|
$$ = enumType;
|
|
}
|
|
}
|
|
;
|
|
|
|
enumerator_list
|
|
: enumerator
|
|
{
|
|
if ($1 == NULL)
|
|
$$ = NULL;
|
|
else {
|
|
std::vector<Symbol *> *el = new std::vector<Symbol *>;
|
|
el->push_back($1);
|
|
$$ = el;
|
|
}
|
|
}
|
|
| enumerator_list ',' enumerator
|
|
{
|
|
std::vector<Symbol *> *symList = $1;
|
|
if (symList == NULL) {
|
|
AssertPos(@1, m->errorCount > 0);
|
|
symList = new std::vector<Symbol *>;
|
|
}
|
|
if ($3 != NULL)
|
|
symList->push_back($3);
|
|
$$ = symList;
|
|
}
|
|
;
|
|
|
|
enumerator
|
|
: enum_identifier
|
|
{
|
|
$$ = new Symbol($1, @1);
|
|
}
|
|
| enum_identifier '=' constant_expression
|
|
{
|
|
int value;
|
|
if ($1 != NULL && $3 != NULL &&
|
|
lGetConstantInt($3, &value, @3, "Enumerator value")) {
|
|
Symbol *sym = new Symbol($1, @1);
|
|
sym->constValue = new ConstExpr(AtomicType::UniformUInt32->GetAsConstType(),
|
|
(uint32_t)value, @3);
|
|
$$ = sym;
|
|
}
|
|
else
|
|
$$ = NULL;
|
|
}
|
|
;
|
|
|
|
type_qualifier
|
|
: TOKEN_CONST { $$ = TYPEQUAL_CONST; }
|
|
| TOKEN_UNIFORM { $$ = TYPEQUAL_UNIFORM; }
|
|
| TOKEN_VARYING { $$ = TYPEQUAL_VARYING; }
|
|
| TOKEN_TASK { $$ = TYPEQUAL_TASK; }
|
|
| TOKEN_UNMASKED { $$ = TYPEQUAL_UNMASKED; }
|
|
| TOKEN_EXPORT { $$ = TYPEQUAL_EXPORT; }
|
|
| TOKEN_INLINE { $$ = TYPEQUAL_INLINE; }
|
|
| TOKEN_SIGNED { $$ = TYPEQUAL_SIGNED; }
|
|
| TOKEN_UNSIGNED { $$ = TYPEQUAL_UNSIGNED; }
|
|
;
|
|
|
|
type_qualifier_list
|
|
: type_qualifier
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| type_qualifier_list type_qualifier
|
|
{
|
|
$$ = $1 | $2;
|
|
}
|
|
;
|
|
|
|
declarator
|
|
: pointer direct_declarator
|
|
{
|
|
if ($1 != NULL) {
|
|
Declarator *tail = $1;
|
|
while (tail->child != NULL)
|
|
tail = tail->child;
|
|
tail->child = $2;
|
|
$$ = $1;
|
|
}
|
|
else
|
|
$$ = NULL;
|
|
}
|
|
| reference direct_declarator
|
|
{
|
|
if ($1 != NULL) {
|
|
Declarator *tail = $1;
|
|
while (tail->child != NULL)
|
|
tail = tail->child;
|
|
tail->child = $2;
|
|
$$ = $1;
|
|
}
|
|
else
|
|
$$ = NULL;
|
|
}
|
|
| direct_declarator
|
|
;
|
|
|
|
int_constant
|
|
: TOKEN_INT8_CONSTANT { $$ = yylval.intVal; }
|
|
| TOKEN_INT16_CONSTANT { $$ = yylval.intVal; }
|
|
| TOKEN_INT32_CONSTANT { $$ = yylval.intVal; }
|
|
| TOKEN_INT64_CONSTANT { $$ = yylval.intVal; }
|
|
;
|
|
|
|
direct_declarator
|
|
: TOKEN_IDENTIFIER
|
|
{
|
|
Declarator *d = new Declarator(DK_BASE, @1);
|
|
d->name = yytext;
|
|
$$ = d;
|
|
}
|
|
| '(' declarator ')'
|
|
{
|
|
$$ = $2;
|
|
}
|
|
| direct_declarator '[' constant_expression ']'
|
|
{
|
|
int size;
|
|
if ($1 != NULL && lGetConstantInt($3, &size, @3, "Array dimension")) {
|
|
if (size < 0) {
|
|
Error(@3, "Array dimension must be non-negative.");
|
|
$$ = NULL;
|
|
}
|
|
else {
|
|
Declarator *d = new Declarator(DK_ARRAY, Union(@1, @4));
|
|
d->arraySize = size;
|
|
d->child = $1;
|
|
$$ = d;
|
|
}
|
|
}
|
|
else
|
|
$$ = NULL;
|
|
}
|
|
| direct_declarator '[' ']'
|
|
{
|
|
if ($1 != NULL) {
|
|
Declarator *d = new Declarator(DK_ARRAY, Union(@1, @3));
|
|
d->arraySize = 0; // unsize
|
|
d->child = $1;
|
|
$$ = d;
|
|
}
|
|
else
|
|
$$ = NULL;
|
|
}
|
|
| direct_declarator '[' error ']'
|
|
{
|
|
$$ = NULL;
|
|
}
|
|
| direct_declarator '(' parameter_type_list ')'
|
|
{
|
|
if ($1 != NULL) {
|
|
Declarator *d = new Declarator(DK_FUNCTION, Union(@1, @4));
|
|
d->child = $1;
|
|
if ($3 != NULL)
|
|
d->functionParams = *$3;
|
|
$$ = d;
|
|
}
|
|
else
|
|
$$ = NULL;
|
|
}
|
|
| direct_declarator '(' ')'
|
|
{
|
|
if ($1 != NULL) {
|
|
Declarator *d = new Declarator(DK_FUNCTION, Union(@1, @3));
|
|
d->child = $1;
|
|
$$ = d;
|
|
}
|
|
else
|
|
$$ = NULL;
|
|
}
|
|
| direct_declarator '(' error ')'
|
|
{
|
|
$$ = NULL;
|
|
}
|
|
;
|
|
|
|
|
|
pointer
|
|
: '*'
|
|
{
|
|
$$ = new Declarator(DK_POINTER, @1);
|
|
}
|
|
| '*' type_qualifier_list
|
|
{
|
|
Declarator *d = new Declarator(DK_POINTER, Union(@1, @2));
|
|
d->typeQualifiers = $2;
|
|
$$ = d;
|
|
}
|
|
| '*' pointer
|
|
{
|
|
Declarator *d = new Declarator(DK_POINTER, Union(@1, @2));
|
|
d->child = $2;
|
|
$$ = d;
|
|
}
|
|
| '*' type_qualifier_list pointer
|
|
{
|
|
Declarator *d = new Declarator(DK_POINTER, Union(@1, @3));
|
|
d->typeQualifiers = $2;
|
|
d->child = $3;
|
|
$$ = d;
|
|
}
|
|
;
|
|
|
|
|
|
reference
|
|
: '&'
|
|
{
|
|
$$ = new Declarator(DK_REFERENCE, @1);
|
|
}
|
|
;
|
|
|
|
|
|
parameter_type_list
|
|
: parameter_list { $$ = $1; }
|
|
;
|
|
|
|
parameter_list
|
|
: parameter_declaration
|
|
{
|
|
std::vector<Declaration *> *dl = new std::vector<Declaration *>;
|
|
if ($1 != NULL)
|
|
dl->push_back($1);
|
|
$$ = dl;
|
|
}
|
|
| parameter_list ',' parameter_declaration
|
|
{
|
|
std::vector<Declaration *> *dl = (std::vector<Declaration *> *)$1;
|
|
if (dl == NULL)
|
|
dl = new std::vector<Declaration *>;
|
|
if ($3 != NULL)
|
|
dl->push_back($3);
|
|
$$ = dl;
|
|
}
|
|
| error ','
|
|
{
|
|
lSuggestParamListAlternates();
|
|
$$ = NULL;
|
|
}
|
|
;
|
|
|
|
parameter_declaration
|
|
: declaration_specifiers declarator
|
|
{
|
|
$$ = new Declaration($1, $2);
|
|
}
|
|
| declaration_specifiers declarator '=' initializer
|
|
{
|
|
if ($1 != NULL && $2 != NULL) {
|
|
$2->initExpr = $4;
|
|
$$ = new Declaration($1, $2);
|
|
}
|
|
else
|
|
$$ = NULL;
|
|
}
|
|
| declaration_specifiers abstract_declarator
|
|
{
|
|
if ($1 != NULL && $2 != NULL)
|
|
$$ = new Declaration($1, $2);
|
|
else
|
|
$$ = NULL;
|
|
}
|
|
| declaration_specifiers
|
|
{
|
|
if ($1 == NULL)
|
|
$$ = NULL;
|
|
else
|
|
$$ = new Declaration($1);
|
|
}
|
|
;
|
|
|
|
/* K&R?
|
|
identifier_list
|
|
: IDENTIFIER
|
|
| identifier_list ',' IDENTIFIER
|
|
;
|
|
*/
|
|
|
|
type_name
|
|
: specifier_qualifier_list
|
|
| specifier_qualifier_list abstract_declarator
|
|
{
|
|
if ($1 == NULL || $2 == NULL)
|
|
$$ = NULL;
|
|
else {
|
|
$2->InitFromType($1, NULL);
|
|
$$ = $2->type;
|
|
}
|
|
}
|
|
;
|
|
|
|
abstract_declarator
|
|
: pointer
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| direct_abstract_declarator
|
|
| pointer direct_abstract_declarator
|
|
{
|
|
if ($2 == NULL)
|
|
$$ = NULL;
|
|
else {
|
|
Declarator *d = new Declarator(DK_POINTER, Union(@1, @2));
|
|
d->child = $2;
|
|
$$ = d;
|
|
}
|
|
}
|
|
| reference
|
|
{
|
|
$$ = new Declarator(DK_REFERENCE, @1);
|
|
}
|
|
| reference direct_abstract_declarator
|
|
{
|
|
if ($2 == NULL)
|
|
$$ = NULL;
|
|
else {
|
|
Declarator *d = new Declarator(DK_REFERENCE, Union(@1, @2));
|
|
d->child = $2;
|
|
$$ = d;
|
|
}
|
|
}
|
|
;
|
|
|
|
direct_abstract_declarator
|
|
: '(' abstract_declarator ')'
|
|
{ $$ = $2; }
|
|
| '[' ']'
|
|
{
|
|
Declarator *d = new Declarator(DK_ARRAY, Union(@1, @2));
|
|
d->arraySize = 0;
|
|
$$ = d;
|
|
}
|
|
| '[' constant_expression ']'
|
|
{
|
|
int size;
|
|
if ($2 != NULL && lGetConstantInt($2, &size, @2, "Array dimension")) {
|
|
if (size < 0) {
|
|
Error(@2, "Array dimension must be non-negative.");
|
|
$$ = NULL;
|
|
}
|
|
else {
|
|
Declarator *d = new Declarator(DK_ARRAY, Union(@1, @3));
|
|
d->arraySize = size;
|
|
$$ = d;
|
|
}
|
|
}
|
|
else
|
|
$$ = NULL;
|
|
}
|
|
| direct_abstract_declarator '[' ']'
|
|
{
|
|
if ($1 == NULL)
|
|
$$ = NULL;
|
|
else {
|
|
Declarator *d = new Declarator(DK_ARRAY, Union(@1, @3));
|
|
d->arraySize = 0;
|
|
d->child = $1;
|
|
$$ = d;
|
|
}
|
|
}
|
|
| direct_abstract_declarator '[' constant_expression ']'
|
|
{
|
|
int size;
|
|
if ($1 != NULL && $3 != NULL && lGetConstantInt($3, &size, @3, "Array dimension")) {
|
|
if (size < 0) {
|
|
Error(@3, "Array dimension must be non-negative.");
|
|
$$ = NULL;
|
|
}
|
|
else {
|
|
Declarator *d = new Declarator(DK_ARRAY, Union(@1, @4));
|
|
d->arraySize = size;
|
|
d->child = $1;
|
|
$$ = d;
|
|
}
|
|
}
|
|
else
|
|
$$ = NULL;
|
|
}
|
|
| '(' ')'
|
|
{ $$ = new Declarator(DK_FUNCTION, Union(@1, @2)); }
|
|
| '(' parameter_type_list ')'
|
|
{
|
|
Declarator *d = new Declarator(DK_FUNCTION, Union(@1, @3));
|
|
if ($2 != NULL) d->functionParams = *$2;
|
|
$$ = d;
|
|
}
|
|
| direct_abstract_declarator '(' ')'
|
|
{
|
|
if ($1 == NULL)
|
|
$$ = NULL;
|
|
else {
|
|
Declarator *d = new Declarator(DK_FUNCTION, Union(@1, @3));
|
|
d->child = $1;
|
|
$$ = d;
|
|
}
|
|
}
|
|
| direct_abstract_declarator '(' parameter_type_list ')'
|
|
{
|
|
if ($1 == NULL)
|
|
$$ = NULL;
|
|
else {
|
|
Declarator *d = new Declarator(DK_FUNCTION, Union(@1, @4));
|
|
d->child = $1;
|
|
if ($3 != NULL) d->functionParams = *$3;
|
|
$$ = d;
|
|
}
|
|
}
|
|
;
|
|
|
|
initializer
|
|
: assignment_expression
|
|
| '{' initializer_list '}' { $$ = $2; }
|
|
| '{' initializer_list ',' '}' { $$ = $2; }
|
|
;
|
|
|
|
initializer_list
|
|
: initializer
|
|
{ $$ = new ExprList($1, @1); }
|
|
| initializer_list ',' initializer
|
|
{
|
|
ExprList *exprList = $1;
|
|
if (exprList == NULL) {
|
|
AssertPos(@1, m->errorCount > 0);
|
|
exprList = new ExprList(@3);
|
|
}
|
|
exprList->exprs.push_back($3);
|
|
exprList->pos = Union(exprList->pos, @3);
|
|
$$ = exprList;
|
|
}
|
|
;
|
|
|
|
statement
|
|
: labeled_statement
|
|
| compound_statement
|
|
| expression_statement
|
|
| selection_statement
|
|
| iteration_statement
|
|
| jump_statement
|
|
| declaration_statement
|
|
| print_statement
|
|
| assert_statement
|
|
| sync_statement
|
|
| delete_statement
|
|
| unmasked_statement
|
|
| error ';'
|
|
{
|
|
lSuggestBuiltinAlternates();
|
|
$$ = NULL;
|
|
}
|
|
;
|
|
|
|
labeled_statement
|
|
: goto_identifier ':' statement
|
|
{
|
|
$$ = new LabeledStmt($1, $3, @1);
|
|
}
|
|
| TOKEN_CASE constant_expression ':' statement
|
|
{
|
|
int value;
|
|
if ($2 != NULL &&
|
|
lGetConstantInt($2, &value, @2, "Case statement value")) {
|
|
$$ = new CaseStmt(value, $4, Union(@1, @2));
|
|
}
|
|
else
|
|
$$ = NULL;
|
|
}
|
|
| TOKEN_DEFAULT ':' statement
|
|
{ $$ = new DefaultStmt($3, @1); }
|
|
;
|
|
|
|
start_scope
|
|
: '{' { m->symbolTable->PushScope(); }
|
|
;
|
|
|
|
end_scope
|
|
: '}' { m->symbolTable->PopScope(); }
|
|
;
|
|
|
|
compound_statement
|
|
: '{' '}' { $$ = NULL; }
|
|
| start_scope statement_list end_scope { $$ = $2; }
|
|
;
|
|
|
|
statement_list
|
|
: statement
|
|
{
|
|
StmtList *sl = new StmtList(@1);
|
|
sl->Add($1);
|
|
$$ = sl;
|
|
}
|
|
| statement_list statement
|
|
{
|
|
StmtList *sl = (StmtList *)$1;
|
|
if (sl == NULL) {
|
|
AssertPos(@1, m->errorCount > 0);
|
|
sl = new StmtList(@2);
|
|
}
|
|
sl->Add($2);
|
|
$$ = sl;
|
|
}
|
|
;
|
|
|
|
expression_statement
|
|
: ';' { $$ = NULL; }
|
|
| expression ';' { $$ = $1 ? new ExprStmt($1, @1) : NULL; }
|
|
;
|
|
|
|
selection_statement
|
|
: TOKEN_IF '(' expression ')' statement
|
|
{ $$ = new IfStmt($3, $5, NULL, false, @1); }
|
|
| TOKEN_IF '(' expression ')' statement TOKEN_ELSE statement
|
|
{ $$ = new IfStmt($3, $5, $7, false, @1); }
|
|
| TOKEN_CIF '(' expression ')' statement
|
|
{ $$ = new IfStmt($3, $5, NULL, true, @1); }
|
|
| TOKEN_CIF '(' expression ')' statement TOKEN_ELSE statement
|
|
{ $$ = new IfStmt($3, $5, $7, true, @1); }
|
|
| TOKEN_SWITCH '(' expression ')' statement
|
|
{ $$ = new SwitchStmt($3, $5, @1); }
|
|
;
|
|
|
|
for_test
|
|
: ';'
|
|
{ $$ = NULL; }
|
|
| expression ';'
|
|
{ $$ = $1; }
|
|
;
|
|
|
|
for_init_statement
|
|
: expression_statement
|
|
| declaration_statement
|
|
;
|
|
|
|
for_scope
|
|
: TOKEN_FOR { m->symbolTable->PushScope(); }
|
|
;
|
|
|
|
cfor_scope
|
|
: TOKEN_CFOR { m->symbolTable->PushScope(); }
|
|
;
|
|
|
|
foreach_scope
|
|
: TOKEN_FOREACH { m->symbolTable->PushScope(); }
|
|
;
|
|
|
|
foreach_tiled_scope
|
|
: TOKEN_FOREACH_TILED { m->symbolTable->PushScope(); }
|
|
;
|
|
|
|
foreach_identifier
|
|
: TOKEN_IDENTIFIER
|
|
{
|
|
$$ = new Symbol(yytext, @1, AtomicType::VaryingInt32->GetAsConstType());
|
|
}
|
|
;
|
|
|
|
foreach_active_scope
|
|
: TOKEN_FOREACH_ACTIVE { m->symbolTable->PushScope(); }
|
|
;
|
|
|
|
foreach_active_identifier
|
|
: TOKEN_IDENTIFIER
|
|
{
|
|
$$ = new Symbol(yytext, @1, AtomicType::UniformInt64->GetAsConstType());
|
|
}
|
|
;
|
|
|
|
integer_dotdotdot
|
|
: TOKEN_INT32DOTDOTDOT_CONSTANT {
|
|
$$ = new ConstExpr(AtomicType::UniformInt32->GetAsConstType(),
|
|
(int32_t)yylval.intVal, @1);
|
|
}
|
|
| TOKEN_UINT32DOTDOTDOT_CONSTANT {
|
|
$$ = new ConstExpr(AtomicType::UniformUInt32->GetAsConstType(),
|
|
(uint32_t)yylval.intVal, @1);
|
|
}
|
|
| TOKEN_INT64DOTDOTDOT_CONSTANT {
|
|
$$ = new ConstExpr(AtomicType::UniformInt64->GetAsConstType(),
|
|
(int64_t)yylval.intVal, @1);
|
|
}
|
|
| TOKEN_UINT64DOTDOTDOT_CONSTANT {
|
|
$$ = new ConstExpr(AtomicType::UniformUInt64->GetAsConstType(),
|
|
(uint64_t)yylval.intVal, @1);
|
|
}
|
|
;
|
|
|
|
foreach_dimension_specifier
|
|
: foreach_identifier '=' assignment_expression TOKEN_DOTDOTDOT assignment_expression
|
|
{
|
|
$$ = new ForeachDimension($1, $3, $5);
|
|
}
|
|
| foreach_identifier '=' integer_dotdotdot assignment_expression
|
|
{
|
|
$$ = new ForeachDimension($1, $3, $4);
|
|
}
|
|
;
|
|
|
|
foreach_dimension_list
|
|
: foreach_dimension_specifier
|
|
{
|
|
$$ = new std::vector<ForeachDimension *>;
|
|
$$->push_back($1);
|
|
}
|
|
| foreach_dimension_list ',' foreach_dimension_specifier
|
|
{
|
|
std::vector<ForeachDimension *> *dv = $1;
|
|
if (dv == NULL) {
|
|
AssertPos(@1, m->errorCount > 0);
|
|
dv = new std::vector<ForeachDimension *>;
|
|
}
|
|
if ($3 != NULL)
|
|
dv->push_back($3);
|
|
$$ = dv;
|
|
}
|
|
;
|
|
|
|
foreach_unique_scope
|
|
: TOKEN_FOREACH_UNIQUE { m->symbolTable->PushScope(); }
|
|
;
|
|
|
|
foreach_unique_identifier
|
|
: TOKEN_IDENTIFIER { $$ = yylval.stringVal->c_str(); }
|
|
;
|
|
|
|
iteration_statement
|
|
: TOKEN_WHILE '(' expression ')' statement
|
|
{ $$ = new ForStmt(NULL, $3, NULL, $5, false, @1); }
|
|
| TOKEN_CWHILE '(' expression ')' statement
|
|
{ $$ = new ForStmt(NULL, $3, NULL, $5, true, @1); }
|
|
| TOKEN_DO statement TOKEN_WHILE '(' expression ')' ';'
|
|
{ $$ = new DoStmt($5, $2, false, @1); }
|
|
| TOKEN_CDO statement TOKEN_WHILE '(' expression ')' ';'
|
|
{ $$ = new DoStmt($5, $2, true, @1); }
|
|
| for_scope '(' for_init_statement for_test ')' statement
|
|
{ $$ = new ForStmt($3, $4, NULL, $6, false, @1);
|
|
m->symbolTable->PopScope();
|
|
}
|
|
| for_scope '(' for_init_statement for_test expression ')' statement
|
|
{ $$ = new ForStmt($3, $4, new ExprStmt($5, @5), $7, false, @1);
|
|
m->symbolTable->PopScope();
|
|
}
|
|
| cfor_scope '(' for_init_statement for_test ')' statement
|
|
{ $$ = new ForStmt($3, $4, NULL, $6, true, @1);
|
|
m->symbolTable->PopScope();
|
|
}
|
|
| cfor_scope '(' for_init_statement for_test expression ')' statement
|
|
{ $$ = new ForStmt($3, $4, new ExprStmt($5, @5), $7, true, @1);
|
|
m->symbolTable->PopScope();
|
|
}
|
|
| foreach_scope '(' foreach_dimension_list ')'
|
|
{
|
|
std::vector<ForeachDimension *> *dims = $3;
|
|
if (dims == NULL) {
|
|
AssertPos(@3, m->errorCount > 0);
|
|
dims = new std::vector<ForeachDimension *>;
|
|
}
|
|
for (unsigned int i = 0; i < dims->size(); ++i)
|
|
m->symbolTable->AddVariable((*dims)[i]->sym);
|
|
}
|
|
statement
|
|
{
|
|
std::vector<ForeachDimension *> *dims = $3;
|
|
if (dims == NULL) {
|
|
AssertPos(@3, m->errorCount > 0);
|
|
dims = new std::vector<ForeachDimension *>;
|
|
}
|
|
|
|
std::vector<Symbol *> syms;
|
|
std::vector<Expr *> begins, ends;
|
|
for (unsigned int i = 0; i < dims->size(); ++i) {
|
|
syms.push_back((*dims)[i]->sym);
|
|
begins.push_back((*dims)[i]->beginExpr);
|
|
ends.push_back((*dims)[i]->endExpr);
|
|
}
|
|
$$ = new ForeachStmt(syms, begins, ends, $6, false, @1);
|
|
m->symbolTable->PopScope();
|
|
}
|
|
| foreach_tiled_scope '(' foreach_dimension_list ')'
|
|
{
|
|
std::vector<ForeachDimension *> *dims = $3;
|
|
if (dims == NULL) {
|
|
AssertPos(@3, m->errorCount > 0);
|
|
dims = new std::vector<ForeachDimension *>;
|
|
}
|
|
|
|
for (unsigned int i = 0; i < dims->size(); ++i)
|
|
m->symbolTable->AddVariable((*dims)[i]->sym);
|
|
}
|
|
statement
|
|
{
|
|
std::vector<ForeachDimension *> *dims = $3;
|
|
if (dims == NULL) {
|
|
AssertPos(@1, m->errorCount > 0);
|
|
dims = new std::vector<ForeachDimension *>;
|
|
}
|
|
|
|
std::vector<Symbol *> syms;
|
|
std::vector<Expr *> begins, ends;
|
|
for (unsigned int i = 0; i < dims->size(); ++i) {
|
|
syms.push_back((*dims)[i]->sym);
|
|
begins.push_back((*dims)[i]->beginExpr);
|
|
ends.push_back((*dims)[i]->endExpr);
|
|
}
|
|
$$ = new ForeachStmt(syms, begins, ends, $6, true, @1);
|
|
m->symbolTable->PopScope();
|
|
}
|
|
| foreach_active_scope '(' foreach_active_identifier ')'
|
|
{
|
|
if ($3 != NULL)
|
|
m->symbolTable->AddVariable($3);
|
|
}
|
|
statement
|
|
{
|
|
$$ = new ForeachActiveStmt($3, $6, Union(@1, @4));
|
|
m->symbolTable->PopScope();
|
|
}
|
|
| foreach_unique_scope '(' foreach_unique_identifier TOKEN_IN
|
|
expression ')'
|
|
{
|
|
Expr *expr = $5;
|
|
const Type *type;
|
|
if (expr != NULL &&
|
|
(expr = TypeCheck(expr)) != NULL &&
|
|
(type = expr->GetType()) != NULL) {
|
|
const Type *iterType = type->GetAsUniformType()->GetAsConstType();
|
|
Symbol *sym = new Symbol($3, @3, iterType);
|
|
m->symbolTable->AddVariable(sym);
|
|
}
|
|
}
|
|
statement
|
|
{
|
|
$$ = new ForeachUniqueStmt($3, $5, $8, @1);
|
|
m->symbolTable->PopScope();
|
|
}
|
|
;
|
|
|
|
goto_identifier
|
|
: TOKEN_IDENTIFIER { $$ = yylval.stringVal->c_str(); }
|
|
;
|
|
|
|
jump_statement
|
|
: TOKEN_GOTO goto_identifier ';'
|
|
{ $$ = new GotoStmt($2, @1, @2); }
|
|
| TOKEN_CONTINUE ';'
|
|
{ $$ = new ContinueStmt(@1); }
|
|
| TOKEN_BREAK ';'
|
|
{ $$ = new BreakStmt(@1); }
|
|
| TOKEN_RETURN ';'
|
|
{ $$ = new ReturnStmt(NULL, @1); }
|
|
| TOKEN_RETURN expression ';'
|
|
{ $$ = new ReturnStmt($2, @1); }
|
|
;
|
|
|
|
sync_statement
|
|
: TOKEN_SYNC ';'
|
|
{ $$ = new ExprStmt(new SyncExpr(@1), @1); }
|
|
;
|
|
|
|
delete_statement
|
|
: TOKEN_DELETE expression ';'
|
|
{
|
|
$$ = new DeleteStmt($2, Union(@1, @2));
|
|
}
|
|
;
|
|
|
|
unmasked_statement
|
|
: TOKEN_UNMASKED '{' statement_list '}'
|
|
{
|
|
$$ = new UnmaskedStmt($3, @1);
|
|
}
|
|
;
|
|
|
|
print_statement
|
|
: TOKEN_PRINT '(' string_constant ')' ';'
|
|
{
|
|
$$ = new PrintStmt(*$3, NULL, @1);
|
|
}
|
|
| TOKEN_PRINT '(' string_constant ',' argument_expression_list ')' ';'
|
|
{
|
|
$$ = new PrintStmt(*$3, $5, @1);
|
|
}
|
|
;
|
|
|
|
assert_statement
|
|
: TOKEN_ASSERT '(' string_constant ',' expression ')' ';'
|
|
{
|
|
$$ = new AssertStmt(*$3, $5, @1);
|
|
}
|
|
;
|
|
|
|
translation_unit
|
|
: external_declaration
|
|
| translation_unit external_declaration
|
|
| error ';'
|
|
;
|
|
|
|
external_declaration
|
|
: function_definition
|
|
| TOKEN_EXTERN TOKEN_STRING_C_LITERAL '{' declaration '}'
|
|
| TOKEN_EXPORT '{' type_specifier_list '}' ';'
|
|
{
|
|
if ($3 != NULL)
|
|
m->AddExportedTypes(*$3);
|
|
}
|
|
| declaration
|
|
{
|
|
if ($1 != NULL)
|
|
for (unsigned int i = 0; i < $1->declarators.size(); ++i)
|
|
lAddDeclaration($1->declSpecs, $1->declarators[i]);
|
|
}
|
|
| ';'
|
|
;
|
|
|
|
function_definition
|
|
: declaration_specifiers declarator
|
|
{
|
|
lAddDeclaration($1, $2);
|
|
lAddFunctionParams($2);
|
|
lAddMaskToSymbolTable(@2);
|
|
if ($1->typeQualifiers & TYPEQUAL_TASK)
|
|
lAddThreadIndexCountToSymbolTable(@2);
|
|
}
|
|
compound_statement
|
|
{
|
|
if ($2 != NULL) {
|
|
$2->InitFromDeclSpecs($1);
|
|
const FunctionType *funcType = CastType<FunctionType>($2->type);
|
|
if (funcType == NULL)
|
|
AssertPos(@1, m->errorCount > 0);
|
|
else if ($1->storageClass == SC_TYPEDEF)
|
|
Error(@1, "Illegal \"typedef\" provided with function definition.");
|
|
else {
|
|
Stmt *code = $4;
|
|
if (code == NULL) code = new StmtList(@4);
|
|
m->AddFunctionDefinition($2->name, funcType, code);
|
|
}
|
|
}
|
|
m->symbolTable->PopScope(); // push in lAddFunctionParams();
|
|
}
|
|
/* function with no declared return type??
|
|
func(...)
|
|
| declarator { lAddFunctionParams($1); } compound_statement
|
|
{
|
|
m->AddFunction(new DeclSpecs(XXX, $1, $3);
|
|
m->symbolTable->PopScope(); // push in lAddFunctionParams();
|
|
}
|
|
*/
|
|
;
|
|
|
|
%%
|
|
|
|
|
|
void yyerror(const char *s) {
|
|
if (strlen(yytext) == 0)
|
|
Error(yylloc, "Premature end of file: %s.", s);
|
|
else
|
|
Error(yylloc, "%s.", s);
|
|
}
|
|
|
|
|
|
static int
|
|
lYYTNameErr (char *yyres, const char *yystr)
|
|
{
|
|
extern std::map<std::string, std::string> tokenNameRemap;
|
|
Assert(tokenNameRemap.size() > 0);
|
|
if (tokenNameRemap.find(yystr) != tokenNameRemap.end()) {
|
|
std::string n = tokenNameRemap[yystr];
|
|
if (yyres == NULL)
|
|
return n.size();
|
|
else
|
|
return yystpcpy(yyres, n.c_str()) - yyres;
|
|
}
|
|
|
|
if (*yystr == '"')
|
|
{
|
|
YYSIZE_T yyn = 0;
|
|
char const *yyp = yystr;
|
|
|
|
for (;;)
|
|
switch (*++yyp)
|
|
{
|
|
case '\'':
|
|
case ',':
|
|
goto do_not_strip_quotes;
|
|
|
|
case '\\':
|
|
if (*++yyp != '\\')
|
|
goto do_not_strip_quotes;
|
|
/* Fall through. */
|
|
default:
|
|
if (yyres)
|
|
yyres[yyn] = *yyp;
|
|
yyn++;
|
|
break;
|
|
|
|
case '"':
|
|
if (yyres)
|
|
yyres[yyn] = '\0';
|
|
return yyn;
|
|
}
|
|
do_not_strip_quotes: ;
|
|
}
|
|
|
|
if (! yyres)
|
|
return yystrlen (yystr);
|
|
|
|
return yystpcpy (yyres, yystr) - yyres;
|
|
}
|
|
|
|
static void
|
|
lSuggestBuiltinAlternates() {
|
|
std::vector<std::string> builtinTokens;
|
|
const char **token = lBuiltinTokens;
|
|
while (*token) {
|
|
builtinTokens.push_back(*token);
|
|
++token;
|
|
}
|
|
std::vector<std::string> alternates = MatchStrings(yytext, builtinTokens);
|
|
std::string alts = lGetAlternates(alternates);
|
|
if (alts.size() > 0)
|
|
Error(yylloc, "%s", alts.c_str());
|
|
}
|
|
|
|
|
|
static void
|
|
lSuggestParamListAlternates() {
|
|
std::vector<std::string> builtinTokens;
|
|
const char **token = lParamListTokens;
|
|
while (*token) {
|
|
builtinTokens.push_back(*token);
|
|
++token;
|
|
}
|
|
std::vector<std::string> alternates = MatchStrings(yytext, builtinTokens);
|
|
std::string alts = lGetAlternates(alternates);
|
|
if (alts.size() > 0)
|
|
Error(yylloc, "%s", alts.c_str());
|
|
}
|
|
|
|
|
|
static void
|
|
lAddDeclaration(DeclSpecs *ds, Declarator *decl) {
|
|
if (ds == NULL || decl == NULL)
|
|
// Error happened earlier during parsing
|
|
return;
|
|
|
|
decl->InitFromDeclSpecs(ds);
|
|
if (ds->storageClass == SC_TYPEDEF)
|
|
m->AddTypeDef(decl->name, decl->type, decl->pos);
|
|
else {
|
|
if (decl->type == NULL) {
|
|
Assert(m->errorCount > 0);
|
|
return;
|
|
}
|
|
|
|
decl->type = decl->type->ResolveUnboundVariability(Variability::Varying);
|
|
|
|
const FunctionType *ft = CastType<FunctionType>(decl->type);
|
|
if (ft != NULL) {
|
|
bool isInline = (ds->typeQualifiers & TYPEQUAL_INLINE);
|
|
m->AddFunctionDeclaration(decl->name, ft, ds->storageClass,
|
|
isInline, decl->pos);
|
|
}
|
|
else {
|
|
bool isConst = (ds->typeQualifiers & TYPEQUAL_CONST) != 0;
|
|
m->AddGlobalVariable(decl->name, decl->type, decl->initExpr,
|
|
isConst, decl->storageClass, decl->pos);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/** We're about to start parsing the body of a function; add all of the
|
|
parameters to the symbol table so that they're available.
|
|
*/
|
|
static void
|
|
lAddFunctionParams(Declarator *decl) {
|
|
m->symbolTable->PushScope();
|
|
|
|
if (decl == NULL) {
|
|
AssertPos(decl->pos, m->errorCount > 0);
|
|
return;
|
|
}
|
|
|
|
// walk down to the declarator for the function itself
|
|
while (decl->kind != DK_FUNCTION && decl->child != NULL)
|
|
decl = decl->child;
|
|
if (decl->kind != DK_FUNCTION) {
|
|
AssertPos(decl->pos, m->errorCount > 0);
|
|
return;
|
|
}
|
|
|
|
// now loop over its parameters and add them to the symbol table
|
|
for (unsigned int i = 0; i < decl->functionParams.size(); ++i) {
|
|
Declaration *pdecl = decl->functionParams[i];
|
|
Assert(pdecl != NULL && pdecl->declarators.size() == 1);
|
|
Declarator *declarator = pdecl->declarators[0];
|
|
if (declarator == NULL)
|
|
AssertPos(decl->pos, m->errorCount > 0);
|
|
else {
|
|
Symbol *sym = new Symbol(declarator->name, declarator->pos,
|
|
declarator->type, declarator->storageClass);
|
|
#ifndef NDEBUG
|
|
bool ok = m->symbolTable->AddVariable(sym);
|
|
if (ok == false)
|
|
AssertPos(decl->pos, m->errorCount > 0);
|
|
#else
|
|
m->symbolTable->AddVariable(sym);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// The corresponding pop scope happens in function_definition rules
|
|
// above...
|
|
}
|
|
|
|
|
|
/** Add a symbol for the built-in mask variable to the symbol table */
|
|
static void lAddMaskToSymbolTable(SourcePos pos) {
|
|
const Type *t = NULL;
|
|
switch (g->target->getMaskBitCount()) {
|
|
case 1:
|
|
t = AtomicType::VaryingBool;
|
|
break;
|
|
case 8:
|
|
t = AtomicType::VaryingUInt8;
|
|
break;
|
|
case 16:
|
|
t = AtomicType::VaryingUInt16;
|
|
break;
|
|
case 32:
|
|
t = AtomicType::VaryingUInt32;
|
|
break;
|
|
case 64:
|
|
t = AtomicType::VaryingUInt64;
|
|
break;
|
|
default:
|
|
FATAL("Unhandled mask bitsize in lAddMaskToSymbolTable");
|
|
}
|
|
|
|
t = t->GetAsConstType();
|
|
Symbol *maskSymbol = new Symbol("__mask", pos, t);
|
|
m->symbolTable->AddVariable(maskSymbol);
|
|
}
|
|
|
|
|
|
/** Add the thread index and thread count variables to the symbol table
|
|
(this should only be done for 'task'-qualified functions. */
|
|
static void lAddThreadIndexCountToSymbolTable(SourcePos pos) {
|
|
const Type *type = AtomicType::UniformUInt32->GetAsConstType();
|
|
|
|
Symbol *threadIndexSym = new Symbol("threadIndex", pos, type);
|
|
m->symbolTable->AddVariable(threadIndexSym);
|
|
|
|
Symbol *threadCountSym = new Symbol("threadCount", pos, type);
|
|
m->symbolTable->AddVariable(threadCountSym);
|
|
|
|
Symbol *taskIndexSym = new Symbol("taskIndex", pos, type);
|
|
m->symbolTable->AddVariable(taskIndexSym);
|
|
|
|
Symbol *taskCountSym = new Symbol("taskCount", pos, type);
|
|
m->symbolTable->AddVariable(taskCountSym);
|
|
|
|
Symbol *taskIndexSym0 = new Symbol("taskIndex0", pos, type);
|
|
m->symbolTable->AddVariable(taskIndexSym0);
|
|
Symbol *taskIndexSym1 = new Symbol("taskIndex1", pos, type);
|
|
m->symbolTable->AddVariable(taskIndexSym1);
|
|
Symbol *taskIndexSym2 = new Symbol("taskIndex2", pos, type);
|
|
m->symbolTable->AddVariable(taskIndexSym2);
|
|
|
|
|
|
Symbol *taskCountSym0 = new Symbol("taskCount0", pos, type);
|
|
m->symbolTable->AddVariable(taskCountSym0);
|
|
Symbol *taskCountSym1 = new Symbol("taskCount1", pos, type);
|
|
m->symbolTable->AddVariable(taskCountSym1);
|
|
Symbol *taskCountSym2 = new Symbol("taskCount2", pos, type);
|
|
m->symbolTable->AddVariable(taskCountSym2);
|
|
}
|
|
|
|
|
|
/** Small utility routine to construct a string for error messages that
|
|
suggests alternate tokens for possibly-misspelled ones... */
|
|
static std::string lGetAlternates(std::vector<std::string> &alternates) {
|
|
std::string alts;
|
|
if (alternates.size()) {
|
|
alts += " Did you mean ";
|
|
for (unsigned int i = 0; i < alternates.size(); ++i) {
|
|
alts += std::string("\"") + alternates[i] + std::string("\"");
|
|
if (i < alternates.size() - 1) alts += ", or ";
|
|
}
|
|
alts += "?";
|
|
}
|
|
return alts;
|
|
}
|
|
|
|
static const char *
|
|
lGetStorageClassString(StorageClass sc) {
|
|
switch (sc) {
|
|
case SC_NONE:
|
|
return "";
|
|
case SC_EXTERN:
|
|
return "extern";
|
|
case SC_STATIC:
|
|
return "static";
|
|
case SC_TYPEDEF:
|
|
return "typedef";
|
|
case SC_EXTERN_C:
|
|
return "extern \"C\"";
|
|
default:
|
|
Assert(!"logic error in lGetStorageClassString()");
|
|
return "";
|
|
}
|
|
}
|
|
|
|
|
|
/** Given an expression, see if it is equal to a compile-time constant
|
|
integer value. If so, return true and return the value in *value.
|
|
If the expression isn't a compile-time constant or isn't an integer
|
|
type, return false.
|
|
*/
|
|
static bool
|
|
lGetConstantInt(Expr *expr, int *value, SourcePos pos, const char *usage) {
|
|
if (expr == NULL)
|
|
return false;
|
|
expr = TypeCheck(expr);
|
|
if (expr == NULL)
|
|
return false;
|
|
expr = Optimize(expr);
|
|
if (expr == NULL)
|
|
return false;
|
|
|
|
llvm::Constant *cval = expr->GetConstant(expr->GetType());
|
|
if (cval == NULL) {
|
|
Error(pos, "%s must be a compile-time constant.", usage);
|
|
return false;
|
|
}
|
|
else {
|
|
llvm::ConstantInt *ci = llvm::dyn_cast<llvm::ConstantInt>(cval);
|
|
if (ci == NULL) {
|
|
Error(pos, "%s must be a compile-time integer constant.", usage);
|
|
return false;
|
|
}
|
|
if ((int64_t)((int32_t)ci->getSExtValue()) != ci->getSExtValue()) {
|
|
Error(pos, "%s must be representable with a 32-bit integer.", usage);
|
|
return false;
|
|
}
|
|
const Type *type = expr->GetType();
|
|
if (type->IsUnsignedType())
|
|
*value = (int)ci->getZExtValue();
|
|
else
|
|
*value = (int)ci->getSExtValue();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
static EnumType *
|
|
lCreateEnumType(const char *name, std::vector<Symbol *> *enums, SourcePos pos) {
|
|
if (enums == NULL)
|
|
return NULL;
|
|
|
|
EnumType *enumType = name ? new EnumType(name, pos) : new EnumType(pos);
|
|
if (name != NULL)
|
|
m->symbolTable->AddType(name, enumType, pos);
|
|
|
|
lFinalizeEnumeratorSymbols(*enums, enumType);
|
|
for (unsigned int i = 0; i < enums->size(); ++i)
|
|
m->symbolTable->AddVariable((*enums)[i]);
|
|
enumType->SetEnumerators(*enums);
|
|
return enumType;
|
|
}
|
|
|
|
|
|
/** Given an array of enumerator symbols, make sure each of them has a
|
|
ConstExpr * in their Symbol::constValue member that stores their
|
|
unsigned integer value. Symbols that had values explicitly provided
|
|
in the source file will already have ConstExpr * set; we just need
|
|
to set the values for the others here.
|
|
*/
|
|
static void
|
|
lFinalizeEnumeratorSymbols(std::vector<Symbol *> &enums,
|
|
const EnumType *enumType) {
|
|
enumType = enumType->GetAsConstType();
|
|
enumType = enumType->GetAsUniformType();
|
|
|
|
/* nextVal tracks the value for the next enumerant. It starts from
|
|
zero and goes up with each successive enumerant. If any of them
|
|
has a value specified, then nextVal is ignored for that one and is
|
|
set to one plus that one's value for the default value for the next
|
|
one. */
|
|
uint32_t nextVal = 0;
|
|
|
|
for (unsigned int i = 0; i < enums.size(); ++i) {
|
|
enums[i]->type = enumType;
|
|
if (enums[i]->constValue != NULL) {
|
|
/* Already has a value, so first update nextVal with it. */
|
|
int count = enums[i]->constValue->GetValues(&nextVal);
|
|
AssertPos(enums[i]->pos, count == 1);
|
|
++nextVal;
|
|
|
|
/* When the source file as being parsed, the ConstExpr for any
|
|
enumerant with a specified value was set to have unsigned
|
|
int32 type, since we haven't created the parent EnumType
|
|
by then. Therefore, add a little type cast from uint32 to
|
|
the actual enum type here and optimize it, which will have
|
|
us end up with a ConstExpr with the desired EnumType... */
|
|
Expr *castExpr = new TypeCastExpr(enumType, enums[i]->constValue,
|
|
enums[i]->pos);
|
|
castExpr = Optimize(castExpr);
|
|
enums[i]->constValue = llvm::dyn_cast<ConstExpr>(castExpr);
|
|
AssertPos(enums[i]->pos, enums[i]->constValue != NULL);
|
|
}
|
|
else {
|
|
enums[i]->constValue = new ConstExpr(enumType, nextVal++,
|
|
enums[i]->pos);
|
|
}
|
|
}
|
|
}
|