/
mojoshader_compiler.c
3490 lines (3022 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
328
} // 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)
329
{
330
SymbolScope *item = map->scope;
331
332
333
if (!item)
return;
if (item->symbol)
334
hash_remove(map->hash, item->symbol);
335
336
map->scope = item->next;
Free(ctx, item);
337
} // pop_symbol
338
339
static void pop_symbol_scope(Context *ctx, SymbolMap *map)
340
341
{
while ((map->scope) && (map->scope->symbol))
342
pop_symbol(ctx, map);
343
344
345
assert(map->scope != NULL);
assert(map->scope->symbol == NULL);
346
347
348
349
350
351
352
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);
353
354
} // push_scope
355
static const MOJOSHADER_astDataType *find_symbol(Context *ctx, SymbolMap *map, const char *sym, int *_index)
356
{
357
358
const void *_item = NULL;
hash_find(map->hash, sym, &_item);
359
SymbolScope *item = (SymbolScope *) _item;
360
361
362
if (item && _index)
*_index = item->index;
return item ? item->datatype : NULL;
363
364
} // find_symbol
365
static inline const MOJOSHADER_astDataType *find_usertype(Context *ctx, const char *sym)
366
{
367
return find_symbol(ctx, &ctx->usertypes, sym, NULL);
368
369
} // find_usertype
370
static inline const MOJOSHADER_astDataType *find_variable(Context *ctx, const char *sym, int *_index)
371
{
372
return find_symbol(ctx, &ctx->variables, sym, _index);
373
374
} // find_variable
375
static void destroy_symbolmap(Context *ctx, SymbolMap *map)
376
377
{
while (map->scope)
378
pop_symbol(ctx, map);
379
380
hash_destroy(map->hash);
} // destroy_symbolmap
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
440
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
441
442
// !!! FIXME: new_* and delete_* should take an allocator, not a context.
443
444
445
446
447
// 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.
448
#define NEW_AST_NODE(retval, cls, typ) \
449
cls *retval = (cls *) Malloc(ctx, sizeof (cls)); \
450
451
452
453
454
455
456
457
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 { \
458
459
460
if (!cls) return; \
} while (0)
461
462
463
static void delete_compilation_unit(Context*, MOJOSHADER_astCompilationUnit*);
static void delete_statement(Context *ctx, MOJOSHADER_astStatement *stmt);
464
465
466
467
static MOJOSHADER_astExpression *new_callfunc_expr(Context *ctx,
MOJOSHADER_astExpression *identifier,
MOJOSHADER_astArguments *args)
468
{
469
470
NEW_AST_NODE(retval, MOJOSHADER_astExpressionCallFunction,
MOJOSHADER_AST_OP_CALLFUNC);
471
472
retval->identifier = identifier;
retval->args = args;
473
return (MOJOSHADER_astExpression *) retval;
474
475
} // new_callfunc_expr
476
static MOJOSHADER_astExpression *new_constructor_expr(Context *ctx,
477
478
const MOJOSHADER_astDataType *dt,
MOJOSHADER_astArguments *args)
479
{
480
481
NEW_AST_NODE(retval, MOJOSHADER_astExpressionConstructor,
MOJOSHADER_AST_OP_CONSTRUCTOR);
482
retval->datatype = dt;
483
retval->args = args;
484
return (MOJOSHADER_astExpression *) retval;
485
486
} // new_constructor_expr
487
static MOJOSHADER_astExpression *new_cast_expr(Context *ctx,
488
const MOJOSHADER_astDataType *dt,
489
MOJOSHADER_astExpression *operand)
490
{
491
NEW_AST_NODE(retval, MOJOSHADER_astExpressionCast, MOJOSHADER_AST_OP_CAST);
492
retval->datatype = dt;
493
retval->operand = operand;
494
return (MOJOSHADER_astExpression *) retval;
495
496
} // new_cast_expr
497
498
499
static MOJOSHADER_astExpression *new_unary_expr(Context *ctx,
const MOJOSHADER_astNodeType op,
MOJOSHADER_astExpression *operand)
500
{
501
NEW_AST_NODE(retval, MOJOSHADER_astExpressionUnary, op);
502
503
assert(operator_is_unary(op));
retval->operand = operand;
504
return (MOJOSHADER_astExpression *) retval;
505
506
} // new_unary_expr
507
508
509
510
static MOJOSHADER_astExpression *new_binary_expr(Context *ctx,
const MOJOSHADER_astNodeType op,
MOJOSHADER_astExpression *left,
MOJOSHADER_astExpression *right)
511
{
512
NEW_AST_NODE(retval, MOJOSHADER_astExpressionBinary, op);
513
514
515
assert(operator_is_binary(op));
retval->left = left;
retval->right = right;
516
return (MOJOSHADER_astExpression *) retval;
517
518
} // new_binary_expr
519
520
521
522
523
static MOJOSHADER_astExpression *new_ternary_expr(Context *ctx,
const MOJOSHADER_astNodeType op,
MOJOSHADER_astExpression *left,
MOJOSHADER_astExpression *center,
MOJOSHADER_astExpression *right)
524
{
525
NEW_AST_NODE(retval, MOJOSHADER_astExpressionTernary, op);
526
assert(operator_is_ternary(op));
527
528
assert(op == MOJOSHADER_AST_OP_CONDITIONAL);
retval->datatype = &ctx->dt_bool;
529
530
531
retval->left = left;
retval->center = center;
retval->right = right;
532
return (MOJOSHADER_astExpression *) retval;
533
534
} // new_ternary_expr
535
536
537
static MOJOSHADER_astExpression *new_deref_struct_expr(Context *ctx,
MOJOSHADER_astExpression *identifier,
const char *member)
538
{
539
540
NEW_AST_NODE(retval, MOJOSHADER_astExpressionDerefStruct,
MOJOSHADER_AST_OP_DEREF_STRUCT);
541
542
retval->identifier = identifier;
retval->member = member; // cached; don't copy string.
543
retval->isswizzle = 0; // may change during semantic analysis.
544
return (MOJOSHADER_astExpression *) retval;
545
546
} // new_deref_struct_expr
547
548
static MOJOSHADER_astExpression *new_identifier_expr(Context *ctx,
const char *string)
549
{
550
551
NEW_AST_NODE(retval, MOJOSHADER_astExpressionIdentifier,
MOJOSHADER_AST_OP_IDENTIFIER);
552
retval->identifier = string; // cached; don't copy string.
553
return (MOJOSHADER_astExpression *) retval;
554
555
} // new_identifier_expr
556
557
static MOJOSHADER_astExpression *new_literal_int_expr(Context *ctx,
const int value)
558
{
559
560
NEW_AST_NODE(retval, MOJOSHADER_astExpressionIntLiteral,
MOJOSHADER_AST_OP_INT_LITERAL);
561
retval->datatype = &ctx->dt_int;
562
retval->value = value;
563
return (MOJOSHADER_astExpression *) retval;
564
565
} // new_literal_int_expr
566
567
static MOJOSHADER_astExpression *new_literal_float_expr(Context *ctx,
const double dbl)
568
{
569
570
NEW_AST_NODE(retval, MOJOSHADER_astExpressionFloatLiteral,
MOJOSHADER_AST_OP_FLOAT_LITERAL);
571
retval->datatype = &ctx->dt_float;
572
retval->value = dbl;
573
return (MOJOSHADER_astExpression *) retval;
574
575
} // new_literal_float_expr
576
577
static MOJOSHADER_astExpression *new_literal_string_expr(Context *ctx,
const char *string)
578
{
579
580
NEW_AST_NODE(retval, MOJOSHADER_astExpressionStringLiteral,
MOJOSHADER_AST_OP_STRING_LITERAL);
581
retval->datatype = &ctx->dt_string;
582
retval->string = string; // cached; don't copy string.
583
return (MOJOSHADER_astExpression *) retval;
584
585
} // new_literal_string_expr
586
587
static MOJOSHADER_astExpression *new_literal_boolean_expr(Context *ctx,
const int value)
588
{
589
590
NEW_AST_NODE(retval, MOJOSHADER_astExpressionBooleanLiteral,
MOJOSHADER_AST_OP_BOOLEAN_LITERAL);
591
retval->datatype = &ctx->dt_bool;
592
retval->value = value;
593
return (MOJOSHADER_astExpression *) retval;
594
} // new_literal_boolean_expr
595
596
static void delete_arguments(Context *ctx, MOJOSHADER_astArguments *args);
597
598
static void delete_expr(Context *ctx, MOJOSHADER_astExpression *_expr)
599
{
600
601
MOJOSHADER_astNode *expr = (MOJOSHADER_astNode *) _expr;
602
DELETE_AST_NODE(expr);
603
604
605
606
607
608
609
610
611
612
613
614
615
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);
616
else if (operator_is_binary(expr->ast.type))
617
{
618
619
delete_expr(ctx, expr->binary.left);
delete_expr(ctx, expr->binary.right);
620
} // else if
621
622
else if (operator_is_ternary(expr->ast.type))
623
{
624
625
626
delete_expr(ctx, expr->ternary.left);
delete_expr(ctx, expr->ternary.center);
delete_expr(ctx, expr->ternary.right);
627
} // else if
628
629
else if (expr->ast.type == MOJOSHADER_AST_OP_CALLFUNC)
630
{
631
632
delete_expr(ctx, expr->callfunc.identifier);
delete_arguments(ctx, expr->callfunc.args);
633
} // else if
634
635
636
// rest of operators don't have extra data to free.
637
638
639
Free(ctx, expr);
} // delete_expr
640
641
static MOJOSHADER_astArguments *new_argument(Context *ctx,
MOJOSHADER_astExpression *arg)
642
{
643
644
NEW_AST_NODE(retval, MOJOSHADER_astArguments, MOJOSHADER_AST_ARGUMENTS);
retval->argument = arg;
645
646
647
648
retval->next = NULL;
return retval;
} // new_argument
649
static void delete_arguments(Context *ctx, MOJOSHADER_astArguments *args)
650
651
652
653
654
655
656
{
DELETE_AST_NODE(args);
delete_arguments(ctx, args->next);
delete_expr(ctx, args->argument);
Free(ctx, args);
} // delete_arguments
657
658
static MOJOSHADER_astFunctionParameters *new_function_param(Context *ctx,
const MOJOSHADER_astInputModifier inputmod,
659
660
const MOJOSHADER_astDataType *dt,
const char *identifier, const char *semantic,
661
662
const MOJOSHADER_astInterpolationModifier interpmod,
MOJOSHADER_astExpression *initializer)
663
{
664
665
NEW_AST_NODE(retval, MOJOSHADER_astFunctionParameters,
MOJOSHADER_AST_FUNCTION_PARAMS);
666
retval->datatype = dt;
667
668
669
670
671
672
673
retval->input_modifier = inputmod;
retval->identifier = identifier;
retval->semantic = semantic;
retval->interpolation_modifier = interpmod;
retval->initializer = initializer;
retval->next = NULL;
return retval;
674
} // new_function_param
675
676
677
static void delete_function_params(Context *ctx,
MOJOSHADER_astFunctionParameters *params)
678
{
679
680
681
682
683
DELETE_AST_NODE(params);
delete_function_params(ctx, params->next);
delete_expr(ctx, params->initializer);
Free(ctx, params);
} // delete_function_params
684
685
static MOJOSHADER_astFunctionSignature *new_function_signature(Context *ctx,
686
const MOJOSHADER_astDataType *dt,
687
688
const char *identifier,
MOJOSHADER_astFunctionParameters *params)
689
{
690
691
NEW_AST_NODE(retval, MOJOSHADER_astFunctionSignature,
MOJOSHADER_AST_FUNCTION_SIGNATURE);
692
retval->datatype = dt;
693
retval->identifier = identifier;
694
retval->params = params;
695
retval->storage_class = MOJOSHADER_AST_FNSTORECLS_NONE;
696
697
698
699
retval->semantic = NULL;
return retval;
} // new_function_signature
700
701
static void delete_function_signature(Context *ctx,
MOJOSHADER_astFunctionSignature *sig)
702
703
{
DELETE_AST_NODE(sig);
704
delete_function_params(ctx, sig->params);
705
706
707
Free(ctx, sig);
} // delete_function_signature
708
709
710
static MOJOSHADER_astCompilationUnit *new_function(Context *ctx,
MOJOSHADER_astFunctionSignature *declaration,
MOJOSHADER_astStatement *definition)
711
{
712
713
NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitFunction,
MOJOSHADER_AST_COMPUNIT_FUNCTION);
714
715
716
retval->next = NULL;
retval->declaration = declaration;
retval->definition = definition;
717
return (MOJOSHADER_astCompilationUnit *) retval;
718
719
} // new_function
720
721
static void delete_function(Context *ctx,
MOJOSHADER_astCompilationUnitFunction *unitfn)
722
723
724
725
726
727
728
729
{
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
730
731
732
static MOJOSHADER_astScalarOrArray *new_scalar_or_array(Context *ctx,
const char *ident, const int isvec,
MOJOSHADER_astExpression *dim)
733
{
734
735
NEW_AST_NODE(retval, MOJOSHADER_astScalarOrArray,
MOJOSHADER_AST_SCALAR_OR_ARRAY);
736
737
738
739
740
741
retval->identifier = ident;
retval->isarray = isvec;
retval->dimension = dim;
return retval;
} // new_scalar_or_array
742
static void delete_scalar_or_array(Context *ctx,MOJOSHADER_astScalarOrArray *s)
743
{
744
745
746
DELETE_AST_NODE(s);
delete_expr(ctx, s->dimension);
Free(ctx, s);
747
748
} // delete_scalar_or_array
749
static MOJOSHADER_astTypedef *new_typedef(Context *ctx, const int isconst,
750
const MOJOSHADER_astDataType *dt,
751
MOJOSHADER_astScalarOrArray *soa)
752
{
753
// we correct this datatype to the final version during semantic analysis.
754
NEW_AST_NODE(retval, MOJOSHADER_astTypedef, MOJOSHADER_AST_TYPEDEF);
755
retval->datatype = dt;
756
757
758
759
760
retval->isconst = isconst;
retval->details = soa;
return retval;
} // new_typedef
761
static void delete_typedef(Context *ctx, MOJOSHADER_astTypedef *td)
762
763
764
765
766
767
{
DELETE_AST_NODE(td);
delete_scalar_or_array(ctx, td->details);
Free(ctx, td);
} // delete_typedef
768
769
static MOJOSHADER_astPackOffset *new_pack_offset(Context *ctx,
const char *a, const char *b)
770
{
771
NEW_AST_NODE(retval, MOJOSHADER_astPackOffset, MOJOSHADER_AST_PACK_OFFSET);
772
773
774
775
776
retval->ident1 = a;
retval->ident2 = b;
return retval;
} // new_pack_offset
777
static void delete_pack_offset(Context *ctx, MOJOSHADER_astPackOffset *o)
778
779
780
781
782
{
DELETE_AST_NODE(o);
Free(ctx, o);
} // delete_pack_offset
783
784
static MOJOSHADER_astVariableLowLevel *new_variable_lowlevel(Context *ctx,
MOJOSHADER_astPackOffset *po,
785
786
const char *reg)
{
787
788
NEW_AST_NODE(retval, MOJOSHADER_astVariableLowLevel,
MOJOSHADER_AST_VARIABLE_LOWLEVEL);
789
790
791
792
793
retval->packoffset = po;
retval->register_name = reg;
return retval;
} // new_variable_lowlevel
794
795
static void delete_variable_lowlevel(Context *ctx,
MOJOSHADER_astVariableLowLevel *vll)
796
797
798
799
800
801
{
DELETE_AST_NODE(vll);
delete_pack_offset(ctx, vll->packoffset);
Free(ctx, vll);
} // delete_variable_lowlevel
802
static MOJOSHADER_astAnnotations *new_annotation(Context *ctx,
803
const MOJOSHADER_astDataType *dt,
804
MOJOSHADER_astExpression *initializer)
805
{
806
NEW_AST_NODE(retval, MOJOSHADER_astAnnotations, MOJOSHADER_AST_ANNOTATION);
807
retval->datatype = dt;
808
809
810
811
812
retval->initializer = initializer;
retval->next = NULL;
return retval;
} // new_annotation
813
static void delete_annotation(Context *ctx, MOJOSHADER_astAnnotations *annos)
814
{
815
816
817
818
DELETE_AST_NODE(annos);
delete_annotation(ctx, annos->next);
delete_expr(ctx, annos->initializer);
Free(ctx, annos);
819
820
} // delete_annotation
821
822
823
824
825
826
static MOJOSHADER_astVariableDeclaration *new_variable_declaration(
Context *ctx, MOJOSHADER_astScalarOrArray *soa,
const char *semantic,
MOJOSHADER_astAnnotations *annotations,
MOJOSHADER_astExpression *init,
MOJOSHADER_astVariableLowLevel *vll)
827
{
828
829
NEW_AST_NODE(retval, MOJOSHADER_astVariableDeclaration,
MOJOSHADER_AST_VARIABLE_DECLARATION);
830
831
832
833
834
835
836
837
838
839
840
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
841
842
static void delete_variable_declaration(Context *ctx,
MOJOSHADER_astVariableDeclaration *dcl)
843
844
845
846
847
848
849
850
851
852
{
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
853
854
static MOJOSHADER_astCompilationUnit *new_global_variable(Context *ctx,
MOJOSHADER_astVariableDeclaration *decl)
855
{
856
857
NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitVariable,
MOJOSHADER_AST_COMPUNIT_VARIABLE);
858
859
retval->next = NULL;
retval->declaration = decl;
860
return (MOJOSHADER_astCompilationUnit *) retval;
861
862
} // new_global_variable
863
864
static void delete_global_variable(Context *ctx,
MOJOSHADER_astCompilationUnitVariable *var)
865
866
867
868
869
870
871
{
DELETE_AST_NODE(var);
delete_compilation_unit(ctx, var->next);
delete_variable_declaration(ctx, var->declaration);
Free(ctx, var);
} // delete_global_variable
872
873
static MOJOSHADER_astCompilationUnit *new_global_typedef(Context *ctx,
MOJOSHADER_astTypedef *td)
874
{
875
876
NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitTypedef,
MOJOSHADER_AST_COMPUNIT_TYPEDEF);
877
878
retval->next = NULL;
retval->type_info = td;
879
return (MOJOSHADER_astCompilationUnit *) retval;
880
881
} // new_global_typedef
882
883
static void delete_global_typedef(Context *ctx,
MOJOSHADER_astCompilationUnitTypedef *unit)
884
885
886
887
888
889
890
{
DELETE_AST_NODE(unit);
delete_compilation_unit(ctx, unit->next);
delete_typedef(ctx, unit->type_info);
Free(ctx, unit);
} // delete_global_typedef
891
892
893
static MOJOSHADER_astStructMembers *new_struct_member(Context *ctx,
MOJOSHADER_astScalarOrArray *soa,
const char *semantic)
894
{
895
896
NEW_AST_NODE(retval, MOJOSHADER_astStructMembers,
MOJOSHADER_AST_STRUCT_MEMBER);
897
898
retval->semantic = semantic;
retval->details = soa;
899
retval->interpolation_mod = MOJOSHADER_AST_INTERPMOD_NONE;
900
901
902
903
retval->next = NULL;
return retval;
} // new_struct_member
904
905
static void delete_struct_member(Context *ctx,
MOJOSHADER_astStructMembers *member)
906
907
908
909
910
911
912
{
DELETE_AST_NODE(member);
delete_struct_member(ctx, member->next);
delete_scalar_or_array(ctx, member->details);
Free(ctx, member);
} // delete_struct_member
913
914
915
static MOJOSHADER_astStructDeclaration *new_struct_declaration(Context *ctx,
const char *name,
MOJOSHADER_astStructMembers *members)
916
{
917
918
NEW_AST_NODE(retval, MOJOSHADER_astStructDeclaration,
MOJOSHADER_AST_STRUCT_DECLARATION);
919
retval->datatype = NULL;
920
921
922
923
924
retval->name = name;
retval->members = members;
return retval;
} // new_struct_declaration
925
926
static void delete_struct_declaration(Context *ctx,
MOJOSHADER_astStructDeclaration *decl)
927
928
929
930
931
932
{
DELETE_AST_NODE(decl);
delete_struct_member(ctx, decl->members);
Free(ctx, decl);
} // delete_struct_declaration
933
934
static MOJOSHADER_astCompilationUnit *new_global_struct(Context *ctx,
MOJOSHADER_astStructDeclaration *sd)
935
{
936
937
NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitStruct,
MOJOSHADER_AST_COMPUNIT_STRUCT);
938
939
retval->next = NULL;
retval->struct_info = sd;
940
return (MOJOSHADER_astCompilationUnit *) retval;
941
942
} // new_global_struct
943
944
static void delete_global_struct(Context *ctx,
MOJOSHADER_astCompilationUnitStruct *unit)
945
946
947
948
949
950
951
{
DELETE_AST_NODE(unit);
delete_compilation_unit(ctx, unit->next);
delete_struct_declaration(ctx, unit->struct_info);
Free(ctx, unit);
} // delete_global_struct
952
953
static void delete_compilation_unit(Context *ctx,
MOJOSHADER_astCompilationUnit *unit)
954
955
956
957
958
959
960
961
962
963
964
{
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.
965
MOJOSHADER_astCompilationUnit *i = unit->next;
966
967
968
unit->next = NULL;
while (i)
{
969
MOJOSHADER_astCompilationUnit *next = i->next;
970
971
972
973
974
i->next = NULL;
delete_compilation_unit(ctx, i);
i = next;
} // while
975
switch (unit->ast.type)
976
977
{
#define DELETE_UNIT(typ, cls, fn) \
978
979
980
981
982
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);
983
984
985
986
987
988
989
#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
990
991
static MOJOSHADER_astStatement *new_typedef_statement(Context *ctx,
MOJOSHADER_astTypedef *td)
992
{
993
994
NEW_AST_NODE(retval, MOJOSHADER_astTypedefStatement,
MOJOSHADER_AST_STATEMENT_TYPEDEF);
995
996
retval->next = NULL;
retval->type_info = td;
997
return (MOJOSHADER_astStatement *) retval;
998
999
} // new_typedef_statement
1000
static void delete_typedef_statement(Context *ctx,