quakeforge/tools/qfcc/source/glsl-parse.y
Bill Currie f3d3bc8ec1 [qfcc] Implement glsl field and swizzle expressions
Ruamoko should have swizzles as well since the same underlying code is
used.
2024-04-22 11:28:13 +09:00

1341 lines
35 KiB
Text

/*
glsl-parse.y
parser for GLSL
Copyright (C) 2023 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2023/11/25
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
%define api.prefix {glsl_yy}
%define api.pure full
%define api.push-pull push
%define api.token.prefix {GLSL_}
%locations
%parse-param {void *scanner}
%define api.value.type {rua_val_t}
%define api.location.type {rua_loc_t}
%{
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <stdlib.h>
#include <QF/hash.h>
#include <QF/sys.h>
#include <QF/va.h>
#define GLSL_YYDEBUG 1
#define GLSL_YYERROR_VERBOSE 1
#undef GLSL_YYERROR_VERBOSE
#include "tools/qfcc/include/algebra.h"
#include "tools/qfcc/include/attribute.h"
#include "tools/qfcc/include/class.h"
#include "tools/qfcc/include/debug.h"
#include "tools/qfcc/include/def.h"
#include "tools/qfcc/include/diagnostic.h"
#include "tools/qfcc/include/emit.h"
#include "tools/qfcc/include/expr.h"
#include "tools/qfcc/include/function.h"
#include "tools/qfcc/include/method.h"
#include "tools/qfcc/include/options.h"
#include "tools/qfcc/include/qfcc.h"
#include "tools/qfcc/include/reloc.h"
#include "tools/qfcc/include/rua-lang.h"
#include "tools/qfcc/include/shared.h"
#include "tools/qfcc/include/strpool.h"
#include "tools/qfcc/include/struct.h"
#include "tools/qfcc/include/switch.h"
#include "tools/qfcc/include/symtab.h"
#include "tools/qfcc/include/type.h"
#include "tools/qfcc/include/value.h"
#include "tools/qfcc/source/glsl-parse.h"
#define glsl_yytext qc_yyget_text (scanner)
char *qc_yyget_text (void *scanner);
static void
yyerror (YYLTYPE *yylloc, void *scanner, const char *s)
{
#ifdef GLSL_YYERROR_VERBOSE
error (0, "%s %s\n", glsl_yytext, s);
#else
error (0, "%s before %s", s, glsl_yytext);
#endif
}
static void __attribute__((used))
parse_error (void *scanner)
{
error (0, "parse error before %s", glsl_yytext);
}
#define PARSE_ERROR do { parse_error (scanner); YYERROR; } while (0)
#define first_line line
#define first_column column
int yylex (YYSTYPE *yylval, YYLTYPE *yylloc);
%}
%code requires { #define glsl_yypstate rua_yypstate }
// these tokens are common between qc and qp
%left LOW
%nonassoc IFX
%nonassoc ELSE
%nonassoc BREAK_PRIMARY
%nonassoc ';'
%nonassoc CLASS_NOT_CATEGORY
%nonassoc STORAGEX
%left COMMA
%right <op> '=' ASX
%right '?' ':'
%left OR
%left XOR
%left AND
%left '|'
%left '^'
%left '&'
%left EQ NE
%left LT GT GE LE
%token NAND NOR XNOR
// end of tokens common between qc and qp
%left SHL SHR
%left '+' '-'
%left '*' '/' '%' MOD SCALE GEOMETRIC QMUL QVMUL VQMUL
%left HADAMARD CROSS DOT WEDGE REGRESSIVE
%right <op> SIZEOF UNARY INCOP REVERSE STAR DUAL UNDUAL
%left HYPERUNARY
%left '.' '(' '['
%token <expr> VALUE STRING TOKEN
%token ELLIPSIS
%token RESERVED
// end of common tokens
%token <symbol> IDENTIFIER
%token WHILE DO IF ELSE FOR BREAK CONTINUE
%token RETURN
%token SWITCH CASE DEFAULT
%token <op> STRUCT
%token <spec> TYPE_SPEC TYPE_NAME TYPE_QUAL VOID
%token <spec> PRECISION INVARIANT SMOOTH FLAT NOPERSPECTIVE LAYOUT SHARED
%token <spec> PRECISE CONST IN OUT INOUT CENTROID PATCH SAMPLE UNIFORM BUFFER VOLATILE
%token <spec> RESTRICT READONLY WRITEONLY HIGH_PRECISION MEDIUM_PRECISION
%token <spec> LOW_PRECISION DISCARD COHERENT
%type <symbol> variable_identifier
%type <expr> expression primary_exprsssion assignment_expression
%type <expr> for_init_statement conditionopt expressionopt else
%type <expr> conditional_expression unary_expression postfix_expression
%type <expr> function_call function_call_or_method function_call_generic
%type <expr> function_call_header_with_parameters
%type <expr> function_call_header_no_parameters
%type <expr> function_call_header function_identifier
%type <expr> logical_or_expression logical_xor_expression
%type <expr> logical_and_expression
%type <expr> inclusive_or_expression exclusive_or_expression and_expression
%type <expr> equality_expression relational_expression
%type <expr> shift_expression additive_expression multiplicative_expression
%type <expr> integer_expression
%type <expr> initializer
%type <expr> condition
%type <expr> compound_statement_no_new_scope compound_statement
%type <expr> statement statement_no_new_scope statement_list
%type <expr> simple_statement expression_statement
%type <expr> declaration_statement selection_statement
%type <expr> switch_statement switch_statement_list case_label
%type <switch_block> switch_block
%type <expr> iteration_statement jump_statement
%type <expr> break_label continue_label
%type <mut_expr> initializer_list
%type <op> unary_operator assignment_operator
%type <spec> function_prototype function_declarator
%type <spec> function_header function_header_with_parameters
%type <spec> fully_specified_type type_specifier struct_specifier
%type <spec> type_qualifier single_type_qualifier type_specifier_nonarray
%type <spec> precision_qualifier interpolation_qualifier invariant_qualifier
%type <spec> precise_qualifer storage_qualifier layout_qualifier
%type <size> array_size
%type <type> array_specifier
%type <param> parameter_declaration
%type <param> parameter_declarator parameter_type_specifier
%{
static switch_block_t *switch_block;
static const expr_t *break_label;
static const expr_t *continue_label;
static symbol_t *
function_sym_type (specifier_t spec, symbol_t *sym)
{
sym->type = append_type (spec.sym->type, spec.type);
set_func_type_attrs (sym->type, spec);
sym->type = find_type (sym->type);
return sym;
}
%}
%expect 0
%%
translation_unit
: external_declaration
| translation_unit external_declaration
;
external_declaration
: function_definition
| declaration
| ';'
;
function_definition
: function_prototype
{
$<symtab>$ = current_symtab;
auto spec = $1;
spec.sym->type = parse_params (spec.sym->type, spec.params);
auto sym = function_sym_type (spec, spec.sym);
sym->params = spec.params;
sym = function_symbol (sym, true, true);
current_func = begin_function (sym, nullptr, current_symtab,
false, spec.storage);
current_symtab = current_func->locals;
current_storage = sc_local;
}
compound_statement_no_new_scope
{
auto spec = $1;
auto sym = spec.sym;
build_code_function (sym, nullptr, (expr_t *) $3);
current_symtab = $<symtab>2;
current_storage = sc_global;//FIXME
current_func = nullptr;
}
;
variable_identifier
: IDENTIFIER
;
primary_exprsssion
: variable_identifier { $$ = new_symbol_expr ($1); }
| VALUE
| '(' expression ')' { $$ = $2; ((expr_t *) $$)->paren = 1; }
;
postfix_expression
: primary_exprsssion
| postfix_expression '[' integer_expression ']'
{
$$ = array_expr ($1, $3);
}
| function_call
| postfix_expression '.' IDENTIFIER/*FIELD_SELECTION*/
{
auto sym = new_symbol_expr ($3);
$$ = field_expr ($1, sym);
}
| postfix_expression INCOP { $$ = incop_expr ($2, $1, 1); }
;
integer_expression
: expression
;
function_call
: function_call_or_method
;
function_call_or_method
: function_call_generic
;
function_call_generic
: function_call_header_with_parameters ')'
| function_call_header_no_parameters ')'
;
function_call_header_no_parameters
: function_call_header VOID
| function_call_header
;
function_call_header_with_parameters
: function_call_header assignment_expression
| function_call_header_with_parameters ',' assignment_expression
;
function_call_header
: function_identifier '('
;
function_identifier
: type_specifier { }
| postfix_expression
;
unary_expression
: postfix_expression
| INCOP unary_expression { $$ = incop_expr ($1, $2, 0); }
| unary_operator unary_expression { $$ = unary_expr ($1, $2); }
;
unary_operator
: '+' { $$ = '+'; }
| '-' { $$ = '-'; }
| '!' { $$ = '!'; }
| '~' { $$ = '~'; }
;
multiplicative_expression
: unary_expression
| multiplicative_expression '*' unary_expression
{
$$ = binary_expr ('*', $1, $3);
}
| multiplicative_expression '/' unary_expression
{
$$ = binary_expr ('/', $1, $3);
}
| multiplicative_expression '%' unary_expression
{
$$ = binary_expr ('%', $1, $3);
}
;
additive_expression
: multiplicative_expression
| additive_expression '+' unary_expression
{
$$ = binary_expr ('+', $1, $3);
}
| additive_expression '-' unary_expression
{
$$ = binary_expr ('-', $1, $3);
}
;
shift_expression
: additive_expression
| shift_expression SHL additive_expression
{
$$ = binary_expr (QC_SHL, $1, $3);
}
| shift_expression SHR additive_expression
{
$$ = binary_expr (QC_SHR, $1, $3);
}
;
relational_expression
: shift_expression
| relational_expression LT shift_expression
{
$$ = binary_expr (QC_LT, $1, $3);
}
| relational_expression GT shift_expression
{
$$ = binary_expr (QC_GT, $1, $3);
}
| relational_expression LE shift_expression
{
$$ = binary_expr (QC_LE, $1, $3);
}
| relational_expression GE shift_expression
{
$$ = binary_expr (QC_GE, $1, $3);
}
;
equality_expression
: relational_expression
| equality_expression EQ relational_expression
{
$$ = binary_expr (QC_EQ, $1, $3);
}
| relational_expression NE relational_expression
{
$$ = binary_expr (QC_NE, $1, $3);
}
;
and_expression
: equality_expression
| and_expression '&' equality_expression
{
$$ = binary_expr ('&', $1, $3);
}
;
exclusive_or_expression
: and_expression
| exclusive_or_expression '^' and_expression
{
$$ = binary_expr ('^', $1, $3);
}
;
inclusive_or_expression
: exclusive_or_expression
| inclusive_or_expression '|' exclusive_or_expression
{
$$ = binary_expr ('|', $1, $3);
}
;
logical_and_expression
: inclusive_or_expression
| logical_and_expression AND inclusive_or_expression
{
$$ = bool_expr (QC_AND, nullptr, $1, $3);
}
;
logical_xor_expression
: logical_and_expression
| logical_xor_expression XOR logical_and_expression
{
$$ = bool_expr (QC_XOR, nullptr, $1, $3);
}
;
logical_or_expression
: logical_xor_expression
| logical_or_expression OR logical_xor_expression
{
$$ = bool_expr (QC_OR, nullptr, $1, $3);
}
;
conditional_expression
: logical_or_expression
| logical_or_expression '?' expression ':' assignment_expression
{
$$ = conditional_expr ($1, $3, $5);
}
;
assignment_expression
: conditional_expression
| unary_expression assignment_operator assignment_expression
{
if ($2 == '=') {
$$ = assign_expr ($1, $3);
} else {
$$ = asx_expr ($2, $1, $3);
}
}
;
assignment_operator
: '=' { $$ = '='; }
| ASX
;
expression
: assignment_expression
| expression ',' assignment_expression
;
constant_expression
: conditional_expression
;
declaration
: function_prototype ';'
| init_declarator_list ';'
| PRECISION precision_qualifier type_specifier ';'
| type_qualifier IDENTIFIER '{' struct_declaration_list '}' ';'
| type_qualifier IDENTIFIER '{' struct_declaration_list '}' IDENTIFIER ';'
| type_qualifier IDENTIFIER '{' struct_declaration_list '}' IDENTIFIER array_specifier ';'
| type_qualifier ';'
| type_qualifier IDENTIFIER ';'
| type_qualifier IDENTIFIER identifier_list ';'
;
identifier_list
: ',' IDENTIFIER
| identifier_list ',' IDENTIFIER
;
function_prototype
: function_declarator ')'
;
function_declarator
: function_header
| function_header_with_parameters
;
function_header_with_parameters
: function_header parameter_declaration
{
auto spec = $1;
spec.params = $2;
$$ = spec;
}
| function_header_with_parameters ',' parameter_declaration
{
auto spec = $1;
spec.params = append_params (spec.params, $3);
$$ = spec;
}
;
function_header
: fully_specified_type IDENTIFIER '('
{
auto spec = $1;
if ($2->table) {
spec.sym = new_symbol ($2->name);
} else {
spec.sym = $2;
}
$$ = spec;
}
;
parameter_declarator
: type_specifier IDENTIFIER
{
$$ = new_param (nullptr, $1.type, $2->name);
}
| type_specifier IDENTIFIER array_specifier
{
$$ = new_param (nullptr, append_type ($1.type, $3), $2->name);
}
;
parameter_declaration
: type_qualifier parameter_declarator { $$ = $2; }//XXX
| parameter_declarator
| type_qualifier parameter_type_specifier { $$ = $2; }//XXX
| parameter_type_specifier
;
parameter_type_specifier
: type_specifier
{
$$ = new_param (nullptr, $1.type, nullptr);
}
;
init_declarator_list
: single_declaration
| init_declarator_list ',' IDENTIFIER
{
auto symtab = current_symtab;
auto space = symtab->space;
auto storage = current_storage;
initialize_def ($3, nullptr, space, storage, symtab);
}
| init_declarator_list ',' IDENTIFIER array_specifier
| init_declarator_list ',' IDENTIFIER array_specifier '=' initializer
| init_declarator_list ',' IDENTIFIER '=' initializer
{
auto symtab = current_symtab;
auto space = symtab->space;
auto storage = current_storage;
initialize_def ($3, $5, space, storage, symtab);
}
;
single_declaration
: fully_specified_type
| fully_specified_type IDENTIFIER
| fully_specified_type IDENTIFIER array_specifier
| fully_specified_type IDENTIFIER array_specifier '=' initializer
| fully_specified_type IDENTIFIER '=' initializer
;
fully_specified_type
: type_specifier
| type_qualifier type_specifier
;
invariant_qualifier
: INVARIANT
;
interpolation_qualifier
: SMOOTH
| FLAT
| NOPERSPECTIVE
;
layout_qualifier
: LAYOUT '(' layout_qualifer_id_list ')'
;
layout_qualifer_id_list
: layout_qualifer_id
| layout_qualifer_id_list ',' layout_qualifer_id
;
layout_qualifer_id
: IDENTIFIER
| IDENTIFIER '=' constant_expression
| SHARED
;
precise_qualifer
: PRECISE
;
type_qualifier
: single_type_qualifier
| type_qualifier single_type_qualifier
;
single_type_qualifier
: storage_qualifier
| layout_qualifier
| precision_qualifier
| interpolation_qualifier
| invariant_qualifier
| precise_qualifer
;
storage_qualifier
: CONST
| IN
| OUT
| INOUT
| CENTROID
| PATCH
| SAMPLE
| UNIFORM
| BUFFER
| SHARED
| COHERENT
| VOLATILE
| RESTRICT
| READONLY
| WRITEONLY
;
type_specifier
: type_specifier_nonarray
| type_specifier_nonarray array_specifier
;
array_specifier
: array_size { $$ = (type_t *) array_type (nullptr, $1); }
| array_specifier array_size
{
$$ = (type_t *) append_type ($1, array_type (nullptr, $2));
}
;
array_size
: '[' ']' { $$ = 0; }
| '[' conditional_expression ']'
{
if (is_int_val ($2) && expr_int ($2) > 0) {
$$ = expr_int ($2);
} else if (is_uint_val ($2) && expr_uint ($2) > 0) {
$$ = expr_uint ($2);
} else{
error (0, "invalid array size");
$$ = 0;
}
}
;
type_specifier_nonarray
: VOID
| TYPE_SPEC
| struct_specifier
| TYPE_NAME
;
precision_qualifier
: HIGH_PRECISION
| MEDIUM_PRECISION
| LOW_PRECISION
;
struct_specifier
: STRUCT IDENTIFIER '{'
{
int op = 's';
current_symtab = start_struct (&op, $2, current_symtab);
}
struct_declaration_list '}'
{
auto symtab = current_symtab;
current_symtab = symtab->parent;
auto sym = build_struct ('s', $2, symtab, nullptr, 0);
if (!sym->table) {
symtab_addsymbol (current_symtab, sym);
}
auto s = $2;
s->sy_type = sy_type;
s->type = find_type (alias_type (sym->type, sym->type, s->name));
symtab_addsymbol (current_symtab, s);
}
| STRUCT '{'
{
int op = 's';
current_symtab = start_struct (&op, nullptr, current_symtab);
}
struct_declaration_list '}'
{
auto symtab = current_symtab;
current_symtab = symtab->parent;
auto sym = build_struct ('s', nullptr, symtab, nullptr, 0);
if (!sym->table) {
symtab_addsymbol (current_symtab, sym);
}
}
;
struct_declaration_list
: struct_declaration
| struct_declaration_list struct_declaration
;
struct_declaration
: type_specifier struct_declarator_list ';'
| type_qualifier type_specifier struct_declarator_list ';'
;
struct_declarator_list
: struct_declarator
| struct_declarator_list ',' struct_declarator
;
struct_declarator
: IDENTIFIER
| IDENTIFIER array_specifier
;
initializer
: assignment_expression
| '{' initializer_list '}' { $$ = $2; }
| '{' initializer_list ',' '}' { $$ = $2; }
;
initializer_list
: initializer
{
$$ = new_compound_init ();
append_element ($$, new_element ($1, nullptr));
}
| initializer_list ',' initializer
{
append_element ($$, new_element ($3, nullptr));
}
;
declaration_statement
: declaration { $$ = nullptr; }
;
statement
: compound_statement
| simple_statement
;
simple_statement
: declaration_statement
| expression_statement
| selection_statement
| switch_statement
| case_label
| iteration_statement
| jump_statement
;
compound_statement
: '{' '}' { $$ = nullptr; }
| '{' statement_list '}' { $$ = $2; }
;
statement_no_new_scope
: compound_statement_no_new_scope
| simple_statement
;
compound_statement_no_new_scope
: '{' '}' { $$ = nullptr; }
| '{' statement_list '}' { $$ = $2; }
;
statement_list
: statement
{
auto list = new_block_expr (nullptr);
append_expr (list, $1);
$$ = list;
}
| statement_list statement
{
auto list = (expr_t *) $1;
append_expr (list, $2);
$$ = list;
}
;
expression_statement
: ';' { $$ = nullptr; }
| expression ';' { $$ = (expr_t *) $expression; }
;
selection_statement
// : IF '(' expression ')' selection_rest_statement
: IF '(' expression ')' statement[true] %prec IFX
{
$$ = build_if_statement (false, $expression,
$true, nullptr, nullptr);
}
| IF '(' expression ')' statement[true] else statement[false]
{
$$ = build_if_statement (false, $expression,
$true, $else, $false);
}
;
else
: ELSE
{
// this is only to get the the file and line number info
$$ = new_nil_expr ();
}
;
//selection_rest_statement
// : statement ELSE statement
// | statement %prec IFX
// ;
condition
: expression
| fully_specified_type IDENTIFIER '=' initializer
{
auto symtab = current_symtab;
auto space = symtab->space;
auto storage = current_storage;
initialize_def ($2, $initializer, space, storage, symtab);
}
;
break_label
: /* empty */
{
$$ = break_label;
break_label = new_label_expr ();
}
;
continue_label
: /* empty */
{
$$ = continue_label;
continue_label = new_label_expr ();
}
;
switch_statement
: SWITCH break_label '(' expression switch_block')'
'{' switch_statement_list '}'
{
$$ = switch_expr (switch_block, break_label,
$switch_statement_list);
switch_block = $switch_block;
break_label = $break_label;
}
;
switch_block
: /* empty */
{
$$ = switch_block;
switch_block = new_switch_block ();
switch_block->test = $<expr>0;
}
;
switch_statement_list
: /* empty */ { $$ = nullptr; }
| statement_list
;
case_label
: CASE expression ':' { $$ = case_label_expr (switch_block, $2); }
| DEFAULT ':' { $$ = case_label_expr (switch_block, nullptr); }
;
iteration_statement
: WHILE break_label continue_label '(' condition ')' statement_no_new_scope
{
$$ = build_while_statement (false, $continue_label,
$statement_no_new_scope, break_label,
continue_label);
break_label = $break_label;
continue_label = $continue_label;
}
| DO break_label continue_label statement WHILE '(' expression ')' ';'
{
$$ = build_do_while_statement ($statement, false, $expression,
break_label, continue_label);
break_label = $break_label;
continue_label = $continue_label;
}
| FOR break_label continue_label
// '(' for_init_statement for_rest_statement ')'
'(' for_init_statement ';' conditionopt ';' expressionopt ')'
statement_no_new_scope
{
if ($for_init_statement) {
$for_init_statement = build_block_expr ((expr_t *) $for_init_statement,
false);
}
$$ = build_for_statement ($for_init_statement, $conditionopt,
$expressionopt, $statement_no_new_scope,
break_label, continue_label);
break_label = $break_label;
continue_label = $continue_label;
}
;
for_init_statement
: expression_statement { $$ = $1; }
| declaration_statement { $$ = $1; }
;
conditionopt
: condition
| /* emtpy */ { $$ = nullptr; }
;
expressionopt
: expression
| /* emtpy */ { $$ = nullptr; }
;
/*
for_rest_statement
: conditionopt ';'
| conditionopt ';' expression
;
*/
jump_statement
: CONTINUE ';'
{
$$ = nullptr;
if (continue_label) {
$$ = goto_expr (continue_label);
} else {
error (nullptr, "continue outside of loop");
}
}
| BREAK ';'
{
$$ = nullptr;
if (break_label) {
$$ = goto_expr (break_label);
} else {
error (nullptr, "continue outside of loop or switch");
}
}
| RETURN ';' { $$ = return_expr (current_func, nullptr); }
| RETURN expression ';' { $$ = return_expr (current_func, $2); }
| DISCARD ';' { $$ = nullptr; } //XXX
;
%%
static keyword_t glsl_keywords[] = {
{"const", GLSL_CONST},
{"uniform", GLSL_UNIFORM},
{"buffer", GLSL_BUFFER},
{"shared", GLSL_SHARED},
{"attribute", GLSL_RESERVED},
{"varying", GLSL_RESERVED},
{"coherent", GLSL_COHERENT},
{"volatile", GLSL_VOLATILE},
{"restrict", GLSL_RESTRICT},
{"readonly", GLSL_READONLY},
{"writeonly", GLSL_WRITEONLY},
{"atomic_uint", GLSL_RESERVED},
{"layout", GLSL_LAYOUT},
{"centroid", GLSL_CENTROID},
{"flat", GLSL_FLAT},
{"smooth", GLSL_SMOOTH},
{"noperspective", GLSL_NOPERSPECTIVE},
{"patch", GLSL_PATCH},
{"sample", GLSL_SAMPLE},
{"invariant", GLSL_INVARIANT},
{"precise", GLSL_PRECISE},
{"break", GLSL_BREAK},
{"continue", GLSL_CONTINUE},
{"do", GLSL_DO},
{"for", GLSL_FOR},
{"while", GLSL_WHILE},
{"switch", GLSL_SWITCH},
{"case", GLSL_CASE},
{"default", GLSL_DEFAULT},
{"if", GLSL_IF},
{"else", GLSL_ELSE},
{"subroutine", GLSL_RESERVED},
{"in", GLSL_IN},
{"out", GLSL_OUT},
{"inout", GLSL_INOUT},
{"int", GLSL_TYPE_SPEC, .spec = {.type = &type_int}},
{"void", GLSL_VOID, .spec = {.type = &type_void}},
{"bool", GLSL_TYPE_SPEC, .spec = {.type = &type_bool}},
{"true", 0},
{"false", 0},
{"float", GLSL_TYPE_SPEC, .spec = {.type = &type_float}},
{"double", GLSL_TYPE_SPEC, .spec = {.type = &type_double}},
{"discard", GLSL_DISCARD},
{"return", GLSL_RETURN},
{"vec2", GLSL_TYPE_SPEC, .spec = {.type = &type_vec2}},
{"vec3", GLSL_TYPE_SPEC, .spec = {.type = &type_vec3}},
{"vec4", GLSL_TYPE_SPEC, .spec = {.type = &type_vec4}},
{"ivec2", GLSL_TYPE_SPEC, .spec = {.type = &type_ivec2}},
{"ivec3", GLSL_TYPE_SPEC, .spec = {.type = &type_ivec3}},
{"ivec4", GLSL_TYPE_SPEC, .spec = {.type = &type_ivec4}},
{"bvec2", GLSL_TYPE_SPEC, .spec = {.type = &type_bvec2}},
{"bvec3", GLSL_TYPE_SPEC, .spec = {.type = &type_bvec3}},
{"bvec4", GLSL_TYPE_SPEC, .spec = {.type = &type_bvec4}},
{"uint", GLSL_TYPE_SPEC, .spec = {.type = &type_uint}},
{"uvec2", GLSL_TYPE_SPEC, .spec = {.type = &type_uivec2}},
{"uvec3", GLSL_TYPE_SPEC, .spec = {.type = &type_uivec3}},
{"uvec4", GLSL_TYPE_SPEC, .spec = {.type = &type_uivec4}},
{"dvec2", GLSL_TYPE_SPEC, .spec = {.type = &type_dvec2}},
{"dvec3", GLSL_TYPE_SPEC, .spec = {.type = &type_dvec3}},
{"dvec4", GLSL_TYPE_SPEC, .spec = {.type = &type_dvec4}},
{"mat2", GLSL_TYPE_SPEC, .spec = {.type = &type_mat2x2}},
{"mat3", GLSL_TYPE_SPEC, .spec = {.type = &type_mat3x3}},
{"mat4", GLSL_TYPE_SPEC, .spec = {.type = &type_mat4x4}},
{"mat2x2", GLSL_TYPE_SPEC, .spec = {.type = &type_mat2x2}},
{"mat2x3", GLSL_TYPE_SPEC, .spec = {.type = &type_mat2x3}},
{"mat2x4", GLSL_TYPE_SPEC, .spec = {.type = &type_mat2x4}},
{"mat3x2", GLSL_TYPE_SPEC, .spec = {.type = &type_mat3x2}},
{"mat3x3", GLSL_TYPE_SPEC, .spec = {.type = &type_mat3x3}},
{"mat3x4", GLSL_TYPE_SPEC, .spec = {.type = &type_mat3x4}},
{"mat4x2", GLSL_TYPE_SPEC, .spec = {.type = &type_mat4x2}},
{"mat4x3", GLSL_TYPE_SPEC, .spec = {.type = &type_mat4x3}},
{"mat4x4", GLSL_TYPE_SPEC, .spec = {.type = &type_mat4x4}},
{"dmat2", GLSL_TYPE_SPEC, .spec = {.type = &type_dmat2x2}},
{"dmat3", GLSL_TYPE_SPEC, .spec = {.type = &type_dmat3x3}},
{"dmat4", GLSL_TYPE_SPEC, .spec = {.type = &type_dmat4x4}},
{"dmat2x2", GLSL_TYPE_SPEC, .spec = {.type = &type_dmat2x2}},
{"dmat2x3", GLSL_TYPE_SPEC, .spec = {.type = &type_dmat2x3}},
{"dmat2x4", GLSL_TYPE_SPEC, .spec = {.type = &type_dmat2x4}},
{"dmat3x2", GLSL_TYPE_SPEC, .spec = {.type = &type_dmat3x2}},
{"dmat3x3", GLSL_TYPE_SPEC, .spec = {.type = &type_dmat3x3}},
{"dmat3x4", GLSL_TYPE_SPEC, .spec = {.type = &type_dmat3x4}},
{"dmat4x2", GLSL_TYPE_SPEC, .spec = {.type = &type_dmat4x2}},
{"dmat4x3", GLSL_TYPE_SPEC, .spec = {.type = &type_dmat4x3}},
{"dmat4x4", GLSL_TYPE_SPEC, .spec = {.type = &type_dmat4x4}},
{"lowp", GLSL_LOW_PRECISION},
{"mediump", GLSL_MEDIUM_PRECISION},
{"highp", GLSL_HIGH_PRECISION},
{"precision", GLSL_PRECISION},
{"sampler1D", GLSL_TYPE_SPEC}, // spec init at runtime
{"sampler1DShadow", GLSL_TYPE_SPEC},
{"sampler1DArray", GLSL_TYPE_SPEC},
{"sampler1DArrayShadow", GLSL_TYPE_SPEC},
{"isampler1D", GLSL_TYPE_SPEC},
{"isampler1DArray", GLSL_TYPE_SPEC},
{"usampler1D", GLSL_TYPE_SPEC},
{"usampler1DArray", GLSL_TYPE_SPEC},
{"sampler2D", GLSL_TYPE_SPEC},
{"sampler2DShadow", GLSL_TYPE_SPEC},
{"sampler2DArray", GLSL_TYPE_SPEC},
{"sampler2DArrayShadow", GLSL_TYPE_SPEC},
{"isampler2D", GLSL_TYPE_SPEC},
{"isampler2DArray", GLSL_TYPE_SPEC},
{"usampler2D", GLSL_TYPE_SPEC},
{"usampler2DArray", GLSL_TYPE_SPEC},
{"sampler2DRect", GLSL_TYPE_SPEC},
{"sampler2DRectShadow", GLSL_TYPE_SPEC},
{"isampler2DRect", GLSL_TYPE_SPEC},
{"usampler2DRect", GLSL_TYPE_SPEC},
{"sampler2DMS", GLSL_TYPE_SPEC},
{"isampler2DMS", GLSL_TYPE_SPEC},
{"usampler2DMS", GLSL_TYPE_SPEC},
{"sampler2DMSArray", GLSL_TYPE_SPEC},
{"isampler2DMSArray", GLSL_TYPE_SPEC},
{"usampler2DMSArray", GLSL_TYPE_SPEC},
{"sampler3D", GLSL_TYPE_SPEC},
{"isampler3D", GLSL_TYPE_SPEC},
{"usampler3D", GLSL_TYPE_SPEC},
{"samplerCube", GLSL_TYPE_SPEC},
{"samplerCubeShadow", GLSL_TYPE_SPEC},
{"isamplerCube", GLSL_TYPE_SPEC},
{"usamplerCube", GLSL_TYPE_SPEC},
{"samplerCubeArray", GLSL_TYPE_SPEC},
{"samplerCubeArrayShadow", GLSL_TYPE_SPEC},
{"isamplerCubeArray", GLSL_TYPE_SPEC},
{"usamplerCubeArray", GLSL_TYPE_SPEC},
{"samplerBuffer", GLSL_TYPE_SPEC},
{"isamplerBuffer", GLSL_TYPE_SPEC},
{"usamplerBuffer", GLSL_TYPE_SPEC},
{"image1D", GLSL_TYPE_SPEC},
{"iimage1D", GLSL_TYPE_SPEC},
{"uimage1D", GLSL_TYPE_SPEC},
{"image1DArray", GLSL_TYPE_SPEC},
{"iimage1DArray", GLSL_TYPE_SPEC},
{"uimage1DArray", GLSL_TYPE_SPEC},
{"image2D", GLSL_TYPE_SPEC},
{"iimage2D", GLSL_TYPE_SPEC},
{"uimage2D", GLSL_TYPE_SPEC},
{"image2DArray", GLSL_TYPE_SPEC},
{"iimage2DArray", GLSL_TYPE_SPEC},
{"uimage2DArray", GLSL_TYPE_SPEC},
{"image2DRect", GLSL_TYPE_SPEC},
{"iimage2DRect", GLSL_TYPE_SPEC},
{"uimage2DRect", GLSL_TYPE_SPEC},
{"image2DMS", GLSL_TYPE_SPEC},
{"iimage2DMS", GLSL_TYPE_SPEC},
{"uimage2DMS", GLSL_TYPE_SPEC},
{"image2DMSArray", GLSL_TYPE_SPEC},
{"iimage2DMSArray", GLSL_TYPE_SPEC},
{"uimage2DMSArray", GLSL_TYPE_SPEC},
{"image3D", GLSL_TYPE_SPEC},
{"iimage3D", GLSL_TYPE_SPEC},
{"uimage3D", GLSL_TYPE_SPEC},
{"imageCube", GLSL_TYPE_SPEC},
{"iimageCube", GLSL_TYPE_SPEC},
{"uimageCube", GLSL_TYPE_SPEC},
{"imageCubeArray", GLSL_TYPE_SPEC},
{"iimageCubeArray", GLSL_TYPE_SPEC},
{"uimageCubeArray", GLSL_TYPE_SPEC},
{"imageBuffer", GLSL_TYPE_SPEC},
{"iimageBuffer", GLSL_TYPE_SPEC},
{"uimageBuffer", GLSL_TYPE_SPEC},
{"struct", GLSL_STRUCT},
//vulkan
{"texture1D", GLSL_TYPE_SPEC}, // spec init at runtime
{"texture1DArray", GLSL_TYPE_SPEC},
{"itexture1D", GLSL_TYPE_SPEC},
{"itexture1DArray", GLSL_TYPE_SPEC},
{"utexture1D", GLSL_TYPE_SPEC},
{"utexture1DArray", GLSL_TYPE_SPEC},
{"texture2D", GLSL_TYPE_SPEC},
{"texture2DArray", GLSL_TYPE_SPEC},
{"itexture2D", GLSL_TYPE_SPEC},
{"itexture2DArray", GLSL_TYPE_SPEC},
{"utexture2D", GLSL_TYPE_SPEC},
{"utexture2DArray", GLSL_TYPE_SPEC},
{"texture2DRect", GLSL_TYPE_SPEC},
{"itexture2DRect", GLSL_TYPE_SPEC},
{"utexture2DRect", GLSL_TYPE_SPEC},
{"texture2DMS", GLSL_TYPE_SPEC},
{"itexture2DMS", GLSL_TYPE_SPEC},
{"utexture2DMS", GLSL_TYPE_SPEC},
{"texture2DMSArray", GLSL_TYPE_SPEC},
{"itexture2DMSArray", GLSL_TYPE_SPEC},
{"utexture2DMSArray", GLSL_TYPE_SPEC},
{"texture3D", GLSL_TYPE_SPEC},
{"itexture3D", GLSL_TYPE_SPEC},
{"utexture3D", GLSL_TYPE_SPEC},
{"textureCube", GLSL_TYPE_SPEC},
{"itextureCube", GLSL_TYPE_SPEC},
{"utextureCube", GLSL_TYPE_SPEC},
{"textureCubeArray", GLSL_TYPE_SPEC},
{"itextureCubeArray", GLSL_TYPE_SPEC},
{"utextureCubeArray", GLSL_TYPE_SPEC},
{"textureBuffer", GLSL_TYPE_SPEC},
{"itextureBuffer", GLSL_TYPE_SPEC},
{"utextureBuffer", GLSL_TYPE_SPEC},
{"sampler", GLSL_TYPE_SPEC},
{"samplerShadow", GLSL_TYPE_SPEC},
{"subpassInput", GLSL_TYPE_SPEC},
{"isubpassInput", GLSL_TYPE_SPEC},
{"usubpassInput", GLSL_TYPE_SPEC},
{"subpassInputMS", GLSL_TYPE_SPEC},
{"isubpassInputMS", GLSL_TYPE_SPEC},
{"usubpassInputMS", GLSL_TYPE_SPEC},
//reserved
{"common", GLSL_RESERVED},
{"partition", GLSL_RESERVED},
{"active", GLSL_RESERVED},
{"asm", GLSL_RESERVED},
{"class", GLSL_RESERVED},
{"union", GLSL_RESERVED},
{"enum", GLSL_RESERVED},
{"typedef", GLSL_RESERVED},
{"template", GLSL_RESERVED},
{"this", GLSL_RESERVED},
{"resource", GLSL_RESERVED},
{"goto", GLSL_RESERVED},
{"inline", GLSL_RESERVED},
{"noinline", GLSL_RESERVED},
{"public", GLSL_RESERVED},
{"static", GLSL_RESERVED},
{"extern", GLSL_RESERVED},
{"external", GLSL_RESERVED},
{"interface", GLSL_RESERVED},
{"long", GLSL_RESERVED},
{"short", GLSL_RESERVED},
{"half", GLSL_RESERVED},
{"fixed", GLSL_RESERVED},
{"unsigned", GLSL_RESERVED},
{"superp", GLSL_RESERVED},
{"input", GLSL_RESERVED},
{"output", GLSL_RESERVED},
{"hvec2", GLSL_RESERVED},
{"hvec3", GLSL_RESERVED},
{"hvec4", GLSL_RESERVED},
{"fvec2", GLSL_RESERVED},
{"fvec3", GLSL_RESERVED},
{"fvec4", GLSL_RESERVED},
{"filter", GLSL_RESERVED},
{"sizeof", GLSL_RESERVED},
{"cast", GLSL_RESERVED},
{"namespace", GLSL_RESERVED},
{"using", GLSL_RESERVED},
{"sampler3DRect", GLSL_RESERVED},
};
// preprocessor directives in ruamoko and quakec
static directive_t glsl_directives[] = {
{"include", PRE_INCLUDE},
{"define", PRE_DEFINE},
{"undef", PRE_UNDEF},
{"error", PRE_ERROR},
{"warning", PRE_WARNING},
{"notice", PRE_NOTICE},
{"pragma", PRE_PRAGMA},
{"line", PRE_LINE},
{"extension", PRE_EXTENSION},
{"version", PRE_VERSION},
};
static directive_t *
glsl_directive (const char *token)
{
static hashtab_t *directive_tab;
if (!directive_tab) {
directive_tab = Hash_NewTable (253, rua_directive_get_key, 0, 0, 0);
for (size_t i = 0; i < ARRCOUNT(glsl_directives); i++) {
Hash_Add (directive_tab, &glsl_directives[i]);
}
}
directive_t *directive = Hash_Find (directive_tab, token);
return directive;
}
static int
glsl_process_keyword (rua_val_t *lval, keyword_t *keyword, const char *token)
{
if (keyword->value == GLSL_STRUCT) {
lval->op = token[0];
} else if (keyword->value == GLSL_TYPE_SPEC && !keyword->spec.type) {
auto sym = new_symbol (token);
sym = find_handle (sym, &type_int);
keyword->spec.type = sym->type;
lval->spec = keyword->spec;
} else {
lval->spec = keyword->spec;
}
return keyword->value;
}
static int
glsl_keyword_or_id (rua_val_t *lval, const char *token)
{
static hashtab_t *glsl_keyword_tab;
keyword_t *keyword = 0;
symbol_t *sym;
if (!glsl_keyword_tab) {
size_t i;
glsl_keyword_tab = Hash_NewTable (253, rua_keyword_get_key, 0, 0, 0);
for (i = 0; i < ARRCOUNT(glsl_keywords); i++)
Hash_Add (glsl_keyword_tab, &glsl_keywords[i]);
}
keyword = Hash_Find (glsl_keyword_tab, token);
if (keyword && keyword->value)
return glsl_process_keyword (lval, keyword, token);
if (token[0] == '@') {
return '@';
}
sym = symtab_lookup (current_symtab, token);
if (!sym)
sym = new_symbol (token);
lval->symbol = sym;
if (sym->sy_type == sy_type) {
lval->spec = (specifier_t) {
.type = sym->type,
.sym = sym,
};
return GLSL_TYPE_NAME;
}
return GLSL_IDENTIFIER;
}
int
glsl_yyparse (FILE *in)
{
rua_parser_t parser = {
.parse = glsl_yypush_parse,
.state = glsl_yypstate_new (),
.directive = glsl_directive,
.keyword_or_id = glsl_keyword_or_id,
};
int ret = rua_parse (in, &parser);
glsl_yypstate_delete (parser.state);
return ret;
}