-
Notifications
You must be signed in to change notification settings - Fork 2
/
SDL_shader_parser.lemon
312 lines (268 loc) · 19.4 KB
/
SDL_shader_parser.lemon
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
/**
* SDL_shader_tools; tools for SDL GPU shader support.
*
* Please see the file LICENSE.txt in the source's root directory.
*/
%name ParseSDLSL
%start_symbol shader
%token_prefix TOKEN_SDLSL_
%token_type { TokenData }
%extra_argument { Context *ctx }
%include {
#ifndef __SDL_SHADER_SDLSL_COMPILER__
#error Do not compile this file directly.
#endif
}
%syntax_error {
// !!! FIXME: make this a proper fail() function.
fail(ctx, "Syntax error");
}
%parse_failure {
// !!! FIXME: make this a proper fail() function.
fail(ctx, "Giving up. Parser is hopelessly lost...");
}
%stack_overflow {
// !!! FIXME: make this a proper fail() function.
fail(ctx, "Giving up. Parser stack overflow");
}
// operator precedence (matches C spec)...
%left COMMA.
%right ASSIGN PLUSASSIGN MINUSASSIGN STARASSIGN SLASHASSIGN PERCENTASSIGN LSHIFTASSIGN RSHIFTASSIGN ANDASSIGN ORASSIGN XORASSIGN.
%right QUESTION.
%left OROR.
%left ANDAND.
%left OR.
%left XOR.
%left AND.
%left EQL NEQ.
%left LT LEQ GT GEQ.
%left LSHIFT RSHIFT.
%left PLUS MINUS.
%left STAR SLASH PERCENT.
%right TYPECAST EXCLAMATION COMPLEMENT MINUSMINUS PLUSPLUS.
%left DOT LBRACKET RBRACKET LPAREN RPAREN.
// bump up the precedence of ELSE, to avoid shift/reduce conflict on the
// usual "dangling else ambiguity" ...
%right ELSE.
// The rules...
// start here.
%type shader { SDL_SHADER_AstShader * }
%destructor shader { delete_shader(ctx, $$); }
shader ::= translation_unit_list(B). { SDL_assert(!ctx->shader); ctx->shader = new_shader(ctx, B); }
%type translation_unit_list { SDL_SHADER_AstTranslationUnits * }
%destructor translation_unit_list { delete_translation_units(ctx, $$); }
translation_unit_list(A) ::= translation_unit(B). { A = new_translation_units(ctx, B); }
translation_unit_list(A) ::= translation_unit_list(B) translation_unit(C). { B->tail->next = C; B->tail = C; A = B; }
// At the top level of the shader, it's only struct declarations and
// functions at the moment. This will likely expand to other things.
%type translation_unit { SDL_SHADER_AstTranslationUnit * }
%destructor translation_unit { delete_translation_unit(ctx, $$); }
translation_unit(A) ::= struct_declaration(B). { A = new_struct_declaration_unit(ctx, B); }
translation_unit(A) ::= function(B). { A = new_function_unit(ctx, B); }
// !!! FIXME: allow global variables?
// !!! FIXME: allow typedefs?
%type at_attrib { SDL_SHADER_AstAtAttribute * }
%destructor at_attrib { delete_at_attribute(ctx, $$); }
at_attrib(A) ::= AT IDENTIFIER(B). { A = new_at_attribute(ctx, B.string, NULL); }
at_attrib(A) ::= AT IDENTIFIER(B) LPAREN INT_CONSTANT(C) RPAREN. { A = new_at_attribute(ctx, B.string, &C.i64); } // this will likely expand later.
%type struct_declaration { SDL_SHADER_AstStructDeclaration * }
%destructor struct_declaration { delete_struct_declaration(ctx, $$); }
struct_declaration(A) ::= STRUCT IDENTIFIER(B) LBRACE struct_member_list(C) RBRACE SEMICOLON. { A = new_struct_declaration(ctx, B.string, C); }
%type struct_member_list { SDL_SHADER_AstStructMembers * }
%destructor struct_member_list { delete_struct_members(ctx, $$); }
struct_member_list(A) ::= struct_member(B). { A = new_struct_members(ctx, B); }
struct_member_list(A) ::= struct_member_list(B) struct_member(C). { B->tail->next = C; B->tail = C; A = B; }
// the first identifier is a datatype, but it might be a user-defined struct. To simplify the
// grammar, we don't treat the many built-in types as unique tokens or have a USERTYPE token,
// and let semantic analysis sort it out.
// array size can be an expression, as long as it folds down to a constant int.
%type struct_member { SDL_SHADER_AstStructMember * }
%destructor struct_member { delete_struct_member(ctx, $$); }
struct_member(A) ::= var_declaration(B) SEMICOLON. { A = new_struct_member(ctx, B); }
%type function { SDL_SHADER_AstFunction * }
%destructor function { delete_function(ctx, $$); }
function(A) ::= FUNCTION return_type(B) IDENTIFIER(C) function_params(D) statement_block(E). { A = new_function(ctx, 1, B, C.string, D, NULL, E); }
function(A) ::= FUNCTION at_attrib(B) return_type(C) IDENTIFIER(D) function_params(E) statement_block(F). { A = new_function(ctx, 1, C, D.string, E, B, F); }
// to keep consistent with optional "myvar : mytype" declarations, we let you do "function x (params) : rettype" too.
function(A) ::= FUNCTION IDENTIFIER(B) function_params(C) COLON return_type(D) statement_block(E). { A = new_function(ctx, 0, D, B.string, C, NULL, E); }
function(A) ::= FUNCTION at_attrib(B) IDENTIFIER(C) function_params(D) COLON return_type(E) statement_block(F). { A = new_function(ctx, 0, E, C.string, D, B, F); }
%type return_type { const char * }
%destructor return_type {} // these are NULL or strcache'd, don't free them.
return_type(A) ::= VOID(B). { A = B.string; }
return_type(A) ::= IDENTIFIER(B). { A = B.string; } // let semantic analysis figure it out.
%type function_params { SDL_SHADER_AstFunctionParams * }
%destructor function_params { delete_function_params(ctx, $$); }
function_params(A) ::= LPAREN RPAREN. { A = NULL; }
function_params(A) ::= LPAREN VOID RPAREN. { A = NULL; }
function_params(A) ::= LPAREN function_param_list(B) RPAREN. { A = B; }
%type function_param_list { SDL_SHADER_AstFunctionParams * }
%destructor function_param_list { delete_function_params(ctx, $$); }
function_param_list(A) ::= var_declaration(B). { A = new_function_params(ctx, new_function_param(ctx, B)); }
function_param_list(A) ::= function_param_list(B) COMMA var_declaration(C). { B->tail->next = new_function_param(ctx, C); B->tail = B->tail->next; A = B; }
%type statement_block { SDL_SHADER_AstStatementBlock * }
%destructor statement_block { delete_statement_block(ctx, $$); }
statement_block(A) ::= LBRACE RBRACE. { A = new_statement_block(ctx, NULL); }
statement_block(A) ::= LBRACE statement_list(B) RBRACE. { A = B; }
%type statement_list { SDL_SHADER_AstStatementBlock * }
%destructor statement_list { delete_statement_block(ctx, $$); }
statement_list(A) ::= statement(B). { A = new_statement_block(ctx, B); }
statement_list(A) ::= statement_list(B) statement(C). { B->tail->next = C; B->tail = C; A = B; }
%type statement { SDL_SHADER_AstStatement * }
%destructor statement { delete_statement(ctx, $$); }
statement(A) ::= SEMICOLON. { A = new_empty_statement(ctx); }
statement(A) ::= BREAK SEMICOLON. { A = new_break_statement(ctx); }
statement(A) ::= CONTINUE SEMICOLON. { A = new_continue_statement(ctx); }
statement(A) ::= DISCARD SEMICOLON. { A = new_discard_statement(ctx); } // obviously only valid in fragment shaders; semantic analysis will check that.
statement(A) ::= VAR var_declaration_statement(B) SEMICOLON. { A = B; }
statement(A) ::= DO statement_block(B) WHILE expression(C) SEMICOLON. { A = new_do_statement(ctx, B, C); }
statement(A) ::= WHILE expression(B) statement_block(C). { A = new_while_statement(ctx, B, C); }
statement(A) ::= FOR LPAREN for_details(B) RPAREN statement_block(C). { A = new_for_statement(ctx, B, C); }
statement(A) ::= FOR for_details(B) statement_block(C). { A = new_for_statement(ctx, B, C); }
statement(A) ::= IF expression(B) statement_block(C). { A = new_if_statement(ctx, B, C, NULL); }
statement(A) ::= IF expression(B) statement_block(C) ELSE statement_block(D). { A = new_if_statement(ctx, B, C, D); }
//statement(A) ::= SWITCH expression(B) LBRACE switch_case_list(C) RBRACE. { A = new_switch_statement(ctx, B, C); }
// NO EXPRESSIONS AS STANDALONE STATEMENTS! statement(A) ::= expression(B) SEMICOLON.
statement(A) ::= RETURN SEMICOLON. { A = new_return_statement(ctx, NULL); }
statement(A) ::= RETURN expression(B) SEMICOLON. { A = new_return_statement(ctx, B); }
statement(A) ::= assignment_statement(B) SEMICOLON. { A = B; } // created in assignment_statement
statement(A) ::= compound_assignment_statement(B) SEMICOLON. { A = B; } // created in compound_assignment_statement
statement(A) ::= increment_statement(B) SEMICOLON. { A = B; } // created in increment_statement
statement(A) ::= function_call_statement(B) SEMICOLON. { A = B; } // created in function_call_statement
statement(A) ::= statement_block(B). { A = (SDL_SHADER_AstStatement *) B; }
//statement(A) ::= error SEMICOLON. { A = NULL; } // !!! FIXME: research using the error nonterminal
%type var_declaration_statement { SDL_SHADER_AstStatement * }
%destructor var_declaration_statement { delete_statement(ctx, $$); }
var_declaration_statement(A) ::= var_declaration(B). { A = new_var_declaration_statement(ctx, B, NULL); }
var_declaration_statement(A) ::= var_declaration(B) ASSIGN expression(C). { A = new_var_declaration_statement(ctx, B, C); }
// assignment is a statement, not an expression (although we tapdance to make this work with a C-like for loop syntax),
// which solves a nasty class of bugs in C programs for not much loss in power.
// We allow multiple assignments for JUST the '=' operator, as syntactic sugar without it being a chain of assignment expressions.
%type assignment_statement { SDL_SHADER_AstStatement * }
%destructor assignment_statement { delete_statement(ctx, $$); }
assignment_statement(A) ::= assignment_statement_list(B) expression(C). { A = new_assignment_statement(ctx, B, C); }
%type assignment_statement_list { SDL_SHADER_AstAssignments * }
%destructor assignment_statement_list { delete_assignments(ctx, $$); }
assignment_statement_list(A) ::= expression(B) ASSIGN. { A = new_assignments(ctx, new_assignment(ctx, B)); }
assignment_statement_list(A) ::= assignment_statement_list(B) expression(C) ASSIGN. { B->tail->next = new_assignment(ctx, C); B->tail = B->tail->next; A = B; }
// Compound assignment operators ("+=", "-=", etc) are also statements, but don't allow multiple assignments, because that wouldn't make sense.
%type compound_assignment_statement { SDL_SHADER_AstStatement * }
%destructor compound_assignment_statement { delete_statement(ctx, $$); }
compound_assignment_statement(A) ::= expression(B) compound_assignment_operator(C) expression(D). { A = new_compound_assignment_statement(ctx, B, C, D); }
%type compound_assignment_operator { SDL_SHADER_AstNodeType }
compound_assignment_operator(A) ::= PLUSASSIGN. { A = SDL_SHADER_AST_STATEMENT_COMPOUNDASSIGNADD; }
compound_assignment_operator(A) ::= MINUSASSIGN. { A = SDL_SHADER_AST_STATEMENT_COMPOUNDASSIGNSUB; }
compound_assignment_operator(A) ::= STARASSIGN. { A = SDL_SHADER_AST_STATEMENT_COMPOUNDASSIGNMUL; }
compound_assignment_operator(A) ::= SLASHASSIGN. { A = SDL_SHADER_AST_STATEMENT_COMPOUNDASSIGNDIV; }
compound_assignment_operator(A) ::= PERCENTASSIGN. { A = SDL_SHADER_AST_STATEMENT_COMPOUNDASSIGNMOD; }
compound_assignment_operator(A) ::= LSHIFTASSIGN. { A = SDL_SHADER_AST_STATEMENT_COMPOUNDASSIGNLSHIFT; }
compound_assignment_operator(A) ::= RSHIFTASSIGN. { A = SDL_SHADER_AST_STATEMENT_COMPOUNDASSIGNRSHIFT; }
compound_assignment_operator(A) ::= ANDASSIGN. { A = SDL_SHADER_AST_STATEMENT_COMPOUNDASSIGNAND; }
compound_assignment_operator(A) ::= ORASSIGN. { A = SDL_SHADER_AST_STATEMENT_COMPOUNDASSIGNOR; }
compound_assignment_operator(A) ::= XORASSIGN. { A = SDL_SHADER_AST_STATEMENT_COMPOUNDASSIGNXOR; }
// "x++" and friends are allowed as standalone statements, and not expressions.
%type increment_statement { SDL_SHADER_AstStatement * }
%destructor increment_statement { delete_statement(ctx, $$); }
increment_statement(A) ::= PLUSPLUS expression(B). { A = new_preincrement_statement(ctx, B); }
increment_statement(A) ::= MINUSMINUS expression(B). { A = new_predecrement_statement(ctx, B); }
increment_statement(A) ::= expression(B) PLUSPLUS. { A = new_postincrement_statement(ctx, B); }
increment_statement(A) ::= expression(B) MINUSMINUS. { A = new_postdecrement_statement(ctx, B); }
// "myfunction()" is allowed in expressions, but can also be used as a standalone statement.
%type function_call_statement { SDL_SHADER_AstStatement * }
%destructor function_call_statement { delete_statement(ctx, $$); }
function_call_statement(A) ::= IDENTIFIER(B) arguments(C). { A = new_fncall_statement(ctx, B.string, C); }
%type for_details { SDL_SHADER_AstForDetails * }
%destructor for_details { delete_for_details(ctx, $$); }
for_details(A) ::= for_initializer(B) SEMICOLON expression(C) SEMICOLON for_step(D). { A = new_for_details(ctx, B, C, D); }
for_details(A) ::= for_initializer(B) SEMICOLON SEMICOLON for_step(C). { A = new_for_details(ctx, B, NULL, C); }
%type for_initializer { SDL_SHADER_AstStatement * }
%destructor for_initializer { delete_statement(ctx, $$); }
for_initializer(A) ::= VAR var_declaration_statement(B). { A = B; }
for_initializer(A) ::= assignment_statement(B). { A = B; }
for_initializer(A) ::= compound_assignment_statement(B). { A = B; }
for_initializer(A) ::= increment_statement(B). { A = B; }
for_initializer(A) ::= . { A = NULL; }
%type for_step { SDL_SHADER_AstStatement * }
%destructor for_step { delete_statement(ctx, $$); }
for_step(A) ::= assignment_statement(B). { A = B; }
for_step(A) ::= compound_assignment_statement(B). { A = B; }
for_step(A) ::= increment_statement(B). { A = B; }
for_step(A) ::= function_call_statement(B). { A = B; }
for_step(A) ::= . { A = NULL; }
// `switch` and `case` are removed from the language, for now, but I might readd it later.
//%type switch_case_list { SDL_SHADER_AstSwitchCases * }
//%destructor switch_case_list { delete_switch_cases(ctx, $$); }
//switch_case_list(A) ::= switch_case(B). { A = new_switch_cases(ctx, B); }
//switch_case_list(A) ::= switch_case_list(B) switch_case(C). { B->tail->next = C; B->tail = C; A = B; }
//// You can do math here, as long as it produces an int constant.
//// ...so "case 3+2:" works.
//%type switch_case { SDL_SHADER_AstSwitchCase * }
//%destructor switch_case { delete_switch_case(ctx, $$); }
//switch_case(A) ::= CASE expression(B) COLON statement(C). { A = new_switch_case(ctx, B, C); }
//switch_case(A) ::= CASE expression(B) COLON. { A = new_switch_case(ctx, B, NULL); }
//switch_case(A) ::= DEFAULT COLON statement(B). { A = new_switch_case(ctx, NULL, B); }
//switch_case(A) ::= DEFAULT COLON. { A = new_switch_case(ctx, NULL, NULL); }
// one identifier is a datatype, but it might be a user-defined struct. To simplify the
// grammar, we don't treat the many built-in types as unique tokens or have a USERTYPE token,
// and let semantic analysis sort it out later.
%type var_declaration { SDL_SHADER_AstVarDeclaration * }
%destructor var_declaration { delete_var_declaration(ctx, $$); }
var_declaration(A) ::= IDENTIFIER(B) IDENTIFIER(C). { A = new_var_declaration(ctx, 1, B.string, C.string, NULL, NULL); }
var_declaration(A) ::= IDENTIFIER(B) IDENTIFIER(C) at_attrib(D). { A = new_var_declaration(ctx, 1, B.string, C.string, NULL, D); }
var_declaration(A) ::= IDENTIFIER(B) IDENTIFIER(C) array_bounds_list(D). { A = new_var_declaration(ctx, 1, B.string, C.string, D, NULL); }
var_declaration(A) ::= IDENTIFIER(B) IDENTIFIER(C) array_bounds_list(D) at_attrib(E). { A = new_var_declaration(ctx, 1, B.string, C.string, D, E); }
// We let you do "var int i;" or "var i: int;"
var_declaration(A) ::= IDENTIFIER(B) COLON IDENTIFIER(C). { A = new_var_declaration(ctx, 0, C.string, B.string, NULL, NULL); }
var_declaration(A) ::= IDENTIFIER(B) COLON IDENTIFIER(C) at_attrib(D). { A = new_var_declaration(ctx, 0, C.string, B.string, NULL, D); }
var_declaration(A) ::= IDENTIFIER(B) COLON IDENTIFIER(C) array_bounds_list(D). { A = new_var_declaration(ctx, 0, C.string, B.string, D, NULL); }
var_declaration(A) ::= IDENTIFIER(B) COLON IDENTIFIER(C) array_bounds_list(D) at_attrib(E). { A = new_var_declaration(ctx, 0, C.string, B.string, D, E); }
%type array_bounds_list { SDL_SHADER_AstArrayBoundsList * }
%destructor array_bounds_list { delete_array_bounds_list(ctx, $$); }
array_bounds_list(A) ::= array_bounds(B). { A = new_array_bounds_list(ctx, B); }
array_bounds_list(A) ::= array_bounds_list(B) array_bounds(C). { B->tail->next = C; B->tail = C; A = B; }
%type array_bounds { SDL_SHADER_AstArrayBounds * }
%destructor array_bounds { delete_array_bounds(ctx, $$); }
array_bounds(A) ::= LBRACKET expression(B) RBRACKET. { A = new_array_bounds(ctx, B); }
%type arguments { SDL_SHADER_AstArguments * }
%destructor arguments { delete_arguments(ctx, $$); }
arguments(A) ::= LPAREN RPAREN. { A = NULL; }
arguments(A) ::= LPAREN argument_list(B) RPAREN. { A = B; }
%type argument_list { SDL_SHADER_AstArguments * }
%destructor argument_list { delete_arguments(ctx, $$); }
argument_list(A) ::= expression(B). { A = new_arguments(ctx, new_argument(ctx, B)); }
argument_list(A) ::= argument_list(B) COMMA expression(C). { B->tail->next = new_argument(ctx, C); B->tail = B->tail->next; A = B; }
// here we go.
%type expression { SDL_SHADER_AstExpression * }
%destructor expression { delete_expression(ctx, $$); }
expression(A) ::= IDENTIFIER(B). { A = new_identifier_expression(ctx, B.string); }
expression(A) ::= INT_CONSTANT(B). { A = new_int_expression(ctx, B.i64); }
expression(A) ::= FLOAT_CONSTANT(B). { A = new_float_expression(ctx, B.dbl); }
expression(A) ::= TRUE. { A = new_bool_expression(ctx, 1); }
expression(A) ::= FALSE. { A = new_bool_expression(ctx, 0); }
expression(A) ::= LPAREN expression(B) RPAREN. { A = new_parentheses_expression(ctx, B); }
expression(A) ::= IDENTIFIER(B) arguments(C). { A = new_fncall_expression(ctx, B.string, C); } // this might be a function call or datatype constructor; semantic analysis will figure that out!
expression(A) ::= PLUS expression(B). { A = new_unaryplus_expression(ctx, B); }
expression(A) ::= MINUS expression(B). { A = new_unaryminus_expression(ctx, B); }
expression(A) ::= COMPLEMENT expression(B). { A = new_unarycompl_expression(ctx, B); }
expression(A) ::= EXCLAMATION expression(B). { A = new_unarynot_expression(ctx, B); }
expression(A) ::= expression(B) STAR expression(C). { A = new_multiply_expression(ctx, B, C); }
expression(A) ::= expression(B) SLASH expression(C). { A = new_divide_expression(ctx, B, C); }
expression(A) ::= expression(B) PERCENT expression(C). { A = new_mod_expression(ctx, B, C); }
expression(A) ::= expression(B) PLUS expression(C). { A = new_addition_expression(ctx, B, C); }
expression(A) ::= expression(B) MINUS expression(C). { A = new_subtraction_expression(ctx, B, C); }
expression(A) ::= expression(B) LSHIFT expression(C). { A = new_lshift_expression(ctx, B, C); }
expression(A) ::= expression(B) RSHIFT expression(C). { A = new_rshift_expression(ctx, B, C); }
expression(A) ::= expression(B) LT expression(C). { A = new_lt_expression(ctx, B, C); }
expression(A) ::= expression(B) GT expression(C). { A = new_gt_expression(ctx, B, C); }
expression(A) ::= expression(B) LEQ expression(C). { A = new_leq_expression(ctx, B, C); }
expression(A) ::= expression(B) GEQ expression(C). { A = new_geq_expression(ctx, B, C); }
expression(A) ::= expression(B) EQL expression(C). { A = new_eql_expression(ctx, B, C); }
expression(A) ::= expression(B) NEQ expression(C). { A = new_neq_expression(ctx, B, C); }
expression(A) ::= expression(B) AND expression(C). { A = new_and_expression(ctx, B, C); }
expression(A) ::= expression(B) XOR expression(C). { A = new_xor_expression(ctx, B, C); }
expression(A) ::= expression(B) OR expression(C). { A = new_or_expression(ctx, B, C); }
expression(A) ::= expression(B) ANDAND expression(C). { A = new_andand_expression(ctx, B, C); }
expression(A) ::= expression(B) OROR expression(C). { A = new_oror_expression(ctx, B, C); }
expression(A) ::= expression(B) QUESTION expression(C) COLON expression(D). { A = new_conditional_expression(ctx, B, C, D); }
expression(A) ::= expression(B) LBRACKET expression(C) RBRACKET. { A = new_array_dereference_expression(ctx, B, C); }
expression(A) ::= expression(B) DOT IDENTIFIER(C). { A = new_struct_dereference_expression(ctx, B, C.string); } // might be a struct deref or a swizzle, semantic analysis will decide.
/* end of SDL_shader_parser.lemon ... */