Reworked datatype processing in the compiler.
Now we can track this better without screwing around with strings.
Also, printing the AST is sane now, since it never handled datatype strings
correctly, anyhow.
/**
* 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)
{
if (unroll == 0)
fprintf(io, "[loop] ");
else if (unroll < 0)
fprintf(io, "[unroll] ");
else
fprintf(io, "[unroll(%d)] ", unroll);
} // 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;
//case MOJOSHADER_AST_DATATYPE_NONE:
//case MOJOSHADER_AST_DATATYPE_FUNCTION:
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);
if (ast->forstmt.initializer != NULL)
{
fprintf(io, " = ");
print_ast(io, 1, ast->forstmt.initializer);
} // if
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 ...