/
mojoshader_compiler.c
3503 lines (3034 loc) · 125 KB
1
2
3
4
5
6
7
8
9
/**
* MojoShader; generate shader programs from bytecode of compiled
* Direct3D shaders.
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
10
11
12
13
// !!! FIXME: this needs to be split into separate source files:
// !!! FIXME: parse, AST, IR, etc. The problem is we need to deal with the
// !!! FIXME: "Context" struct being passed around everywhere.
14
15
#define __MOJOSHADER_INTERNAL__ 1
#include "mojoshader_internal.h"
16
17
18
19
20
#if DEBUG_COMPILER_PARSER
#define LEMON_SUPPORT_TRACING 1
#endif
21
22
// !!! FIXME: I'd like to lose this. It's really inefficient. Just keep a
// !!! FIXME: (tail) on these list structures instead?
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#define REVERSE_LINKED_LIST(typ, head) { \
if ((head) && (head->next)) { \
typ *tmp = NULL; \
typ *tmp1 = NULL; \
while (head != NULL) { \
tmp = head; \
head = head->next; \
tmp->next = tmp1; \
tmp1 = tmp; \
} \
head = tmp; \
} \
}
37
static inline int operator_is_unary(const MOJOSHADER_astNodeType op)
38
{
39
40
return ( (op > MOJOSHADER_AST_OP_START_RANGE_UNARY) &&
(op < MOJOSHADER_AST_OP_END_RANGE_UNARY) );
41
42
} // operator_is_unary
43
static inline int operator_is_binary(const MOJOSHADER_astNodeType op)
44
{
45
46
return ( (op > MOJOSHADER_AST_OP_START_RANGE_BINARY) &&
(op < MOJOSHADER_AST_OP_END_RANGE_BINARY) );
47
48
} // operator_is_binary
49
static inline int operator_is_ternary(const MOJOSHADER_astNodeType op)
50
{
51
52
return ( (op > MOJOSHADER_AST_OP_START_RANGE_TERNARY) &&
(op < MOJOSHADER_AST_OP_END_RANGE_TERNARY) );
53
54
55
} // operator_is_ternary
56
typedef union TokenData
57
{
58
59
int64 i64;
double dbl;
60
const char *string;
61
const MOJOSHADER_astDataType *datatype;
62
} TokenData;
63
64
65
// This tracks data types and variables, and notes when they enter/leave scope.
66
67
typedef struct SymbolScope
68
69
{
const char *symbol;
70
const MOJOSHADER_astDataType *datatype;
71
int index; // unique positive value within a function, negative if global.
72
73
struct SymbolScope *next;
} SymbolScope;
74
75
typedef struct SymbolMap
76
{
77
78
79
HashTable *hash;
SymbolScope *scope;
} SymbolMap;
80
81
82
83
84
85
86
87
88
89
90
91
// Compile state, passed around all over the place.
typedef struct Context
{
int isfail;
int out_of_memory;
MOJOSHADER_malloc malloc;
MOJOSHADER_free free;
void *malloc_data;
ErrorList *errors;
92
ErrorList *warnings;
93
StringCache *strcache;
94
95
const char *sourcefile; // current source file that we're parsing.
unsigned int sourceline; // current line in sourcefile that we're parsing.
96
97
SymbolMap usertypes;
SymbolMap variables;
98
MOJOSHADER_astNode *ast; // Abstract Syntax Tree
99
const char *source_profile;
100
101
102
int is_func_scope; // non-zero if semantic analysis is in function scope.
int var_index; // next variable index for current function.
int global_var_index; // next variable index for global scope.
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
// Cache intrinsic types for fast lookup and consistent pointer values.
MOJOSHADER_astDataType dt_bool;
MOJOSHADER_astDataType dt_int;
MOJOSHADER_astDataType dt_uint;
MOJOSHADER_astDataType dt_float;
MOJOSHADER_astDataType dt_float_snorm;
MOJOSHADER_astDataType dt_float_unorm;
MOJOSHADER_astDataType dt_half;
MOJOSHADER_astDataType dt_double;
MOJOSHADER_astDataType dt_string;
MOJOSHADER_astDataType dt_sampler1d;
MOJOSHADER_astDataType dt_sampler2d;
MOJOSHADER_astDataType dt_sampler3d;
MOJOSHADER_astDataType dt_samplercube;
MOJOSHADER_astDataType dt_samplerstate;
MOJOSHADER_astDataType dt_samplercompstate;
MOJOSHADER_astDataType dt_buf_bool;
MOJOSHADER_astDataType dt_buf_int;
MOJOSHADER_astDataType dt_buf_uint;
MOJOSHADER_astDataType dt_buf_half;
MOJOSHADER_astDataType dt_buf_float;
MOJOSHADER_astDataType dt_buf_double;
MOJOSHADER_astDataType dt_buf_float_snorm;
MOJOSHADER_astDataType dt_buf_float_unorm;
Buffer *garbage; // this is sort of hacky.
130
131
132
} Context;
133
134
135
136
// !!! FIXME: cut and paste between every damned source file follows...
// !!! FIXME: We need to make some sort of ContextBase that applies to all
// !!! FIXME: files and move this stuff to mojoshader_common.c ...
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
// Convenience functions for allocators...
static inline void out_of_memory(Context *ctx)
{
ctx->isfail = ctx->out_of_memory = 1;
} // out_of_memory
static inline void *Malloc(Context *ctx, const size_t len)
{
void *retval = ctx->malloc((int) len, ctx->malloc_data);
if (retval == NULL)
out_of_memory(ctx);
return retval;
} // Malloc
static inline char *StrDup(Context *ctx, const char *str)
{
char *retval = (char *) Malloc(ctx, strlen(str) + 1);
if (retval != NULL)
strcpy(retval, str);
return retval;
} // StrDup
static inline void Free(Context *ctx, void *ptr)
{
162
ctx->free(ptr, ctx->malloc_data);
163
164
} // Free
165
166
167
168
169
170
171
172
173
174
static void *MallocBridge(int bytes, void *data)
{
return Malloc((Context *) data, (size_t) bytes);
} // MallocBridge
static void FreeBridge(void *ptr, void *data)
{
Free((Context *) data, ptr);
} // FreeBridge
175
176
177
178
static void failf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3);
static void failf(Context *ctx, const char *fmt, ...)
{
ctx->isfail = 1;
179
if (ctx->out_of_memory)
180
181
182
183
return;
va_list ap;
va_start(ap, fmt);
184
errorlist_add_va(ctx->errors, ctx->sourcefile, ctx->sourceline, fmt, ap);
185
186
187
188
va_end(ap);
} // failf
static inline void fail(Context *ctx, const char *reason)
189
{
190
failf(ctx, "%s", reason);
191
} // fail
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
static void warnf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3);
static void warnf(Context *ctx, const char *fmt, ...)
{
if (ctx->out_of_memory)
return;
va_list ap;
va_start(ap, fmt);
errorlist_add_va(ctx->warnings, ctx->sourcefile, ctx->sourceline, fmt, ap);
va_end(ap);
} // warnf
static inline void warn(Context *ctx, const char *reason)
{
warnf(ctx, "%s", reason);
} // warn
210
211
212
213
214
static inline int isfail(const Context *ctx)
{
return ctx->isfail;
} // isfail
215
216
static void symbolmap_nuke(const void *k, const void *v, void *d) {/*no-op*/}
217
218
static int create_symbolmap(Context *ctx, SymbolMap *map)
219
{
220
// !!! FIXME: should compare string pointer, with string in cache.
221
map->scope = NULL;
222
map->hash = hash_create(ctx, hash_hash_string, hash_keymatch_string,
223
224
symbolmap_nuke, 1, MallocBridge, FreeBridge, ctx);
return (map->hash != NULL);
225
} // create_symbolmap
226
227
228
229
static void push_symbol(Context *ctx, SymbolMap *map, const char *sym,
const MOJOSHADER_astDataType *dt, const int index)
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
// Decide if this symbol is defined, and if it's in the current scope.
SymbolScope *item = NULL;
const void *value = NULL;
void *iter = NULL;
if ((sym != NULL) && (hash_iter(map->hash, sym, &value, &iter)))
{
item = (SymbolScope *) value;
// Functions are always global, so no need to search scopes.
// !!! FIXME: Functions overload, though, so we have to continue
// !!! FIXME: iterating to see if it matches anything.
//const MOJOSHADER_astDataType *dt = item->datatype;
//if (dt->type == MOJOSHADER_AST_DATATYPE_FUNCTION)
//{
//} // if
//else // check the current scope for a dupe.
{
item = map->scope;
while ((item) && (item->symbol))
{
if (strcmp(item->symbol, sym) == 0)
{
failf(ctx, "Symbol '%s' already defined", sym);
return;
} // if
item = item->next;
} // while
} // else
} // if
259
260
261
// Add the symbol to our map and scope stack.
item = (SymbolScope *) Malloc(ctx, sizeof (SymbolScope));
262
263
264
if (item == NULL)
return;
265
if (sym != NULL) // sym can be NULL if we're pushing a new scope.
266
{
267
if (hash_insert(map->hash, sym, item) == -1)
268
269
270
{
Free(ctx, item);
return;
271
} // if
272
273
274
} // if
item->symbol = sym; // cached strings, don't copy.
275
item->index = index;
276
item->datatype = dt;
277
278
item->next = map->scope;
map->scope = item;
279
280
} // push_symbol
281
static void push_usertype(Context *ctx, const char *sym, const MOJOSHADER_astDataType *dt)
282
{
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
if (sym != NULL)
{
MOJOSHADER_astDataType *userdt;
userdt = (MOJOSHADER_astDataType *) Malloc(ctx, sizeof (*userdt));
if (userdt != NULL)
{
// !!! FIXME: this is hacky.
if (!buffer_append(ctx->garbage, &userdt, sizeof (userdt)))
{
Free(ctx, userdt);
userdt = NULL;
} // if
userdt->type = MOJOSHADER_AST_DATATYPE_USER;
userdt->user.details = dt;
userdt->user.name = sym;
dt = userdt;
} // if
} // if
304
push_symbol(ctx, &ctx->usertypes, sym, dt, 0);
305
306
} // push_usertype
307
static inline void push_variable(Context *ctx, const char *sym, const MOJOSHADER_astDataType *dt)
308
{
309
310
311
312
313
314
315
316
317
318
int idx = 0;
if (sym != NULL)
{
if (ctx->is_func_scope)
idx = ++ctx->var_index; // these are positive.
else
idx = --ctx->global_var_index; // these are negative.
} // if
push_symbol(ctx, &ctx->variables, sym, dt, idx);
319
320
321
322
323
324
325
326
327
} // push_variable
static inline void push_scope(Context *ctx)
{
push_usertype(ctx, NULL, NULL);
push_variable(ctx, NULL, NULL);
} // push_scope
static void pop_symbol(Context *ctx, SymbolMap *map)
328
{
329
SymbolScope *item = map->scope;
330
331
332
if (!item)
return;
if (item->symbol)
333
hash_remove(map->hash, item->symbol);
334
335
map->scope = item->next;
Free(ctx, item);
336
} // pop_symbol
337
338
static void pop_symbol_scope(Context *ctx, SymbolMap *map)
339
340
{
while ((map->scope) && (map->scope->symbol))
341
pop_symbol(ctx, map);
342
343
344
assert(map->scope != NULL);
assert(map->scope->symbol == NULL);
345
346
347
348
349
350
351
pop_symbol(ctx, map);
} // pop_symbol_scope
static inline void pop_scope(Context *ctx)
{
pop_symbol_scope(ctx, &ctx->usertypes);
pop_symbol_scope(ctx, &ctx->variables);
352
353
} // push_scope
354
static const MOJOSHADER_astDataType *find_symbol(Context *ctx, SymbolMap *map, const char *sym, int *_index)
355
{
356
357
const void *_item = NULL;
hash_find(map->hash, sym, &_item);
358
SymbolScope *item = (SymbolScope *) _item;
359
360
361
if (item && _index)
*_index = item->index;
return item ? item->datatype : NULL;
362
363
} // find_symbol
364
static inline const MOJOSHADER_astDataType *find_usertype(Context *ctx, const char *sym)
365
{
366
return find_symbol(ctx, &ctx->usertypes, sym, NULL);
367
368
} // find_usertype
369
static inline const MOJOSHADER_astDataType *find_variable(Context *ctx, const char *sym, int *_index)
370
{
371
return find_symbol(ctx, &ctx->variables, sym, _index);
372
373
} // find_variable
374
static void destroy_symbolmap(Context *ctx, SymbolMap *map)
375
376
{
while (map->scope)
377
pop_symbol(ctx, map);
378
379
hash_destroy(map->hash);
} // destroy_symbolmap
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
static const MOJOSHADER_astDataType *new_datatype_vector(Context *ctx,
const MOJOSHADER_astDataType *dt,
const int columns)
{
MOJOSHADER_astDataType *retval;
retval = (MOJOSHADER_astDataType *) Malloc(ctx, sizeof (*retval));
if (retval == NULL)
return NULL;
// !!! FIXME: this is hacky.
// !!! FIXME: I'd like to cache these anyhow and reuse types.
if (!buffer_append(ctx->garbage, &retval, sizeof (retval)))
{
Free(ctx, retval);
return NULL;
} // if
if ((columns < 1) || (columns > 4))
fail(ctx, "Vector must have between 1 and 4 elements");
retval->type = MOJOSHADER_AST_DATATYPE_VECTOR;
retval->vector.base = dt;
retval->vector.elements = columns;
return retval;
} // new_datatype_vector
static const MOJOSHADER_astDataType *new_datatype_matrix(Context *ctx,
const MOJOSHADER_astDataType *dt,
const int rows, const int columns)
{
MOJOSHADER_astDataType *retval;
// !!! FIXME: allocate enough for a matrix, but we need to cleanup things that copy without checking for subsize.
retval = (MOJOSHADER_astDataType *) Malloc(ctx, sizeof (*retval));
if (retval == NULL)
return NULL;
// !!! FIXME: this is hacky.
// !!! FIXME: I'd like to cache these anyhow and reuse types.
if (!buffer_append(ctx->garbage, &retval, sizeof (retval)))
{
Free(ctx, retval);
return NULL;
} // if
if ((rows < 1) || (rows > 4))
fail(ctx, "Matrix must have between 1 and 4 rows");
if ((columns < 1) || (columns > 4))
fail(ctx, "Matrix must have between 1 and 4 columns");
retval->type = MOJOSHADER_AST_DATATYPE_MATRIX;
retval->matrix.base = dt;
retval->matrix.rows = rows;
retval->matrix.columns = columns;
return retval;
} // new_datatype_matrix
// !!! FIXME: move this to mojoshader_ast.c
440
441
// !!! FIXME: new_* and delete_* should take an allocator, not a context.
442
443
444
445
446
// These functions are mostly for construction and cleanup of nodes in the
// parse tree. Mostly this is simple allocation and initialization, so we
// can do as little in the lemon code as possible, and then sort it all out
// afterwards.
447
#define NEW_AST_NODE(retval, cls, typ) \
448
cls *retval = (cls *) Malloc(ctx, sizeof (cls)); \
449
450
451
452
453
454
455
456
do { \
if (retval == NULL) { return NULL; } \
retval->ast.type = typ; \
retval->ast.filename = ctx->sourcefile; \
retval->ast.line = ctx->sourceline; \
} while (0)
#define DELETE_AST_NODE(cls) do { \
457
458
459
if (!cls) return; \
} while (0)
460
461
462
static void delete_compilation_unit(Context*, MOJOSHADER_astCompilationUnit*);
static void delete_statement(Context *ctx, MOJOSHADER_astStatement *stmt);
463
464
465
466
static MOJOSHADER_astExpression *new_callfunc_expr(Context *ctx,
MOJOSHADER_astExpression *identifier,
MOJOSHADER_astArguments *args)
467
{
468
469
NEW_AST_NODE(retval, MOJOSHADER_astExpressionCallFunction,
MOJOSHADER_AST_OP_CALLFUNC);
470
471
retval->identifier = identifier;
retval->args = args;
472
return (MOJOSHADER_astExpression *) retval;
473
474
} // new_callfunc_expr
475
static MOJOSHADER_astExpression *new_constructor_expr(Context *ctx,
476
477
const MOJOSHADER_astDataType *dt,
MOJOSHADER_astArguments *args)
478
{
479
480
NEW_AST_NODE(retval, MOJOSHADER_astExpressionConstructor,
MOJOSHADER_AST_OP_CONSTRUCTOR);
481
retval->datatype = dt;
482
retval->args = args;
483
return (MOJOSHADER_astExpression *) retval;
484
485
} // new_constructor_expr
486
static MOJOSHADER_astExpression *new_cast_expr(Context *ctx,
487
const MOJOSHADER_astDataType *dt,
488
MOJOSHADER_astExpression *operand)
489
{
490
NEW_AST_NODE(retval, MOJOSHADER_astExpressionCast, MOJOSHADER_AST_OP_CAST);
491
retval->datatype = dt;
492
retval->operand = operand;
493
return (MOJOSHADER_astExpression *) retval;
494
495
} // new_cast_expr
496
497
498
static MOJOSHADER_astExpression *new_unary_expr(Context *ctx,
const MOJOSHADER_astNodeType op,
MOJOSHADER_astExpression *operand)
499
{
500
NEW_AST_NODE(retval, MOJOSHADER_astExpressionUnary, op);
501
502
assert(operator_is_unary(op));
retval->operand = operand;
503
return (MOJOSHADER_astExpression *) retval;
504
505
} // new_unary_expr
506
507
508
509
static MOJOSHADER_astExpression *new_binary_expr(Context *ctx,
const MOJOSHADER_astNodeType op,
MOJOSHADER_astExpression *left,
MOJOSHADER_astExpression *right)
510
{
511
NEW_AST_NODE(retval, MOJOSHADER_astExpressionBinary, op);
512
513
514
assert(operator_is_binary(op));
retval->left = left;
retval->right = right;
515
return (MOJOSHADER_astExpression *) retval;
516
517
} // new_binary_expr
518
519
520
521
522
static MOJOSHADER_astExpression *new_ternary_expr(Context *ctx,
const MOJOSHADER_astNodeType op,
MOJOSHADER_astExpression *left,
MOJOSHADER_astExpression *center,
MOJOSHADER_astExpression *right)
523
{
524
NEW_AST_NODE(retval, MOJOSHADER_astExpressionTernary, op);
525
assert(operator_is_ternary(op));
526
527
assert(op == MOJOSHADER_AST_OP_CONDITIONAL);
retval->datatype = &ctx->dt_bool;
528
529
530
retval->left = left;
retval->center = center;
retval->right = right;
531
return (MOJOSHADER_astExpression *) retval;
532
533
} // new_ternary_expr
534
535
536
static MOJOSHADER_astExpression *new_deref_struct_expr(Context *ctx,
MOJOSHADER_astExpression *identifier,
const char *member)
537
{
538
539
NEW_AST_NODE(retval, MOJOSHADER_astExpressionDerefStruct,
MOJOSHADER_AST_OP_DEREF_STRUCT);
540
541
retval->identifier = identifier;
retval->member = member; // cached; don't copy string.
542
retval->isswizzle = 0; // may change during semantic analysis.
543
return (MOJOSHADER_astExpression *) retval;
544
545
} // new_deref_struct_expr
546
547
static MOJOSHADER_astExpression *new_identifier_expr(Context *ctx,
const char *string)
548
{
549
550
NEW_AST_NODE(retval, MOJOSHADER_astExpressionIdentifier,
MOJOSHADER_AST_OP_IDENTIFIER);
551
retval->identifier = string; // cached; don't copy string.
552
return (MOJOSHADER_astExpression *) retval;
553
554
} // new_identifier_expr
555
556
static MOJOSHADER_astExpression *new_literal_int_expr(Context *ctx,
const int value)
557
{
558
559
NEW_AST_NODE(retval, MOJOSHADER_astExpressionIntLiteral,
MOJOSHADER_AST_OP_INT_LITERAL);
560
retval->datatype = &ctx->dt_int;
561
retval->value = value;
562
return (MOJOSHADER_astExpression *) retval;
563
564
} // new_literal_int_expr
565
566
static MOJOSHADER_astExpression *new_literal_float_expr(Context *ctx,
const double dbl)
567
{
568
569
NEW_AST_NODE(retval, MOJOSHADER_astExpressionFloatLiteral,
MOJOSHADER_AST_OP_FLOAT_LITERAL);
570
retval->datatype = &ctx->dt_float;
571
retval->value = dbl;
572
return (MOJOSHADER_astExpression *) retval;
573
574
} // new_literal_float_expr
575
576
static MOJOSHADER_astExpression *new_literal_string_expr(Context *ctx,
const char *string)
577
{
578
579
NEW_AST_NODE(retval, MOJOSHADER_astExpressionStringLiteral,
MOJOSHADER_AST_OP_STRING_LITERAL);
580
retval->datatype = &ctx->dt_string;
581
retval->string = string; // cached; don't copy string.
582
return (MOJOSHADER_astExpression *) retval;
583
584
} // new_literal_string_expr
585
586
static MOJOSHADER_astExpression *new_literal_boolean_expr(Context *ctx,
const int value)
587
{
588
589
NEW_AST_NODE(retval, MOJOSHADER_astExpressionBooleanLiteral,
MOJOSHADER_AST_OP_BOOLEAN_LITERAL);
590
retval->datatype = &ctx->dt_bool;
591
retval->value = value;
592
return (MOJOSHADER_astExpression *) retval;
593
} // new_literal_boolean_expr
594
595
static void delete_arguments(Context *ctx, MOJOSHADER_astArguments *args);
596
597
static void delete_expr(Context *ctx, MOJOSHADER_astExpression *_expr)
598
{
599
600
MOJOSHADER_astNode *expr = (MOJOSHADER_astNode *) _expr;
601
DELETE_AST_NODE(expr);
602
603
604
605
606
607
608
609
610
611
612
613
614
if (expr->ast.type == MOJOSHADER_AST_OP_CAST)
delete_expr(ctx, expr->cast.operand);
else if (expr->ast.type == MOJOSHADER_AST_OP_CONSTRUCTOR)
delete_arguments(ctx, expr->constructor.args);
else if (expr->ast.type == MOJOSHADER_AST_OP_DEREF_STRUCT)
delete_expr(ctx, expr->derefstruct.identifier);
else if (operator_is_unary(expr->ast.type))
delete_expr(ctx, expr->unary.operand);
615
else if (operator_is_binary(expr->ast.type))
616
{
617
618
delete_expr(ctx, expr->binary.left);
delete_expr(ctx, expr->binary.right);
619
} // else if
620
621
else if (operator_is_ternary(expr->ast.type))
622
{
623
624
625
delete_expr(ctx, expr->ternary.left);
delete_expr(ctx, expr->ternary.center);
delete_expr(ctx, expr->ternary.right);
626
} // else if
627
628
else if (expr->ast.type == MOJOSHADER_AST_OP_CALLFUNC)
629
{
630
631
delete_expr(ctx, expr->callfunc.identifier);
delete_arguments(ctx, expr->callfunc.args);
632
} // else if
633
634
635
// rest of operators don't have extra data to free.
636
637
638
Free(ctx, expr);
} // delete_expr
639
640
static MOJOSHADER_astArguments *new_argument(Context *ctx,
MOJOSHADER_astExpression *arg)
641
{
642
643
NEW_AST_NODE(retval, MOJOSHADER_astArguments, MOJOSHADER_AST_ARGUMENTS);
retval->argument = arg;
644
645
646
647
retval->next = NULL;
return retval;
} // new_argument
648
static void delete_arguments(Context *ctx, MOJOSHADER_astArguments *args)
649
650
651
652
653
654
655
{
DELETE_AST_NODE(args);
delete_arguments(ctx, args->next);
delete_expr(ctx, args->argument);
Free(ctx, args);
} // delete_arguments
656
657
static MOJOSHADER_astFunctionParameters *new_function_param(Context *ctx,
const MOJOSHADER_astInputModifier inputmod,
658
659
const MOJOSHADER_astDataType *dt,
const char *identifier, const char *semantic,
660
661
const MOJOSHADER_astInterpolationModifier interpmod,
MOJOSHADER_astExpression *initializer)
662
{
663
664
NEW_AST_NODE(retval, MOJOSHADER_astFunctionParameters,
MOJOSHADER_AST_FUNCTION_PARAMS);
665
retval->datatype = dt;
666
667
668
669
670
671
672
retval->input_modifier = inputmod;
retval->identifier = identifier;
retval->semantic = semantic;
retval->interpolation_modifier = interpmod;
retval->initializer = initializer;
retval->next = NULL;
return retval;
673
} // new_function_param
674
675
676
static void delete_function_params(Context *ctx,
MOJOSHADER_astFunctionParameters *params)
677
{
678
679
680
681
682
DELETE_AST_NODE(params);
delete_function_params(ctx, params->next);
delete_expr(ctx, params->initializer);
Free(ctx, params);
} // delete_function_params
683
684
static MOJOSHADER_astFunctionSignature *new_function_signature(Context *ctx,
685
const MOJOSHADER_astDataType *dt,
686
687
const char *identifier,
MOJOSHADER_astFunctionParameters *params)
688
{
689
690
NEW_AST_NODE(retval, MOJOSHADER_astFunctionSignature,
MOJOSHADER_AST_FUNCTION_SIGNATURE);
691
retval->datatype = dt;
692
retval->identifier = identifier;
693
retval->params = params;
694
retval->storage_class = MOJOSHADER_AST_FNSTORECLS_NONE;
695
696
697
698
retval->semantic = NULL;
return retval;
} // new_function_signature
699
700
static void delete_function_signature(Context *ctx,
MOJOSHADER_astFunctionSignature *sig)
701
702
{
DELETE_AST_NODE(sig);
703
delete_function_params(ctx, sig->params);
704
705
706
Free(ctx, sig);
} // delete_function_signature
707
708
709
static MOJOSHADER_astCompilationUnit *new_function(Context *ctx,
MOJOSHADER_astFunctionSignature *declaration,
MOJOSHADER_astStatement *definition)
710
{
711
712
NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitFunction,
MOJOSHADER_AST_COMPUNIT_FUNCTION);
713
714
715
retval->next = NULL;
retval->declaration = declaration;
retval->definition = definition;
716
return (MOJOSHADER_astCompilationUnit *) retval;
717
718
} // new_function
719
720
static void delete_function(Context *ctx,
MOJOSHADER_astCompilationUnitFunction *unitfn)
721
722
723
724
725
726
727
728
{
DELETE_AST_NODE(unitfn);
delete_compilation_unit(ctx, unitfn->next);
delete_function_signature(ctx, unitfn->declaration);
delete_statement(ctx, unitfn->definition);
Free(ctx, unitfn);
} // delete_function
729
730
731
static MOJOSHADER_astScalarOrArray *new_scalar_or_array(Context *ctx,
const char *ident, const int isvec,
MOJOSHADER_astExpression *dim)
732
{
733
734
NEW_AST_NODE(retval, MOJOSHADER_astScalarOrArray,
MOJOSHADER_AST_SCALAR_OR_ARRAY);
735
736
737
738
739
740
retval->identifier = ident;
retval->isarray = isvec;
retval->dimension = dim;
return retval;
} // new_scalar_or_array
741
static void delete_scalar_or_array(Context *ctx,MOJOSHADER_astScalarOrArray *s)
742
{
743
744
745
DELETE_AST_NODE(s);
delete_expr(ctx, s->dimension);
Free(ctx, s);
746
747
} // delete_scalar_or_array
748
static MOJOSHADER_astTypedef *new_typedef(Context *ctx, const int isconst,
749
const MOJOSHADER_astDataType *dt,
750
MOJOSHADER_astScalarOrArray *soa)
751
{
752
// we correct this datatype to the final version during semantic analysis.
753
NEW_AST_NODE(retval, MOJOSHADER_astTypedef, MOJOSHADER_AST_TYPEDEF);
754
retval->datatype = dt;
755
756
757
758
759
retval->isconst = isconst;
retval->details = soa;
return retval;
} // new_typedef
760
static void delete_typedef(Context *ctx, MOJOSHADER_astTypedef *td)
761
762
763
764
765
766
{
DELETE_AST_NODE(td);
delete_scalar_or_array(ctx, td->details);
Free(ctx, td);
} // delete_typedef
767
768
static MOJOSHADER_astPackOffset *new_pack_offset(Context *ctx,
const char *a, const char *b)
769
{
770
NEW_AST_NODE(retval, MOJOSHADER_astPackOffset, MOJOSHADER_AST_PACK_OFFSET);
771
772
773
774
775
retval->ident1 = a;
retval->ident2 = b;
return retval;
} // new_pack_offset
776
static void delete_pack_offset(Context *ctx, MOJOSHADER_astPackOffset *o)
777
778
779
780
781
{
DELETE_AST_NODE(o);
Free(ctx, o);
} // delete_pack_offset
782
783
static MOJOSHADER_astVariableLowLevel *new_variable_lowlevel(Context *ctx,
MOJOSHADER_astPackOffset *po,
784
785
const char *reg)
{
786
787
NEW_AST_NODE(retval, MOJOSHADER_astVariableLowLevel,
MOJOSHADER_AST_VARIABLE_LOWLEVEL);
788
789
790
791
792
retval->packoffset = po;
retval->register_name = reg;
return retval;
} // new_variable_lowlevel
793
794
static void delete_variable_lowlevel(Context *ctx,
MOJOSHADER_astVariableLowLevel *vll)
795
796
797
798
799
800
{
DELETE_AST_NODE(vll);
delete_pack_offset(ctx, vll->packoffset);
Free(ctx, vll);
} // delete_variable_lowlevel
801
static MOJOSHADER_astAnnotations *new_annotation(Context *ctx,
802
const MOJOSHADER_astDataType *dt,
803
MOJOSHADER_astExpression *initializer)
804
{
805
NEW_AST_NODE(retval, MOJOSHADER_astAnnotations, MOJOSHADER_AST_ANNOTATION);
806
retval->datatype = dt;
807
808
809
810
811
retval->initializer = initializer;
retval->next = NULL;
return retval;
} // new_annotation
812
static void delete_annotation(Context *ctx, MOJOSHADER_astAnnotations *annos)
813
{
814
815
816
817
DELETE_AST_NODE(annos);
delete_annotation(ctx, annos->next);
delete_expr(ctx, annos->initializer);
Free(ctx, annos);
818
819
} // delete_annotation
820
821
822
823
824
825
static MOJOSHADER_astVariableDeclaration *new_variable_declaration(
Context *ctx, MOJOSHADER_astScalarOrArray *soa,
const char *semantic,
MOJOSHADER_astAnnotations *annotations,
MOJOSHADER_astExpression *init,
MOJOSHADER_astVariableLowLevel *vll)
826
{
827
828
NEW_AST_NODE(retval, MOJOSHADER_astVariableDeclaration,
MOJOSHADER_AST_VARIABLE_DECLARATION);
829
830
831
832
833
834
835
836
837
838
839
retval->attributes = 0;
retval->anonymous_datatype = NULL;
retval->details = soa;
retval->semantic = semantic;
retval->annotations = annotations;
retval->initializer = init;
retval->lowlevel = vll;
retval->next = NULL;
return retval;
} // new_variable_declaration
840
841
static void delete_variable_declaration(Context *ctx,
MOJOSHADER_astVariableDeclaration *dcl)
842
843
844
845
846
847
848
849
850
851
{
DELETE_AST_NODE(dcl);
delete_variable_declaration(ctx, dcl->next);
delete_scalar_or_array(ctx, dcl->details);
delete_annotation(ctx, dcl->annotations);
delete_expr(ctx, dcl->initializer);
delete_variable_lowlevel(ctx, dcl->lowlevel);
Free(ctx, dcl);
} // delete_variable_declaration
852
853
static MOJOSHADER_astCompilationUnit *new_global_variable(Context *ctx,
MOJOSHADER_astVariableDeclaration *decl)
854
{
855
856
NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitVariable,
MOJOSHADER_AST_COMPUNIT_VARIABLE);
857
858
retval->next = NULL;
retval->declaration = decl;
859
return (MOJOSHADER_astCompilationUnit *) retval;
860
861
} // new_global_variable
862
863
static void delete_global_variable(Context *ctx,
MOJOSHADER_astCompilationUnitVariable *var)
864
865
866
867
868
869
870
{
DELETE_AST_NODE(var);
delete_compilation_unit(ctx, var->next);
delete_variable_declaration(ctx, var->declaration);
Free(ctx, var);
} // delete_global_variable
871
872
static MOJOSHADER_astCompilationUnit *new_global_typedef(Context *ctx,
MOJOSHADER_astTypedef *td)
873
{
874
875
NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitTypedef,
MOJOSHADER_AST_COMPUNIT_TYPEDEF);
876
877
retval->next = NULL;
retval->type_info = td;
878
return (MOJOSHADER_astCompilationUnit *) retval;
879
880
} // new_global_typedef
881
882
static void delete_global_typedef(Context *ctx,
MOJOSHADER_astCompilationUnitTypedef *unit)
883
884
885
886
887
888
889
{
DELETE_AST_NODE(unit);
delete_compilation_unit(ctx, unit->next);
delete_typedef(ctx, unit->type_info);
Free(ctx, unit);
} // delete_global_typedef
890
891
892
static MOJOSHADER_astStructMembers *new_struct_member(Context *ctx,
MOJOSHADER_astScalarOrArray *soa,
const char *semantic)
893
{
894
895
NEW_AST_NODE(retval, MOJOSHADER_astStructMembers,
MOJOSHADER_AST_STRUCT_MEMBER);
896
897
retval->semantic = semantic;
retval->details = soa;
898
retval->interpolation_mod = MOJOSHADER_AST_INTERPMOD_NONE;
899
900
901
902
retval->next = NULL;
return retval;
} // new_struct_member
903
904
static void delete_struct_member(Context *ctx,
MOJOSHADER_astStructMembers *member)
905
906
907
908
909
910
911
{
DELETE_AST_NODE(member);
delete_struct_member(ctx, member->next);
delete_scalar_or_array(ctx, member->details);
Free(ctx, member);
} // delete_struct_member
912
913
914
static MOJOSHADER_astStructDeclaration *new_struct_declaration(Context *ctx,
const char *name,
MOJOSHADER_astStructMembers *members)
915
{
916
917
NEW_AST_NODE(retval, MOJOSHADER_astStructDeclaration,
MOJOSHADER_AST_STRUCT_DECLARATION);
918
retval->datatype = NULL;
919
920
921
922
923
retval->name = name;
retval->members = members;
return retval;
} // new_struct_declaration
924
925
static void delete_struct_declaration(Context *ctx,
MOJOSHADER_astStructDeclaration *decl)
926
927
928
929
930
931
{
DELETE_AST_NODE(decl);
delete_struct_member(ctx, decl->members);
Free(ctx, decl);
} // delete_struct_declaration
932
933
static MOJOSHADER_astCompilationUnit *new_global_struct(Context *ctx,
MOJOSHADER_astStructDeclaration *sd)
934
{
935
936
NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitStruct,
MOJOSHADER_AST_COMPUNIT_STRUCT);
937
938
retval->next = NULL;
retval->struct_info = sd;
939
return (MOJOSHADER_astCompilationUnit *) retval;
940
941
} // new_global_struct
942
943
static void delete_global_struct(Context *ctx,
MOJOSHADER_astCompilationUnitStruct *unit)
944
945
946
947
948
949
950
{
DELETE_AST_NODE(unit);
delete_compilation_unit(ctx, unit->next);
delete_struct_declaration(ctx, unit->struct_info);
Free(ctx, unit);
} // delete_global_struct
951
952
static void delete_compilation_unit(Context *ctx,
MOJOSHADER_astCompilationUnit *unit)
953
954
955
956
957
958
959
960
961
962
963
{
if (!unit) return;
// it's important to not recurse too deeply here, since you may have
// thousands of items in this linked list (each line of a massive
// function, for example). To avoid this, we iterate the list here,
// deleting all children and making them think they have no reason
// to recurse in their own delete methods.
// Please note that everyone should _try_ to delete their "next" member,
// just in case, but hopefully this cleaned it out.
964
MOJOSHADER_astCompilationUnit *i = unit->next;
965
966
967
unit->next = NULL;
while (i)
{
968
MOJOSHADER_astCompilationUnit *next = i->next;
969
970
971
972
973
i->next = NULL;
delete_compilation_unit(ctx, i);
i = next;
} // while
974
switch (unit->ast.type)
975
976
{
#define DELETE_UNIT(typ, cls, fn) \
977
978
979
980
981
case MOJOSHADER_AST_COMPUNIT_##typ: delete_##fn(ctx, (cls *) unit); break;
DELETE_UNIT(FUNCTION, MOJOSHADER_astCompilationUnitFunction, function);
DELETE_UNIT(TYPEDEF, MOJOSHADER_astCompilationUnitTypedef, global_typedef);
DELETE_UNIT(VARIABLE, MOJOSHADER_astCompilationUnitVariable, global_variable);
DELETE_UNIT(STRUCT, MOJOSHADER_astCompilationUnitStruct, global_struct);
982
983
984
985
986
987
988
#undef DELETE_UNIT
default: assert(0 && "missing cleanup code"); break;
} // switch
// don't free (unit) here, the class-specific functions do it.
} // delete_compilation_unit
989
990
static MOJOSHADER_astStatement *new_typedef_statement(Context *ctx,
MOJOSHADER_astTypedef *td)
991
{
992
993
NEW_AST_NODE(retval, MOJOSHADER_astTypedefStatement,
MOJOSHADER_AST_STATEMENT_TYPEDEF);
994
995
retval->next = NULL;
retval->type_info = td;
996
return (MOJOSHADER_astStatement *) retval;
997
998
} // new_typedef_statement
999
1000
static void delete_typedef_statement(Context *ctx,
MOJOSHADER_astTypedefStatement *stmt)