Fixed a few outdated comments.
/**
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "mojoshader.h"
#ifdef _WIN32
#define snprintf _snprintf // !!! FIXME: not a safe replacement!
#endif
static const char **include_paths = NULL;
static unsigned int include_path_count = 0;
#define MOJOSHADER_DEBUG_MALLOC 0
#if MOJOSHADER_DEBUG_MALLOC
static void *Malloc(int len, void *d)
{
void *ptr = malloc(len + sizeof (int));
int *store = (int *) ptr;
printf("malloc() %d bytes (%p)\n", len, ptr);
if (ptr == NULL) return NULL;
*store = len;
return (void *) (store + 1);
} // Malloc
static void Free(void *_ptr, void *d)
{
int *ptr = (((int *) _ptr) - 1);
int len = *ptr;
printf("free() %d bytes (%p)\n", len, ptr);
free(ptr);
} // Free
#else
#define Malloc NULL
#define Free NULL
#endif
static void fail(const char *err)
{
printf("%s.\n", err);
exit(1);
} // fail
static void print_unroll_attr(FILE *io, const int unroll)
{
// -1 means "unroll at compiler's discretion",
// -2 means user didn't specify the attribute.
switch (unroll)
{
case 0:
fprintf(io, "[loop] ");
break;
case -1:
fprintf(io, "[unroll] ");
break;
case -2:
/* no-op. */
break;
default:
assert(unroll > 0);
fprintf(io, "[unroll(%d)] ", unroll);
break;
} // case
} // print_unroll_attr
static void print_ast_datatype(FILE *io, const MOJOSHADER_astDataType *dt)
{
int i;
if (dt == NULL)
return;
switch (dt->type)
{
case MOJOSHADER_AST_DATATYPE_BOOL:
fprintf(io, "bool");
return;
case MOJOSHADER_AST_DATATYPE_INT:
fprintf(io, "int");
return;
case MOJOSHADER_AST_DATATYPE_UINT:
fprintf(io, "uint");
return;
case MOJOSHADER_AST_DATATYPE_FLOAT:
fprintf(io, "float");
return;
case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM:
fprintf(io, "snorm float");
return;
case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM:
fprintf(io, "unorm float");
return;
case MOJOSHADER_AST_DATATYPE_HALF:
fprintf(io, "half");
return;
case MOJOSHADER_AST_DATATYPE_DOUBLE:
fprintf(io, "double");
return;
case MOJOSHADER_AST_DATATYPE_STRING:
fprintf(io, "string");
return;
case MOJOSHADER_AST_DATATYPE_SAMPLER_1D:
fprintf(io, "sampler1D");
return;
case MOJOSHADER_AST_DATATYPE_SAMPLER_2D:
fprintf(io, "sampler2D");
return;
case MOJOSHADER_AST_DATATYPE_SAMPLER_3D:
fprintf(io, "sampler3D");
return;
case MOJOSHADER_AST_DATATYPE_SAMPLER_CUBE:
fprintf(io, "samplerCUBE");
return;
case MOJOSHADER_AST_DATATYPE_SAMPLER_STATE:
fprintf(io, "sampler_state");
return;
case MOJOSHADER_AST_DATATYPE_SAMPLER_COMPARISON_STATE:
fprintf(io, "SamplerComparisonState");
return;
case MOJOSHADER_AST_DATATYPE_STRUCT:
fprintf(io, "struct { ");
for (i = 0; i < dt->structure.member_count; i++)
{
print_ast_datatype(io, dt->structure.members[i].datatype);
fprintf(io, " %s; ", dt->structure.members[i].identifier);
} // for
fprintf(io, "}");
return;
case MOJOSHADER_AST_DATATYPE_ARRAY:
print_ast_datatype(io, dt->array.base);
if (dt->array.elements < 0)
fprintf(io, "[]");
else
fprintf(io, "[%d]", dt->array.elements);
return;
case MOJOSHADER_AST_DATATYPE_VECTOR:
fprintf(io, "vector<");
print_ast_datatype(io, dt->vector.base);
fprintf(io, ",%d>", dt->vector.elements);
return;
case MOJOSHADER_AST_DATATYPE_MATRIX:
fprintf(io, "matrix<");
print_ast_datatype(io, dt->matrix.base);
fprintf(io, ",%d,%d>", dt->matrix.rows, dt->matrix.columns);
return;
case MOJOSHADER_AST_DATATYPE_BUFFER:
fprintf(io, "buffer<");
print_ast_datatype(io, dt->buffer.base);
fprintf(io, ">");
return;
case MOJOSHADER_AST_DATATYPE_USER:
fprintf(io, "%s", dt->user.name);
return;
// this should only appear if we did semantic analysis on the AST,
// so we only print the return value here.
case MOJOSHADER_AST_DATATYPE_FUNCTION:
if (!dt->function.retval)
fprintf(io, "void");
else
print_ast_datatype(io, dt->function.retval);
return;
//case MOJOSHADER_AST_DATATYPE_NONE:
default:
assert(0 && "Unexpected datatype.");
return;
} // switch
} // print_ast_datatype
// !!! FIXME: this screws up on order of operations.
static void print_ast(FILE *io, const int substmt, const void *_ast)
{
const MOJOSHADER_astNode *ast = (const MOJOSHADER_astNode *) _ast;
const char *nl = substmt ? "" : "\n";
int typeint = 0;
static int indent = 0;
int isblock = 0;
int i;
// These _HAVE_ to be in the same order as MOJOSHADER_astNodeType!
static const char *binary[] =
{
",", "*", "/", "%", "+", "-", "<<", ">>", "<", ">", "<=", ">=", "==",
"!=", "&", "^", "|", "&&", "||", "=", "*=", "/=", "%=", "+=", "-=",
"<<=", ">>=", "&=", "^=", "|="
};
static const char *pre_unary[] = { "++", "--", "-", "~", "!" };
static const char *post_unary[] = { "++", "--" };
static const char *simple_stmt[] = { "", "break", "continue", "discard" };
static const char *inpmod[] = { "", "in ", "out ", "in out ", "uniform " };
static const char *fnstorage[] = { "", "inline " };
static const char *interpmod[] = {
"", " linear", " centroid", " nointerpolation",
" noperspective", " sample"
};
if (!ast) return;
typeint = (int) ast->ast.type;
#define DO_INDENT do { \
if (!substmt) { for (i = 0; i < indent; i++) fprintf(io, " "); } \
} while (0)
switch (ast->ast.type)
{
case MOJOSHADER_AST_OP_PREINCREMENT:
case MOJOSHADER_AST_OP_PREDECREMENT:
case MOJOSHADER_AST_OP_NEGATE:
case MOJOSHADER_AST_OP_COMPLEMENT:
case MOJOSHADER_AST_OP_NOT:
fprintf(io, "%s", pre_unary[(typeint-MOJOSHADER_AST_OP_START_RANGE_UNARY)-1]);
print_ast(io, 0, ast->unary.operand);
break;
case MOJOSHADER_AST_OP_POSTINCREMENT:
case MOJOSHADER_AST_OP_POSTDECREMENT:
print_ast(io, 0, ast->unary.operand);
fprintf(io, "%s", post_unary[typeint-MOJOSHADER_AST_OP_POSTINCREMENT]);
break;
case MOJOSHADER_AST_OP_MULTIPLY:
case MOJOSHADER_AST_OP_DIVIDE:
case MOJOSHADER_AST_OP_MODULO:
case MOJOSHADER_AST_OP_ADD:
case MOJOSHADER_AST_OP_SUBTRACT:
case MOJOSHADER_AST_OP_LSHIFT:
case MOJOSHADER_AST_OP_RSHIFT:
case MOJOSHADER_AST_OP_LESSTHAN:
case MOJOSHADER_AST_OP_GREATERTHAN:
case MOJOSHADER_AST_OP_LESSTHANOREQUAL:
case MOJOSHADER_AST_OP_GREATERTHANOREQUAL:
case MOJOSHADER_AST_OP_EQUAL:
case MOJOSHADER_AST_OP_NOTEQUAL:
case MOJOSHADER_AST_OP_BINARYAND:
case MOJOSHADER_AST_OP_BINARYXOR:
case MOJOSHADER_AST_OP_BINARYOR:
case MOJOSHADER_AST_OP_LOGICALAND:
case MOJOSHADER_AST_OP_LOGICALOR:
case MOJOSHADER_AST_OP_ASSIGN:
case MOJOSHADER_AST_OP_MULASSIGN:
case MOJOSHADER_AST_OP_DIVASSIGN:
case MOJOSHADER_AST_OP_MODASSIGN:
case MOJOSHADER_AST_OP_ADDASSIGN:
case MOJOSHADER_AST_OP_SUBASSIGN:
case MOJOSHADER_AST_OP_LSHIFTASSIGN:
case MOJOSHADER_AST_OP_RSHIFTASSIGN:
case MOJOSHADER_AST_OP_ANDASSIGN:
case MOJOSHADER_AST_OP_XORASSIGN:
case MOJOSHADER_AST_OP_ORASSIGN:
case MOJOSHADER_AST_OP_COMMA:
print_ast(io, 0, ast->binary.left);
if (ast->ast.type != MOJOSHADER_AST_OP_COMMA)
fprintf(io, " "); // no space before the comma.
fprintf(io, "%s ", binary[
(typeint - MOJOSHADER_AST_OP_START_RANGE_BINARY) - 1]);
print_ast(io, 0, ast->binary.right);
break;
case MOJOSHADER_AST_OP_DEREF_ARRAY:
print_ast(io, 0, ast->binary.left);
fprintf(io, "[");
print_ast(io, 0, ast->binary.right);
fprintf(io, "]");
break;
case MOJOSHADER_AST_OP_DEREF_STRUCT:
print_ast(io, 0, ast->derefstruct.identifier);
fprintf(io, ".");
fprintf(io, "%s", ast->derefstruct.member);
break;
case MOJOSHADER_AST_OP_CONDITIONAL:
print_ast(io, 0, ast->ternary.left);
fprintf(io, " ? ");
print_ast(io, 0, ast->ternary.center);
fprintf(io, " : ");
print_ast(io, 0, ast->ternary.right);
break;
case MOJOSHADER_AST_OP_IDENTIFIER:
fprintf(io, "%s", ast->identifier.identifier);
break;
case MOJOSHADER_AST_OP_INT_LITERAL:
fprintf(io, "%d", ast->intliteral.value);
break;
case MOJOSHADER_AST_OP_FLOAT_LITERAL:
{
const float f = ast->floatliteral.value;
const long long flr = (long long) f;
if (((float) flr) == f)
fprintf(io, "%lld.0", flr);
else
fprintf(io, "%.16g", f);
break;
} // case
case MOJOSHADER_AST_OP_STRING_LITERAL:
fprintf(io, "\"%s\"", ast->stringliteral.string);
break;
case MOJOSHADER_AST_OP_BOOLEAN_LITERAL:
fprintf(io, "%s", ast->boolliteral.value ? "true" : "false");
break;
case MOJOSHADER_AST_ARGUMENTS:
print_ast(io, 0, ast->arguments.argument);
if (ast->arguments.next != NULL)
{
fprintf(io, ", ");
print_ast(io, 0, ast->arguments.next);
} // if
break;
case MOJOSHADER_AST_OP_CALLFUNC:
print_ast(io, 0, ast->callfunc.identifier);
fprintf(io, "(");
print_ast(io, 0, ast->callfunc.args);
fprintf(io, ")");
break;
case MOJOSHADER_AST_OP_CONSTRUCTOR:
print_ast_datatype(io, ast->constructor.datatype);
fprintf(io, "(");
print_ast(io, 0, ast->constructor.args);
fprintf(io, ")");
break;
case MOJOSHADER_AST_OP_CAST:
fprintf(io, "(");
print_ast_datatype(io, ast->cast.datatype);
fprintf(io, ") (");
print_ast(io, 0, ast->cast.operand);
fprintf(io, ")");
break;
case MOJOSHADER_AST_STATEMENT_EXPRESSION:
DO_INDENT;
print_ast(io, 0, ast->exprstmt.expr); // !!! FIXME: This is named badly...
fprintf(io, ";%s", nl);
print_ast(io, 0, ast->exprstmt.next);
break;
case MOJOSHADER_AST_STATEMENT_IF:
DO_INDENT;
fprintf(io, "if (");
print_ast(io, 0, ast->ifstmt.expr);
fprintf(io, ")\n");
isblock = ast->ifstmt.statement->ast.type == MOJOSHADER_AST_STATEMENT_BLOCK;
if (!isblock) indent++;
print_ast(io, 0, ast->ifstmt.statement);
if (!isblock) indent--;
print_ast(io, 0, ast->ifstmt.next);
break;
case MOJOSHADER_AST_STATEMENT_TYPEDEF:
DO_INDENT;
print_ast(io, 1, ast->typedefstmt.type_info);
fprintf(io, "%s", nl);
print_ast(io, 0, ast->typedefstmt.next);
break;
case MOJOSHADER_AST_STATEMENT_SWITCH:
DO_INDENT;
switch ( ast->switchstmt.attributes )
{
case MOJOSHADER_AST_SWITCHATTR_NONE: break;
case MOJOSHADER_AST_SWITCHATTR_FLATTEN: fprintf(io, "[flatten] "); break;
case MOJOSHADER_AST_SWITCHATTR_BRANCH: fprintf(io, "[branch] "); break;
case MOJOSHADER_AST_SWITCHATTR_FORCECASE: fprintf(io, "[forcecase] "); break;
case MOJOSHADER_AST_SWITCHATTR_CALL: fprintf(io, "[call] "); break;
} // switch
fprintf(io, "switch (");
print_ast(io, 0, ast->switchstmt.expr);
fprintf(io, ")\n");
DO_INDENT;
fprintf(io, "{\n");
indent++;
print_ast(io, 0, ast->switchstmt.cases);
indent--;
fprintf(io, "\n");
DO_INDENT;
fprintf(io, "}\n");
print_ast(io, 0, ast->switchstmt.next);
break;
case MOJOSHADER_AST_SWITCH_CASE:
DO_INDENT;
fprintf(io, "case ");
print_ast(io, 0, ast->cases.expr);
fprintf(io, ":\n");
isblock = ast->cases.statement->ast.type == MOJOSHADER_AST_STATEMENT_BLOCK;
if (!isblock) indent++;
print_ast(io, 0, ast->cases.statement);
if (!isblock) indent--;
print_ast(io, 0, ast->cases.next);
break;
case MOJOSHADER_AST_STATEMENT_STRUCT:
DO_INDENT;
print_ast(io, 0, ast->structstmt.struct_info);
fprintf(io, ";%s%s", nl, nl); // always space these out.
print_ast(io, 0, ast->structstmt.next);
break;
case MOJOSHADER_AST_STATEMENT_VARDECL:
DO_INDENT;
print_ast(io, 1, ast->vardeclstmt.declaration);
fprintf(io, ";%s", nl);
print_ast(io, 0, ast->vardeclstmt.next);
break;
case MOJOSHADER_AST_STATEMENT_BLOCK:
DO_INDENT;
fprintf(io, "{\n");
indent++;
print_ast(io, 0, ast->blockstmt.statements);
indent--;
DO_INDENT;
fprintf(io, "}\n");
print_ast(io, 0, ast->blockstmt.next);
break;
case MOJOSHADER_AST_STATEMENT_FOR:
DO_INDENT;
print_unroll_attr(io, ast->forstmt.unroll);
fprintf(io, "for (");
print_ast(io, 1, ast->forstmt.var_decl);
print_ast(io, 1, ast->forstmt.initializer);
fprintf(io, "; ");
print_ast(io, 1, ast->forstmt.looptest);
fprintf(io, "; ");
print_ast(io, 1, ast->forstmt.counter);
fprintf(io, ")\n");
isblock = ast->forstmt.statement->ast.type == MOJOSHADER_AST_STATEMENT_BLOCK;
if (!isblock) indent++;
print_ast(io, 0, ast->forstmt.statement);
if (!isblock) indent--;
print_ast(io, 0, ast->forstmt.next);
break;
case MOJOSHADER_AST_STATEMENT_DO:
DO_INDENT;
print_unroll_attr(io, ast->dostmt.unroll);
fprintf(io, "do\n");
isblock = ast->dostmt.statement->ast.type == MOJOSHADER_AST_STATEMENT_BLOCK;
if (!isblock) indent++;
print_ast(io, 0, ast->dostmt.statement);
if (!isblock) indent--;
DO_INDENT;
fprintf(io, "while (");
print_ast(io, 0, ast->dostmt.expr);
fprintf(io, ");\n");
print_ast(io, 0, ast->dostmt.next);
break;
case MOJOSHADER_AST_STATEMENT_WHILE:
DO_INDENT;
print_unroll_attr(io, ast->whilestmt.unroll);
fprintf(io, "while (");
print_ast(io, 0, ast->whilestmt.expr);
fprintf(io, ")\n");
isblock = ast->whilestmt.statement->ast.type == MOJOSHADER_AST_STATEMENT_BLOCK;
if (!isblock) indent++;
print_ast(io, 0, ast->whilestmt.statement);
if (!isblock) indent--;
print_ast(io, 0, ast->whilestmt.next);
break;
case MOJOSHADER_AST_STATEMENT_RETURN:
DO_INDENT;
fprintf(io, "return");
if (ast->returnstmt.expr)
{
fprintf(io, " ");
print_ast(io, 0, ast->returnstmt.expr);
} // if
fprintf(io, ";%s", nl);
print_ast(io, 0, ast->returnstmt.next);
break;
case MOJOSHADER_AST_STATEMENT_EMPTY:
case MOJOSHADER_AST_STATEMENT_BREAK:
case MOJOSHADER_AST_STATEMENT_CONTINUE:
case MOJOSHADER_AST_STATEMENT_DISCARD:
DO_INDENT;
fprintf(io, "%s;%s",
simple_stmt[(typeint-MOJOSHADER_AST_STATEMENT_START_RANGE)-1],
nl);
print_ast(io, 0, ast->stmt.next);
break;
case MOJOSHADER_AST_COMPUNIT_FUNCTION:
DO_INDENT;
print_ast(io, 0, ast->funcunit.declaration);
if (ast->funcunit.definition == NULL)
fprintf(io, ";%s", nl);
else
{
fprintf(io, "%s", nl);
print_ast(io, 0, ast->funcunit.definition);
fprintf(io, "%s", nl);
} // else
print_ast(io, 0, ast->funcunit.next);
break;
case MOJOSHADER_AST_COMPUNIT_TYPEDEF:
DO_INDENT;
print_ast(io, 0, ast->typedefunit.type_info);
fprintf(io, "%s", nl);
print_ast(io, 0, ast->typedefunit.next);
break;
case MOJOSHADER_AST_COMPUNIT_STRUCT:
DO_INDENT;
print_ast(io, 0, ast->structunit.struct_info);
fprintf(io, ";%s%s", nl, nl); // always space these out.
print_ast(io, 0, ast->structunit.next);
break;
case MOJOSHADER_AST_COMPUNIT_VARIABLE:
DO_INDENT;
print_ast(io, 1, ast->varunit.declaration);
fprintf(io, ";%s", nl);
if (ast->varunit.next &&
ast->varunit.next->ast.type!=MOJOSHADER_AST_COMPUNIT_VARIABLE)
{
fprintf(io, "%s", nl); // group vars together, and space out other things.
} // if
print_ast(io, 0, ast->varunit.next);
break;
case MOJOSHADER_AST_SCALAR_OR_ARRAY:
fprintf(io, "%s", ast->soa.identifier);
if (ast->soa.isarray)
{
fprintf(io, "[");
print_ast(io, 0, ast->soa.dimension);
fprintf(io, "]");
} // if
break;
case MOJOSHADER_AST_TYPEDEF:
DO_INDENT;
fprintf(io, "typedef %s", ast->typdef.isconst ? "const " : "");
print_ast_datatype(io, ast->typdef.datatype);
fprintf(io, " ");
print_ast(io, 0, ast->typdef.details);
fprintf(io, ";%s", nl);
break;
case MOJOSHADER_AST_FUNCTION_PARAMS:
fprintf(io, "%s", inpmod[(int) ast->params.input_modifier]);
print_ast_datatype(io, ast->params.datatype);
fprintf(io, " %s", ast->params.identifier);
if (ast->params.semantic)
fprintf(io, " : %s", ast->params.semantic);
fprintf(io, "%s", interpmod[(int) ast->params.interpolation_modifier]);
if (ast->params.initializer)
{
fprintf(io, " = ");
print_ast(io, 0, ast->params.initializer);
} // if
if (ast->params.next)
{
fprintf(io, ", ");
print_ast(io, 0, ast->params.next);
} // if
break;
case MOJOSHADER_AST_FUNCTION_SIGNATURE:
fprintf(io, "%s", fnstorage[(int) ast->funcsig.storage_class]);
if (ast->funcsig.datatype)
print_ast_datatype(io, ast->funcsig.datatype);
else
fprintf(io, "void");
fprintf(io, " %s(", ast->funcsig.identifier);
print_ast(io, 0, ast->funcsig.params);
fprintf(io, ")");
if (ast->funcsig.semantic)
fprintf(io, " : %s", ast->funcsig.semantic);
break;
case MOJOSHADER_AST_STRUCT_DECLARATION:
fprintf(io, "struct %s\n", ast->structdecl.name);
DO_INDENT;
fprintf(io, "{\n");
indent++;
print_ast(io, 0, ast->structdecl.members);
indent--;
DO_INDENT;
fprintf(io, "}");
break;
case MOJOSHADER_AST_STRUCT_MEMBER:
DO_INDENT;
fprintf(io, "%s", interpmod[(int)ast->structmembers.interpolation_mod]);
print_ast_datatype(io, ast->structmembers.datatype);
fprintf(io, " ");
print_ast(io, 0, ast->structmembers.details);
if (ast->structmembers.semantic)
fprintf(io, " : %s", ast->structmembers.semantic);
fprintf(io, ";%s", nl);
print_ast(io, 0, ast->structmembers.next);
break;
case MOJOSHADER_AST_VARIABLE_DECLARATION:
DO_INDENT;
if (ast->vardecl.attributes & MOJOSHADER_AST_VARATTR_EXTERN)
fprintf(io, "extern ");
if (ast->vardecl.attributes & MOJOSHADER_AST_VARATTR_NOINTERPOLATION)
fprintf(io, "nointerpolation ");
if (ast->vardecl.attributes & MOJOSHADER_AST_VARATTR_SHARED)
fprintf(io, "shared");
if (ast->vardecl.attributes & MOJOSHADER_AST_VARATTR_STATIC)
fprintf(io, "static ");
if (ast->vardecl.attributes & MOJOSHADER_AST_VARATTR_UNIFORM)
fprintf(io, "uniform ");
if (ast->vardecl.attributes & MOJOSHADER_AST_VARATTR_VOLATILE)
fprintf(io, "nointerpolation ");
if (ast->vardecl.attributes & MOJOSHADER_AST_VARATTR_CONST)
fprintf(io, "const ");
if (ast->vardecl.attributes & MOJOSHADER_AST_VARATTR_ROWMAJOR)
fprintf(io, "rowmajor ");
if (ast->vardecl.attributes & MOJOSHADER_AST_VARATTR_COLUMNMAJOR)
fprintf(io, "columnmajor ");
if (ast->vardecl.datatype)
print_ast_datatype(io, ast->vardecl.datatype);
else
print_ast(io, 0, ast->vardecl.anonymous_datatype);
fprintf(io, " ");
print_ast(io, 0, ast->vardecl.details);
if (ast->vardecl.semantic)
fprintf(io, " : %s", ast->vardecl.semantic);
if (ast->vardecl.annotations)
{
fprintf(io, " ");
print_ast(io, 0, ast->vardecl.annotations);
} // if
if (ast->vardecl.initializer != NULL)
{
fprintf(io, " = ");
print_ast(io, 0, ast->vardecl.initializer);
} // if
print_ast(io, 0, ast->vardecl.lowlevel);
if (ast->vardecl.next == NULL)
fprintf(io, "%s", nl);
else
{
const int attr = ast->vardecl.next->attributes;
fprintf(io, ", ");
ast->vardecl.next->attributes = 0;
print_ast(io, 1, ast->vardecl.next);
ast->vardecl.next->attributes = attr;
} // if
break;
case MOJOSHADER_AST_PACK_OFFSET:
fprintf(io, " : packoffset(%s%s%s)", ast->packoffset.ident1,
ast->packoffset.ident2 ? "." : "",
ast->packoffset.ident2 ? ast->packoffset.ident2 : "");
break;
case MOJOSHADER_AST_VARIABLE_LOWLEVEL:
print_ast(io, 0, ast->varlowlevel.packoffset);
if (ast->varlowlevel.register_name)
fprintf(io, " : register(%s)", ast->varlowlevel.register_name);
break;
case MOJOSHADER_AST_ANNOTATION:
{
const MOJOSHADER_astAnnotations *a = &ast->annotations;
fprintf(io, "<");
while (a)
{
fprintf(io, " ");
print_ast_datatype(io, a->datatype);
if (a->initializer != NULL)
{
fprintf(io, " = ");
print_ast(io, 0, a->initializer);
} // if
if (a->next)
fprintf(io, ",");
a = a->next;
} // while
fprintf(io, " >");
break;
} // case
default:
assert(0 && "unexpected type");
break;
} // switch
#undef DO_INDENT
} // print_ast
static int open_include(MOJOSHADER_includeType inctype, const char *fname,
const char *parent, const char **outdata,
unsigned int *outbytes, MOJOSHADER_malloc m,
MOJOSHADER_free f, void *d)
{
int i;
for (i = 0; i < include_path_count; i++)
{
const char *path = include_paths[i];
const size_t len = strlen(path) + strlen(fname) + 2;
char *buf = (char *) m(len, d);
if (buf == NULL)
return 0;
snprintf(buf, len, "%s/%s", path, fname);
FILE *io = fopen(buf, "rb");
f(buf, d);
if (io == NULL)
continue;
if (fseek(io, 0, SEEK_END) != -1)
{
const long fsize = ftell(io);
if ((fsize == -1) || (fseek(io, 0, SEEK_SET) == -1))
{
fclose(io);
return 0;
} // if
char *data = (char *) m(fsize, d);
if (data == NULL)
{
fclose(io);
return 0;
} // if
if (fread(data, fsize, 1, io) != 1)
{
f(data, d);
fclose(io);
return 0;
} // if
fclose(io);
*outdata = data;
*outbytes = (unsigned int) fsize;
return 1;
} // if
} // for
return 0;
} // open_include
static void close_include(const char *data, MOJOSHADER_malloc m,
MOJOSHADER_free f, void *d)
{
f((void *) data, d);
} // close_include
static int preprocess(const char *fname, const char *buf, int len,
const char *outfile,
const MOJOSHADER_preprocessorDefine *defs,
unsigned int defcount, FILE *io)
{
const MOJOSHADER_preprocessData *pd;
int retval = 0;
pd = MOJOSHADER_preprocess(fname, buf, len, defs, defcount, open_include,
close_include, Malloc, Free, NULL);
if (pd->error_count > 0)
{
int i;
for (i = 0; i < pd->error_count; i++)
{
fprintf(stderr, "%s:%d: ERROR: %s\n",
pd->errors[i].filename ? pd->errors[i].filename : "???",
pd->errors[i].error_position,
pd->errors[i].error);
} // for
} // if
else
{
if (pd->output != NULL)
{
const int len = pd->output_len;
if ((len) && (fwrite(pd->output, len, 1, io) != 1))
printf(" ... fwrite('%s') failed.\n", outfile);
else if ((outfile != NULL) && (fclose(io) == EOF))
printf(" ... fclose('%s') failed.\n", outfile);
else
retval = 1;
} // if
} // else
MOJOSHADER_freePreprocessData(pd);
return retval;
} // preprocess
static int assemble(const char *fname, const char *buf, int len,
const char *outfile,
const MOJOSHADER_preprocessorDefine *defs,
unsigned int defcount, FILE *io)
{
const MOJOSHADER_parseData *pd;
int retval = 0;
pd = MOJOSHADER_assemble(fname, buf, len, NULL, 0, NULL, 0,
defs, defcount, open_include, close_include,
Malloc, Free, NULL);
if (pd->error_count > 0)
{
int i;
for (i = 0; i < pd->error_count; i++)
{
fprintf(stderr, "%s:%d: ERROR: %s\n",
pd->errors[i].filename ? pd->errors[i].filename : "???",
pd->errors[i].error_position,
pd->errors[i].error);
} // for
} // if
else
{
if (pd->output != NULL)
{
const int len = pd->output_len;
if ((len) && (fwrite(pd->output, len, 1, io) != 1))
printf(" ... fwrite('%s') failed.\n", outfile);
else if ((outfile != NULL) && (fclose(io) == EOF))
printf(" ... fclose('%s') failed.\n", outfile);
else
retval = 1;
} // if
} // else
MOJOSHADER_freeParseData(pd);
return retval;
} // assemble
static int ast(const char *fname, const char *buf, int len,
const char *outfile, const MOJOSHADER_preprocessorDefine *defs,
unsigned int defcount, FILE *io)
{
const MOJOSHADER_astData *ad;
int retval = 0;
ad = MOJOSHADER_parseAst(MOJOSHADER_SRC_PROFILE_HLSL_PS_1_1, // !!! FIXME
fname, buf, len, defs, defcount,
open_include, close_include, Malloc, Free, NULL);
if (ad->error_count > 0)
{
int i;
for (i = 0; i < ad->error_count; i++)
{
fprintf(stderr, "%s:%d: ERROR: %s\n",
ad->errors[i].filename ? ad->errors[i].filename : "???",
ad->errors[i].error_position,
ad->errors[i].error);
} // for
} // if
else
{
print_ast(io, 0, ad->ast);
if ((outfile != NULL) && (fclose(io) == EOF))
printf(" ... fclose('%s') failed.\n", outfile);
else
retval = 1;
} // else
MOJOSHADER_freeAstData(ad);
return retval;
} // ast
static int compile(const char *fname, const char *buf, int len,
const char *outfile,
const MOJOSHADER_preprocessorDefine *defs,
unsigned int defcount, FILE *io)
{
// !!! FIXME: write me.
//const MOJOSHADER_parseData *pd;
//int retval = 0;
MOJOSHADER_compile(MOJOSHADER_SRC_PROFILE_HLSL_PS_1_1, // !!! FIXME
fname, buf, len, defs, defcount,
open_include, close_include,
Malloc, Free, NULL);
return 1;
} // compile
typedef enum
{
ACTION_UNKNOWN,
ACTION_VERSION,
ACTION_PREPROCESS,
ACTION_ASSEMBLE,
ACTION_AST,
ACTION_COMPILE,
} Action;
int main(int argc, char **argv)
{
Action action = ACTION_UNKNOWN;
int retval = 1;
const char *infile = NULL;
const char *outfile = NULL;
int i;
MOJOSHADER_preprocessorDefine *defs = NULL;
unsigned int defcount = 0;
include_paths = (const char **) malloc(sizeof (char *));
include_paths[0] = ".";
include_path_count = 1;
// !!! FIXME: clean this up.
for (i = 1; i < argc; i++)
{
const char *arg = argv[i];
if (strcmp(arg, "-P") == 0)
{
if ((action != ACTION_UNKNOWN) && (action != ACTION_PREPROCESS))
fail("Multiple actions specified");
action = ACTION_PREPROCESS;
} // if
else if (strcmp(arg, "-A") == 0)
{
if ((action != ACTION_UNKNOWN) && (action != ACTION_ASSEMBLE))
fail("Multiple actions specified");
action = ACTION_ASSEMBLE;
} // else if
else if (strcmp(arg, "-T") == 0)
{
if ((action != ACTION_UNKNOWN) && (action != ACTION_AST))
fail("Multiple actions specified");
action = ACTION_AST;
} // else if
else if (strcmp(arg, "-C") == 0)
{
if ((action != ACTION_UNKNOWN) && (action != ACTION_COMPILE))
fail("Multiple actions specified");
action = ACTION_COMPILE;
} // else if
else if ((strcmp(arg, "-V") == 0) || (strcmp(arg, "--version") == 0))
{
if ((action != ACTION_UNKNOWN) && (action != ACTION_VERSION))
fail("Multiple actions specified");
action = ACTION_VERSION;
} // else if
else if (strcmp(arg, "-o") == 0)
{
if (outfile != NULL)
fail("multiple output files specified");
arg = argv[++i];
if (arg == NULL)
fail("no filename after '-o'");
outfile = arg;
} // if
else if (strcmp(arg, "-I") == 0)
{
arg = argv[++i];
if (arg == NULL)
fail("no path after '-I'");
include_paths = (const char **) realloc(include_paths,
(include_path_count+1) * sizeof (char *));
include_paths[include_path_count] = arg;
include_path_count++;
} // if
else if (strncmp(arg, "-D", 2) == 0)
{
arg += 2;
char *ident = strdup(arg);
char *ptr = strchr(ident, '=');
const char *val = "";
if (ptr)
{
*ptr = '\0';
val = ptr+1;
} // if
defs = (MOJOSHADER_preprocessorDefine *) realloc(defs,
(defcount+1) * sizeof (MOJOSHADER_preprocessorDefine));
defs[defcount].identifier = ident;
defs[defcount].definition = val;
defcount++;
} // else if
else
{
if (infile != NULL)
fail("multiple input files specified");
infile = arg;
} // else
} // for
if (action == ACTION_UNKNOWN)
action = ACTION_ASSEMBLE;
if (action == ACTION_VERSION)
{
printf("mojoshader-compiler, changeset %s\n", MOJOSHADER_CHANGESET);
return 0;
} // if
if (infile == NULL)
fail("no input file specified");
FILE *io = fopen(infile, "rb");
if (io == NULL)
fail("failed to open input file");
fseek(io, 0, SEEK_END);
long fsize = ftell(io);
fseek(io, 0, SEEK_SET);
if (fsize == -1)
fsize = 1000000;
char *buf = (char *) malloc(fsize);
const int rc = fread(buf, 1, fsize, io);
fclose(io);
if (rc == EOF)
fail("failed to read input file");
FILE *outio = outfile ? fopen(outfile, "wb") : stdout;
if (outio == NULL)
fail("failed to open output file");
if (action == ACTION_PREPROCESS)
retval = (!preprocess(infile, buf, rc, outfile, defs, defcount, outio));
else if (action == ACTION_ASSEMBLE)
retval = (!assemble(infile, buf, rc, outfile, defs, defcount, outio));
else if (action == ACTION_AST)
retval = (!ast(infile, buf, rc, outfile, defs, defcount, outio));
else if (action == ACTION_COMPILE)
retval = (!compile(infile, buf, rc, outfile, defs, defcount, outio));
if ((retval != 0) && (outfile != NULL))
remove(outfile);
free(buf);
for (i = 0; i < defcount; i++)
free((void *) defs[i].identifier);
free(defs);
free(include_paths);
return retval;
} // main
// end of mojoshader-compiler.c ...