/
mojoshader_compiler.c
2770 lines (2377 loc) · 97.2 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
} TokenData;
62
63
64
// This tracks data types and variables, and notes when they enter/leave scope.
65
66
typedef struct SymbolScope
67
68
69
{
const char *symbol;
const char *datatype;
70
71
struct SymbolScope *next;
} SymbolScope;
72
73
typedef struct SymbolMap
74
{
75
76
77
HashTable *hash;
SymbolScope *scope;
} SymbolMap;
78
79
80
81
82
83
84
85
86
87
88
89
90
// 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;
int error_count;
ErrorList *errors;
91
92
int warning_count;
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
103
104
105
// These are entries allocated in the strcache, so these pointers are
// valid from shortly after we create the cache until we destroy it
// with the rest of the context. This makes it so we can compare common
// strings by pointer without having to hash them every time, so long as
// we're comparing a string pointer we know came from this string cache.
106
// The first batch are simplifed datatype strings ("b" == bool, etc).
107
108
109
const char *str_b; // "b"
const char *str_f; // "f"
const char *str_i; // "i"
110
111
112
113
const char *str_u; // "u"
const char *str_h; // "h"
const char *str_d; // "d"
const char *str_s; // "s"
114
115
116
117
118
119
120
121
122
123
124
const char *str_S; // "S"
const char *str_s1; // "s1"
const char *str_s2; // "s2"
const char *str_s3; // "s3"
const char *str_sc; // "sc"
const char *str_ss; // "ss"
const char *str_sS; // "sS"
const char *str_Fs; // "Fs"
const char *str_Fu; // "Fu"
const char *str_ns; // "ns"
const char *str_nu; // "nu"
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
} Context;
// 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)
{
if (ptr != NULL) // check for NULL in case of dumb free() impl.
ctx->free(ptr, ctx->malloc_data);
} // Free
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
static void failf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3);
static void failf(Context *ctx, const char *fmt, ...)
{
const char *fname = ctx->sourcefile;
const unsigned int error_position = ctx->sourceline;
ctx->isfail = 1;
const int MAX_ERROR_COUNT = 128;
if (ctx->error_count == (MAX_ERROR_COUNT-1))
fmt = "Too many errors, not reporting any more.";
else if (ctx->error_count >= MAX_ERROR_COUNT)
return;
ErrorList *error = (ErrorList *) Malloc(ctx, sizeof (ErrorList));
if (error == NULL)
return;
char scratch = 0;
va_list ap;
va_start(ap, fmt);
const int len = vsnprintf(&scratch, sizeof (scratch), fmt, ap);
va_end(ap);
char *failstr = (char *) Malloc(ctx, len + 1);
if (failstr == NULL)
Free(ctx, error);
else
{
va_start(ap, fmt);
vsnprintf(failstr, len + 1, fmt, ap); // rebuild it.
va_end(ap);
error->error.error = failstr;
error->error.filename = fname ? StrDup(ctx, fname) : NULL;
error->error.error_position = error_position;
error->next = NULL;
ErrorList *prev = NULL;
ErrorList *item = ctx->errors;
while (item != NULL)
{
prev = item;
item = item->next;
} // while
if (prev == NULL)
ctx->errors = error;
else
prev->next = error;
ctx->error_count++;
} // else
} // failf
static inline void fail(Context *ctx, const char *reason)
213
{
214
failf(ctx, "%s", reason);
215
} // fail
216
217
218
219
220
221
static inline int isfail(const Context *ctx)
{
return ctx->isfail;
} // isfail
222
223
static void symbolmap_nuke(const void *k, const void *v, void *d) {/*no-op*/}
224
225
static int create_symbolmap(Context *ctx, SymbolMap *map)
226
{
227
// !!! FIXME: should compare string pointer, with string in cache.
228
map->scope = NULL;
229
230
231
232
map->hash = hash_create(ctx, hash_hash_string, hash_keymatch_string,
symbolmap_nuke, 1, ctx->malloc, ctx->free,
ctx->malloc_data);
if (!map->hash)
233
234
235
236
237
238
{
out_of_memory(ctx);
return 0;
} // if
return 1;
239
} // create_symbolmap
240
241
242
243
244
static void push_symbol(Context *ctx, SymbolMap *map,
const char *sym, const char *datatype)
{
245
246
247
// !!! FIXME: decide if this symbol is defined, and if so, if it's in
// !!! FIXME: the current scope.
248
SymbolScope *item = (SymbolScope *) Malloc(ctx, sizeof (SymbolScope));
249
250
251
252
253
if (item == NULL)
return;
if (sym != NULL)
{
254
if (hash_insert(map->hash, sym, datatype) == -1)
255
256
257
{
Free(ctx, item);
return;
258
} // if
259
260
261
262
263
264
} // if
item->symbol = sym; // cached strings, don't copy.
item->datatype = datatype;
item->next = map->scope;
map->scope = item;
265
266
267
268
269
} // push_symbol
static inline void push_usertype(Context *ctx, const char *sym, const char *dt)
{
push_symbol(ctx, &ctx->usertypes, sym, dt);
270
271
} // push_usertype
272
273
274
275
276
277
278
279
280
281
282
283
284
static inline void push_variable(Context *ctx, const char *sym, const char *dt)
{
push_symbol(ctx, &ctx->variables, sym, dt);
} // 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)
285
{
286
SymbolScope *item = map->scope;
287
288
289
if (!item)
return;
if (item->symbol)
290
hash_remove(map->hash, item->symbol);
291
292
map->scope = item->next;
Free(ctx, item);
293
} // pop_symbol
294
295
static void pop_symbol_scope(Context *ctx, SymbolMap *map)
296
297
{
while ((map->scope) && (map->scope->symbol))
298
pop_symbol(ctx, map);
299
300
301
assert(map->scope != NULL);
assert(map->scope->symbol == NULL);
302
303
304
305
306
307
308
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);
309
310
} // push_scope
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
static const char *find_symbol(Context *ctx, SymbolMap *map, const char *sym)
{
const void *value = NULL;
hash_find(map->hash, sym, &value);
return (const char *) value;
} // find_symbol
static inline const char *find_usertype(Context *ctx, const char *sym)
{
return find_symbol(ctx, &ctx->usertypes, sym);
} // find_usertype
static inline const char *find_variable(Context *ctx, const char *sym)
{
return find_symbol(ctx, &ctx->variables, sym);
} // find_variable
328
static void destroy_symbolmap(Context *ctx, SymbolMap *map)
329
330
{
while (map->scope)
331
332
333
pop_symbol_scope(ctx, map);
hash_destroy(map->hash);
} // destroy_symbolmap
334
335
336
337
338
339
340
// 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.
341
#define NEW_AST_NODE(retval, cls, typ) \
342
cls *retval = (cls *) Malloc(ctx, sizeof (cls)); \
343
344
345
346
347
348
349
350
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 { \
351
352
353
if (!cls) return; \
} while (0)
354
355
static void delete_compilation_unit(Context*, MOJOSHADER_astCompilationUnit*);
static void delete_statement(Context *ctx, MOJOSHADER_astStatement *stmt);
356
357
358
359
static MOJOSHADER_astExpression *new_callfunc_expr(Context *ctx,
MOJOSHADER_astExpression *identifier,
MOJOSHADER_astArguments *args)
360
{
361
362
NEW_AST_NODE(retval, MOJOSHADER_astExpressionCallFunction,
MOJOSHADER_AST_OP_CALLFUNC);
363
364
retval->identifier = identifier;
retval->args = args;
365
return (MOJOSHADER_astExpression *) retval;
366
367
} // new_callfunc_expr
368
369
370
static MOJOSHADER_astExpression *new_constructor_expr(Context *ctx,
const char *datatype,
MOJOSHADER_astArguments *args)
371
{
372
373
NEW_AST_NODE(retval, MOJOSHADER_astExpressionConstructor,
MOJOSHADER_AST_OP_CONSTRUCTOR);
374
375
retval->datatype = datatype;
retval->args = args;
376
return (MOJOSHADER_astExpression *) retval;
377
378
} // new_constructor_expr
379
380
381
static MOJOSHADER_astExpression *new_cast_expr(Context *ctx,
const char *datatype,
MOJOSHADER_astExpression *operand)
382
{
383
NEW_AST_NODE(retval, MOJOSHADER_astExpressionCast, MOJOSHADER_AST_OP_CAST);
384
385
retval->datatype = datatype;
retval->operand = operand;
386
return (MOJOSHADER_astExpression *) retval;
387
388
} // new_cast_expr
389
390
391
static MOJOSHADER_astExpression *new_unary_expr(Context *ctx,
const MOJOSHADER_astNodeType op,
MOJOSHADER_astExpression *operand)
392
{
393
NEW_AST_NODE(retval, MOJOSHADER_astExpressionUnary, op);
394
395
assert(operator_is_unary(op));
retval->operand = operand;
396
return (MOJOSHADER_astExpression *) retval;
397
398
} // new_unary_expr
399
400
401
402
static MOJOSHADER_astExpression *new_binary_expr(Context *ctx,
const MOJOSHADER_astNodeType op,
MOJOSHADER_astExpression *left,
MOJOSHADER_astExpression *right)
403
{
404
NEW_AST_NODE(retval, MOJOSHADER_astExpressionBinary, op);
405
406
407
assert(operator_is_binary(op));
retval->left = left;
retval->right = right;
408
return (MOJOSHADER_astExpression *) retval;
409
410
} // new_binary_expr
411
412
413
414
415
static MOJOSHADER_astExpression *new_ternary_expr(Context *ctx,
const MOJOSHADER_astNodeType op,
MOJOSHADER_astExpression *left,
MOJOSHADER_astExpression *center,
MOJOSHADER_astExpression *right)
416
{
417
NEW_AST_NODE(retval, MOJOSHADER_astExpressionTernary, op);
418
419
420
421
assert(operator_is_ternary(op));
retval->left = left;
retval->center = center;
retval->right = right;
422
return (MOJOSHADER_astExpression *) retval;
423
424
} // new_ternary_expr
425
426
427
static MOJOSHADER_astExpression *new_deref_struct_expr(Context *ctx,
MOJOSHADER_astExpression *identifier,
const char *member)
428
{
429
430
NEW_AST_NODE(retval, MOJOSHADER_astExpressionDerefStruct,
MOJOSHADER_AST_OP_DEREF_STRUCT);
431
432
retval->identifier = identifier;
retval->member = member; // cached; don't copy string.
433
return (MOJOSHADER_astExpression *) retval;
434
435
} // new_deref_struct_expr
436
437
static MOJOSHADER_astExpression *new_identifier_expr(Context *ctx,
const char *string)
438
{
439
440
NEW_AST_NODE(retval, MOJOSHADER_astExpressionIdentifier,
MOJOSHADER_AST_OP_IDENTIFIER);
441
retval->identifier = string; // cached; don't copy string.
442
return (MOJOSHADER_astExpression *) retval;
443
444
} // new_identifier_expr
445
446
static MOJOSHADER_astExpression *new_literal_int_expr(Context *ctx,
const int value)
447
{
448
449
NEW_AST_NODE(retval, MOJOSHADER_astExpressionIntLiteral,
MOJOSHADER_AST_OP_INT_LITERAL);
450
retval->value = value;
451
return (MOJOSHADER_astExpression *) retval;
452
453
} // new_literal_int_expr
454
455
static MOJOSHADER_astExpression *new_literal_float_expr(Context *ctx,
const double dbl)
456
{
457
458
NEW_AST_NODE(retval, MOJOSHADER_astExpressionFloatLiteral,
MOJOSHADER_AST_OP_FLOAT_LITERAL);
459
retval->value = dbl;
460
return (MOJOSHADER_astExpression *) retval;
461
462
} // new_literal_float_expr
463
464
static MOJOSHADER_astExpression *new_literal_string_expr(Context *ctx,
const char *string)
465
{
466
467
NEW_AST_NODE(retval, MOJOSHADER_astExpressionStringLiteral,
MOJOSHADER_AST_OP_STRING_LITERAL);
468
retval->string = string; // cached; don't copy string.
469
return (MOJOSHADER_astExpression *) retval;
470
471
} // new_literal_string_expr
472
473
static MOJOSHADER_astExpression *new_literal_boolean_expr(Context *ctx,
const int value)
474
{
475
476
NEW_AST_NODE(retval, MOJOSHADER_astExpressionBooleanLiteral,
MOJOSHADER_AST_OP_BOOLEAN_LITERAL);
477
retval->value = value;
478
return (MOJOSHADER_astExpression *) retval;
479
} // new_literal_boolean_expr
480
481
static void delete_arguments(Context *ctx, MOJOSHADER_astArguments *args);
482
483
static void delete_expr(Context *ctx, MOJOSHADER_astExpression *_expr)
484
{
485
486
MOJOSHADER_astNode *expr = (MOJOSHADER_astNode *) _expr;
487
DELETE_AST_NODE(expr);
488
489
490
491
492
493
494
495
496
497
498
499
500
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);
501
else if (operator_is_binary(expr->ast.type))
502
{
503
504
delete_expr(ctx, expr->binary.left);
delete_expr(ctx, expr->binary.right);
505
} // else if
506
507
else if (operator_is_ternary(expr->ast.type))
508
{
509
510
511
delete_expr(ctx, expr->ternary.left);
delete_expr(ctx, expr->ternary.center);
delete_expr(ctx, expr->ternary.right);
512
} // else if
513
514
else if (expr->ast.type == MOJOSHADER_AST_OP_CALLFUNC)
515
{
516
517
delete_expr(ctx, expr->callfunc.identifier);
delete_arguments(ctx, expr->callfunc.args);
518
} // else if
519
520
521
// rest of operators don't have extra data to free.
522
523
524
Free(ctx, expr);
} // delete_expr
525
526
static MOJOSHADER_astArguments *new_argument(Context *ctx,
MOJOSHADER_astExpression *arg)
527
{
528
529
NEW_AST_NODE(retval, MOJOSHADER_astArguments, MOJOSHADER_AST_ARGUMENTS);
retval->argument = arg;
530
531
532
533
retval->next = NULL;
return retval;
} // new_argument
534
static void delete_arguments(Context *ctx, MOJOSHADER_astArguments *args)
535
536
537
538
539
540
541
{
DELETE_AST_NODE(args);
delete_arguments(ctx, args->next);
delete_expr(ctx, args->argument);
Free(ctx, args);
} // delete_arguments
542
543
544
545
546
547
static MOJOSHADER_astFunctionParameters *new_function_param(Context *ctx,
const MOJOSHADER_astInputModifier inputmod,
const char *datatype, const char *identifier,
const char *semantic,
const MOJOSHADER_astInterpolationModifier interpmod,
MOJOSHADER_astExpression *initializer)
548
{
549
550
NEW_AST_NODE(retval, MOJOSHADER_astFunctionParameters,
MOJOSHADER_AST_FUNCTION_PARAMS);
551
552
553
554
555
556
557
558
retval->input_modifier = inputmod;
retval->datatype = datatype;
retval->identifier = identifier;
retval->semantic = semantic;
retval->interpolation_modifier = interpmod;
retval->initializer = initializer;
retval->next = NULL;
return retval;
559
} // new_function_param
560
561
562
static void delete_function_params(Context *ctx,
MOJOSHADER_astFunctionParameters *params)
563
{
564
565
566
567
568
DELETE_AST_NODE(params);
delete_function_params(ctx, params->next);
delete_expr(ctx, params->initializer);
Free(ctx, params);
} // delete_function_params
569
570
571
572
573
static MOJOSHADER_astFunctionSignature *new_function_signature(Context *ctx,
const char *datatype,
const char *identifier,
MOJOSHADER_astFunctionParameters *params)
574
{
575
576
NEW_AST_NODE(retval, MOJOSHADER_astFunctionSignature,
MOJOSHADER_AST_FUNCTION_SIGNATURE);
577
578
retval->datatype = datatype;
retval->identifier = identifier;
579
retval->params = params;
580
retval->storage_class = MOJOSHADER_AST_FNSTORECLS_NONE;
581
582
583
584
retval->semantic = NULL;
return retval;
} // new_function_signature
585
586
static void delete_function_signature(Context *ctx,
MOJOSHADER_astFunctionSignature *sig)
587
588
{
DELETE_AST_NODE(sig);
589
delete_function_params(ctx, sig->params);
590
591
592
Free(ctx, sig);
} // delete_function_signature
593
594
595
static MOJOSHADER_astCompilationUnit *new_function(Context *ctx,
MOJOSHADER_astFunctionSignature *declaration,
MOJOSHADER_astStatement *definition)
596
{
597
598
NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitFunction,
MOJOSHADER_AST_COMPUNIT_FUNCTION);
599
600
601
retval->next = NULL;
retval->declaration = declaration;
retval->definition = definition;
602
return (MOJOSHADER_astCompilationUnit *) retval;
603
604
} // new_function
605
606
static void delete_function(Context *ctx,
MOJOSHADER_astCompilationUnitFunction *unitfn)
607
608
609
610
611
612
613
614
{
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
615
616
617
static MOJOSHADER_astScalarOrArray *new_scalar_or_array(Context *ctx,
const char *ident, const int isvec,
MOJOSHADER_astExpression *dim)
618
{
619
620
NEW_AST_NODE(retval, MOJOSHADER_astScalarOrArray,
MOJOSHADER_AST_SCALAR_OR_ARRAY);
621
622
623
624
625
626
retval->identifier = ident;
retval->isarray = isvec;
retval->dimension = dim;
return retval;
} // new_scalar_or_array
627
static void delete_scalar_or_array(Context *ctx,MOJOSHADER_astScalarOrArray *s)
628
{
629
630
631
DELETE_AST_NODE(s);
delete_expr(ctx, s->dimension);
Free(ctx, s);
632
633
} // delete_scalar_or_array
634
635
636
static MOJOSHADER_astTypedef *new_typedef(Context *ctx, const int isconst,
const char *datatype,
MOJOSHADER_astScalarOrArray *soa)
637
{
638
// we correct this datatype to the final string during semantic analysis.
639
NEW_AST_NODE(retval, MOJOSHADER_astTypedef, MOJOSHADER_AST_TYPEDEF);
640
641
642
643
644
645
retval->isconst = isconst;
retval->datatype = datatype;
retval->details = soa;
return retval;
} // new_typedef
646
static void delete_typedef(Context *ctx, MOJOSHADER_astTypedef *td)
647
648
649
650
651
652
{
DELETE_AST_NODE(td);
delete_scalar_or_array(ctx, td->details);
Free(ctx, td);
} // delete_typedef
653
654
static MOJOSHADER_astPackOffset *new_pack_offset(Context *ctx,
const char *a, const char *b)
655
{
656
NEW_AST_NODE(retval, MOJOSHADER_astPackOffset, MOJOSHADER_AST_PACK_OFFSET);
657
658
659
660
661
retval->ident1 = a;
retval->ident2 = b;
return retval;
} // new_pack_offset
662
static void delete_pack_offset(Context *ctx, MOJOSHADER_astPackOffset *o)
663
664
665
666
667
{
DELETE_AST_NODE(o);
Free(ctx, o);
} // delete_pack_offset
668
669
static MOJOSHADER_astVariableLowLevel *new_variable_lowlevel(Context *ctx,
MOJOSHADER_astPackOffset *po,
670
671
const char *reg)
{
672
673
NEW_AST_NODE(retval, MOJOSHADER_astVariableLowLevel,
MOJOSHADER_AST_VARIABLE_LOWLEVEL);
674
675
676
677
678
retval->packoffset = po;
retval->register_name = reg;
return retval;
} // new_variable_lowlevel
679
680
static void delete_variable_lowlevel(Context *ctx,
MOJOSHADER_astVariableLowLevel *vll)
681
682
683
684
685
686
{
DELETE_AST_NODE(vll);
delete_pack_offset(ctx, vll->packoffset);
Free(ctx, vll);
} // delete_variable_lowlevel
687
688
689
static MOJOSHADER_astAnnotations *new_annotation(Context *ctx,
const char *datatype,
MOJOSHADER_astExpression *initializer)
690
{
691
NEW_AST_NODE(retval, MOJOSHADER_astAnnotations, MOJOSHADER_AST_ANNOTATION);
692
693
694
695
696
697
retval->datatype = datatype;
retval->initializer = initializer;
retval->next = NULL;
return retval;
} // new_annotation
698
static void delete_annotation(Context *ctx, MOJOSHADER_astAnnotations *annos)
699
{
700
701
702
703
DELETE_AST_NODE(annos);
delete_annotation(ctx, annos->next);
delete_expr(ctx, annos->initializer);
Free(ctx, annos);
704
705
} // delete_annotation
706
707
708
709
710
711
static MOJOSHADER_astVariableDeclaration *new_variable_declaration(
Context *ctx, MOJOSHADER_astScalarOrArray *soa,
const char *semantic,
MOJOSHADER_astAnnotations *annotations,
MOJOSHADER_astExpression *init,
MOJOSHADER_astVariableLowLevel *vll)
712
{
713
714
NEW_AST_NODE(retval, MOJOSHADER_astVariableDeclaration,
MOJOSHADER_AST_VARIABLE_DECLARATION);
715
716
717
718
719
720
721
722
723
724
725
726
retval->attributes = 0;
retval->datatype = NULL;
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
727
728
static void delete_variable_declaration(Context *ctx,
MOJOSHADER_astVariableDeclaration *dcl)
729
730
731
732
733
734
735
736
737
738
{
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
739
740
static MOJOSHADER_astCompilationUnit *new_global_variable(Context *ctx,
MOJOSHADER_astVariableDeclaration *decl)
741
{
742
743
NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitVariable,
MOJOSHADER_AST_COMPUNIT_VARIABLE);
744
745
retval->next = NULL;
retval->declaration = decl;
746
return (MOJOSHADER_astCompilationUnit *) retval;
747
748
} // new_global_variable
749
750
static void delete_global_variable(Context *ctx,
MOJOSHADER_astCompilationUnitVariable *var)
751
752
753
754
755
756
757
{
DELETE_AST_NODE(var);
delete_compilation_unit(ctx, var->next);
delete_variable_declaration(ctx, var->declaration);
Free(ctx, var);
} // delete_global_variable
758
759
static MOJOSHADER_astCompilationUnit *new_global_typedef(Context *ctx,
MOJOSHADER_astTypedef *td)
760
{
761
762
NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitTypedef,
MOJOSHADER_AST_COMPUNIT_TYPEDEF);
763
764
retval->next = NULL;
retval->type_info = td;
765
return (MOJOSHADER_astCompilationUnit *) retval;
766
767
} // new_global_typedef
768
769
static void delete_global_typedef(Context *ctx,
MOJOSHADER_astCompilationUnitTypedef *unit)
770
771
772
773
774
775
776
{
DELETE_AST_NODE(unit);
delete_compilation_unit(ctx, unit->next);
delete_typedef(ctx, unit->type_info);
Free(ctx, unit);
} // delete_global_typedef
777
778
779
static MOJOSHADER_astStructMembers *new_struct_member(Context *ctx,
MOJOSHADER_astScalarOrArray *soa,
const char *semantic)
780
{
781
782
NEW_AST_NODE(retval, MOJOSHADER_astStructMembers,
MOJOSHADER_AST_STRUCT_MEMBER);
783
784
785
retval->datatype = NULL;
retval->semantic = semantic;
retval->details = soa;
786
retval->interpolation_mod = MOJOSHADER_AST_INTERPMOD_NONE;
787
788
789
790
retval->next = NULL;
return retval;
} // new_struct_member
791
792
static void delete_struct_member(Context *ctx,
MOJOSHADER_astStructMembers *member)
793
794
795
796
797
798
799
{
DELETE_AST_NODE(member);
delete_struct_member(ctx, member->next);
delete_scalar_or_array(ctx, member->details);
Free(ctx, member);
} // delete_struct_member
800
801
802
static MOJOSHADER_astStructDeclaration *new_struct_declaration(Context *ctx,
const char *name,
MOJOSHADER_astStructMembers *members)
803
{
804
805
NEW_AST_NODE(retval, MOJOSHADER_astStructDeclaration,
MOJOSHADER_AST_STRUCT_DECLARATION);
806
807
808
809
810
retval->name = name;
retval->members = members;
return retval;
} // new_struct_declaration
811
812
static void delete_struct_declaration(Context *ctx,
MOJOSHADER_astStructDeclaration *decl)
813
814
815
816
817
818
{
DELETE_AST_NODE(decl);
delete_struct_member(ctx, decl->members);
Free(ctx, decl);
} // delete_struct_declaration
819
820
static MOJOSHADER_astCompilationUnit *new_global_struct(Context *ctx,
MOJOSHADER_astStructDeclaration *sd)
821
{
822
823
NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitStruct,
MOJOSHADER_AST_COMPUNIT_STRUCT);
824
825
retval->next = NULL;
retval->struct_info = sd;
826
return (MOJOSHADER_astCompilationUnit *) retval;
827
828
} // new_global_struct
829
830
static void delete_global_struct(Context *ctx,
MOJOSHADER_astCompilationUnitStruct *unit)
831
832
833
834
835
836
837
{
DELETE_AST_NODE(unit);
delete_compilation_unit(ctx, unit->next);
delete_struct_declaration(ctx, unit->struct_info);
Free(ctx, unit);
} // delete_global_struct
838
839
static void delete_compilation_unit(Context *ctx,
MOJOSHADER_astCompilationUnit *unit)
840
841
842
843
844
845
846
847
848
849
850
{
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.
851
MOJOSHADER_astCompilationUnit *i = unit->next;
852
853
854
unit->next = NULL;
while (i)
{
855
MOJOSHADER_astCompilationUnit *next = i->next;
856
857
858
859
860
i->next = NULL;
delete_compilation_unit(ctx, i);
i = next;
} // while
861
switch (unit->ast.type)
862
863
{
#define DELETE_UNIT(typ, cls, fn) \
864
865
866
867
868
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);
869
870
871
872
873
874
875
#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
876
877
static MOJOSHADER_astStatement *new_typedef_statement(Context *ctx,
MOJOSHADER_astTypedef *td)
878
{
879
880
NEW_AST_NODE(retval, MOJOSHADER_astTypedefStatement,
MOJOSHADER_AST_STATEMENT_TYPEDEF);
881
882
retval->next = NULL;
retval->type_info = td;
883
return (MOJOSHADER_astStatement *) retval;
884
885
} // new_typedef_statement
886
887
static void delete_typedef_statement(Context *ctx,
MOJOSHADER_astTypedefStatement *stmt)
888
889
890
891
892
893
894
{
DELETE_AST_NODE(stmt);
delete_statement(ctx, stmt->next);
delete_typedef(ctx, stmt->type_info);
Free(ctx, stmt);
} // delete_typedef_statement
895
896
static MOJOSHADER_astStatement *new_return_statement(Context *ctx,
MOJOSHADER_astExpression *expr)
897
{
898
899
NEW_AST_NODE(retval, MOJOSHADER_astReturnStatement,
MOJOSHADER_AST_STATEMENT_RETURN);
900
901
retval->next = NULL;
retval->expr = expr;
902
return (MOJOSHADER_astStatement *) retval;
903
904
} // new_return_statement
905
906
static void delete_return_statement(Context *ctx,
MOJOSHADER_astReturnStatement *stmt)
907
908
909
910
911
912
913
{
DELETE_AST_NODE(stmt);
delete_statement(ctx, stmt->next);
delete_expr(ctx, stmt->expr);
Free(ctx, stmt);
} // delete_return_statement
914
915
static MOJOSHADER_astStatement *new_block_statement(Context *ctx,
MOJOSHADER_astStatement *stmts)
916
{
917
918
NEW_AST_NODE(retval, MOJOSHADER_astBlockStatement,
MOJOSHADER_AST_STATEMENT_BLOCK);
919
retval->next = NULL;
920
921
retval->statements = stmts;
return (MOJOSHADER_astStatement *) retval;
922
923
} // new_block_statement
924
925
static void delete_block_statement(Context *ctx,
MOJOSHADER_astBlockStatement *stmt)
926
927
928
929
930
931
932
{
DELETE_AST_NODE(stmt);
delete_statement(ctx, stmt->statements);
delete_statement(ctx, stmt->next);
Free(ctx, stmt);
} // delete_statement_block
933
934
935
936
937
938
static MOJOSHADER_astStatement *new_for_statement(Context *ctx,
MOJOSHADER_astVariableDeclaration *decl,
MOJOSHADER_astExpression *initializer,
MOJOSHADER_astExpression *looptest,
MOJOSHADER_astExpression *counter,
MOJOSHADER_astStatement *statement)
939
{
940
941
NEW_AST_NODE(retval, MOJOSHADER_astForStatement,
MOJOSHADER_AST_STATEMENT_FOR);
942
943
944
945
946
947
948
retval->next = NULL;
retval->unroll = -1;
retval->var_decl = decl;
retval->initializer = initializer;
retval->looptest = looptest;
retval->counter = counter;
retval->statement = statement;
949
return (MOJOSHADER_astStatement *) retval;
950
951
} // new_for_statement
952
static void delete_for_statement(Context *ctx,MOJOSHADER_astForStatement *stmt)
953
954
955
956
957
958
959
960
961
962
963
{
DELETE_AST_NODE(stmt);
delete_statement(ctx, stmt->next);
delete_variable_declaration(ctx, stmt->var_decl);
delete_expr(ctx, stmt->initializer);
delete_expr(ctx, stmt->looptest);
delete_expr(ctx, stmt->counter);
delete_statement(ctx, stmt->statement);
Free(ctx, stmt);
} // delete_for_statement
964
965
966
967
static MOJOSHADER_astStatement *new_do_statement(Context *ctx,
const int unroll,
MOJOSHADER_astStatement *stmt,
MOJOSHADER_astExpression *expr)
968
{
969
NEW_AST_NODE(retval,MOJOSHADER_astDoStatement,MOJOSHADER_AST_STATEMENT_DO);
970
971
972
973
retval->next = NULL;
retval->unroll = unroll;
retval->expr = expr;
retval->statement = stmt;
974
return (MOJOSHADER_astStatement *) retval;
975
976
} // new_do_statement
977
static void delete_do_statement(Context *ctx, MOJOSHADER_astDoStatement *stmt)
978
979
980
981
982
983
984
985
{
DELETE_AST_NODE(stmt);
delete_statement(ctx, stmt->next);
delete_statement(ctx, stmt->statement);
delete_expr(ctx, stmt->expr);
Free(ctx, stmt);
} // delete_do_statement
986
987
988
989
static MOJOSHADER_astStatement *new_while_statement(Context *ctx,
const int unroll,
MOJOSHADER_astExpression *expr,
MOJOSHADER_astStatement *stmt)
990
{
991
992
NEW_AST_NODE(retval, MOJOSHADER_astWhileStatement,
MOJOSHADER_AST_STATEMENT_WHILE);
993
994
995
996
retval->next = NULL;
retval->unroll = unroll;
retval->expr = expr;
retval->statement = stmt;
997
return (MOJOSHADER_astStatement *) retval;
998
999
} // new_while_statement
1000
static void delete_while_statement(Context *ctx,