Heavy rework of the AST code.
authorRyan C. Gordon <icculus@icculus.org>
Thu, 28 Oct 2010 03:42:12 -0400
changeset 931 4aa1f68d8292
parent 930 cedd05bc6290
child 932 079c62f868eb
Heavy rework of the AST code. Moved AST stuff to a public API and filled in AST and compile API stubs. print_ast() has been cleaned up, and moved from MojoShader to the compiler application. type_check_ast() is much cleaner, too. This has turned into a massive (and incomplete) undertaking. Next steps are filling in the formal API code, moving the AST stuff to a separate file, and wiring it up to the compiler application. (Not to mention polishing up semantic analysis, finishing up the IR, reworking the nasty datatype system, etc, etc, etc...)
mojoshader.h
mojoshader_compiler.c
mojoshader_parser_hlsl.lemon
utils/mojoshader-compiler.c
--- a/mojoshader.h	Tue Oct 26 17:27:31 2010 -0400
+++ b/mojoshader.h	Thu Oct 28 03:42:12 2010 -0400
@@ -882,6 +882,865 @@
                              MOJOSHADER_malloc m, MOJOSHADER_free f, void *d);
 
 
+/* High level shading language support... */
+
+/*
+ * Source profile strings for HLSL: Direct3D High Level Shading Language.
+ */
+#define MOJOSHADER_SRC_PROFILE_HLSL_VS_1_1 "hlsl_vs_1_1"
+#define MOJOSHADER_SRC_PROFILE_HLSL_VS_2_0 "hlsl_vs_2_0"
+#define MOJOSHADER_SRC_PROFILE_HLSL_VS_3_0 "hlsl_vs_3_0"
+#define MOJOSHADER_SRC_PROFILE_HLSL_PS_1_1 "hlsl_ps_1_1"
+#define MOJOSHADER_SRC_PROFILE_HLSL_PS_1_2 "hlsl_ps_1_2"
+#define MOJOSHADER_SRC_PROFILE_HLSL_PS_1_3 "hlsl_ps_1_3"
+#define MOJOSHADER_SRC_PROFILE_HLSL_PS_1_4 "hlsl_ps_1_4"
+#define MOJOSHADER_SRC_PROFILE_HLSL_PS_2_0 "hlsl_ps_2_0"
+#define MOJOSHADER_SRC_PROFILE_HLSL_PS_3_0 "hlsl_ps_3_0"
+
+
+/* Abstract Syntax Tree interface... */
+
+/*
+ * ATTENTION: This adds a lot of stuff to the API, but almost everyone can
+ *  ignore this section. Seriously, go ahead and skip over anything that has
+ *  "AST" in it, unless you know why you'd want to use it.
+ *
+ * ALSO: This API is still evolving! We make no promises at this time to keep
+ *  source or binary compatibility for the AST pieces.
+ */
+
+/* Structures that make up the parse tree... */
+
+typedef enum MOJOSHADER_astNodeType
+{
+    MOJOSHADER_AST_OP_START_RANGE,         /* expression operators. */
+
+    MOJOSHADER_AST_OP_START_RANGE_UNARY,   /* unary operators. */
+    MOJOSHADER_AST_OP_PREINCREMENT,
+    MOJOSHADER_AST_OP_PREDECREMENT,
+    MOJOSHADER_AST_OP_NEGATE,
+    MOJOSHADER_AST_OP_COMPLEMENT,
+    MOJOSHADER_AST_OP_NOT,
+    MOJOSHADER_AST_OP_POSTINCREMENT,
+    MOJOSHADER_AST_OP_POSTDECREMENT,
+    MOJOSHADER_AST_OP_END_RANGE_UNARY,
+
+    MOJOSHADER_AST_OP_START_RANGE_BINARY,  /* binary operators. */
+    MOJOSHADER_AST_OP_COMMA,
+    MOJOSHADER_AST_OP_MULTIPLY,
+    MOJOSHADER_AST_OP_DIVIDE,
+    MOJOSHADER_AST_OP_MODULO,
+    MOJOSHADER_AST_OP_ADD,
+    MOJOSHADER_AST_OP_SUBTRACT,
+    MOJOSHADER_AST_OP_LSHIFT,
+    MOJOSHADER_AST_OP_RSHIFT,
+    MOJOSHADER_AST_OP_LESSTHAN,
+    MOJOSHADER_AST_OP_GREATERTHAN,
+    MOJOSHADER_AST_OP_LESSTHANOREQUAL,
+    MOJOSHADER_AST_OP_GREATERTHANOREQUAL,
+    MOJOSHADER_AST_OP_EQUAL,
+    MOJOSHADER_AST_OP_NOTEQUAL,
+    MOJOSHADER_AST_OP_BINARYAND,
+    MOJOSHADER_AST_OP_BINARYXOR,
+    MOJOSHADER_AST_OP_BINARYOR,
+    MOJOSHADER_AST_OP_LOGICALAND,
+    MOJOSHADER_AST_OP_LOGICALOR,
+    MOJOSHADER_AST_OP_ASSIGN,
+    MOJOSHADER_AST_OP_MULASSIGN,
+    MOJOSHADER_AST_OP_DIVASSIGN,
+    MOJOSHADER_AST_OP_MODASSIGN,
+    MOJOSHADER_AST_OP_ADDASSIGN,
+    MOJOSHADER_AST_OP_SUBASSIGN,
+    MOJOSHADER_AST_OP_LSHIFTASSIGN,
+    MOJOSHADER_AST_OP_RSHIFTASSIGN,
+    MOJOSHADER_AST_OP_ANDASSIGN,
+    MOJOSHADER_AST_OP_XORASSIGN,
+    MOJOSHADER_AST_OP_ORASSIGN,
+    MOJOSHADER_AST_OP_DEREF_ARRAY,
+    MOJOSHADER_AST_OP_END_RANGE_BINARY,
+
+    MOJOSHADER_AST_OP_START_RANGE_TERNARY,  /* ternary operators. */
+    MOJOSHADER_AST_OP_CONDITIONAL,
+    MOJOSHADER_AST_OP_END_RANGE_TERNARY,
+
+    MOJOSHADER_AST_OP_START_RANGE_DATA,     /* expression operands. */
+    MOJOSHADER_AST_OP_IDENTIFIER,
+    MOJOSHADER_AST_OP_INT_LITERAL,
+    MOJOSHADER_AST_OP_FLOAT_LITERAL,
+    MOJOSHADER_AST_OP_STRING_LITERAL,
+    MOJOSHADER_AST_OP_BOOLEAN_LITERAL,
+    MOJOSHADER_AST_OP_END_RANGE_DATA,
+
+    MOJOSHADER_AST_OP_START_RANGE_MISC,     /* other expression things. */
+    MOJOSHADER_AST_OP_DEREF_STRUCT,
+    MOJOSHADER_AST_OP_CALLFUNC,
+    MOJOSHADER_AST_OP_CONSTRUCTOR,
+    MOJOSHADER_AST_OP_CAST,
+    MOJOSHADER_AST_OP_END_RANGE_MISC,
+    MOJOSHADER_AST_OP_END_RANGE,
+
+    MOJOSHADER_AST_COMPUNIT_START_RANGE,    /* things in global scope. */
+    MOJOSHADER_AST_COMPUNIT_FUNCTION,
+    MOJOSHADER_AST_COMPUNIT_TYPEDEF,
+    MOJOSHADER_AST_COMPUNIT_STRUCT,
+    MOJOSHADER_AST_COMPUNIT_VARIABLE,
+    MOJOSHADER_AST_COMPUNIT_END_RANGE,
+
+    MOJOSHADER_AST_STATEMENT_START_RANGE,   /* statements in function scope. */
+    MOJOSHADER_AST_STATEMENT_EMPTY,
+    MOJOSHADER_AST_STATEMENT_BREAK,
+    MOJOSHADER_AST_STATEMENT_CONTINUE,
+    MOJOSHADER_AST_STATEMENT_DISCARD,
+    MOJOSHADER_AST_STATEMENT_BLOCK,
+    MOJOSHADER_AST_STATEMENT_EXPRESSION,
+    MOJOSHADER_AST_STATEMENT_IF,
+    MOJOSHADER_AST_STATEMENT_SWITCH,
+    MOJOSHADER_AST_STATEMENT_FOR,
+    MOJOSHADER_AST_STATEMENT_DO,
+    MOJOSHADER_AST_STATEMENT_WHILE,
+    MOJOSHADER_AST_STATEMENT_RETURN,
+    MOJOSHADER_AST_STATEMENT_TYPEDEF,
+    MOJOSHADER_AST_STATEMENT_STRUCT,
+    MOJOSHADER_AST_STATEMENT_VARDECL,
+    MOJOSHADER_AST_STATEMENT_END_RANGE,
+
+    MOJOSHADER_AST_MISC_START_RANGE,        /* misc. syntactic glue. */
+    MOJOSHADER_AST_FUNCTION_PARAMS,
+    MOJOSHADER_AST_FUNCTION_SIGNATURE,
+    MOJOSHADER_AST_SCALAR_OR_ARRAY,
+    MOJOSHADER_AST_TYPEDEF,
+    MOJOSHADER_AST_PACK_OFFSET,
+    MOJOSHADER_AST_VARIABLE_LOWLEVEL,
+    MOJOSHADER_AST_ANNOTATION,
+    MOJOSHADER_AST_VARIABLE_DECLARATION,
+    MOJOSHADER_AST_STRUCT_DECLARATION,
+    MOJOSHADER_AST_STRUCT_MEMBER,
+    MOJOSHADER_AST_SWITCH_CASE,
+    MOJOSHADER_AST_ARGUMENTS,
+    MOJOSHADER_AST_MISC_END_RANGE,
+
+    MOJOSHADER_AST_END_RANGE
+} MOJOSHADER_astNodeType;
+
+typedef struct MOJOSHADER_astNodeInfo
+{
+    MOJOSHADER_astNodeType type;
+    const char *filename;
+    unsigned int line;
+} MOJOSHADER_astNodeInfo;
+
+typedef enum MOJOSHADER_astVariableAttributes
+{
+    MOJOSHADER_AST_VARATTR_EXTERN = (1 << 0),
+    MOJOSHADER_AST_VARATTR_NOINTERPOLATION = (1 << 1),
+    MOJOSHADER_AST_VARATTR_SHARED = (1 << 2),
+    MOJOSHADER_AST_VARATTR_STATIC = (1 << 3),
+    MOJOSHADER_AST_VARATTR_UNIFORM = (1 << 4),
+    MOJOSHADER_AST_VARATTR_VOLATILE = (1 << 5),
+    MOJOSHADER_AST_VARATTR_CONST = (1 << 6),
+    MOJOSHADER_AST_VARATTR_ROWMAJOR = (1 << 7),
+    MOJOSHADER_AST_VARATTR_COLUMNMAJOR = (1 << 8)
+} MOJOSHADER_astVariableAttributes;
+
+typedef enum MOJOSHADER_astIfAttributes
+{
+    MOJOSHADER_AST_IFATTR_NONE,
+    MOJOSHADER_AST_IFATTR_BRANCH,
+    MOJOSHADER_AST_IFATTR_FLATTEN,
+    MOJOSHADER_AST_IFATTR_IFALL,
+    MOJOSHADER_AST_IFATTR_IFANY,
+    MOJOSHADER_AST_IFATTR_PREDICATE,
+    MOJOSHADER_AST_IFATTR_PREDICATEBLOCK,
+} MOJOSHADER_astIfAttributes;
+
+typedef enum MOJOSHADER_astSwitchAttributes
+{
+    MOJOSHADER_AST_SWITCHATTR_NONE,
+    MOJOSHADER_AST_SWITCHATTR_FLATTEN,
+    MOJOSHADER_AST_SWITCHATTR_BRANCH,
+    MOJOSHADER_AST_SWITCHATTR_FORCECASE,
+    MOJOSHADER_AST_SWITCHATTR_CALL
+} MOJOSHADER_astSwitchAttributes;
+
+/* You can cast any AST node pointer to this. */
+typedef struct MOJOSHADER_astGeneric
+{
+    MOJOSHADER_astNodeInfo ast;
+} MOJOSHADER_astGeneric;
+
+typedef MOJOSHADER_astGeneric MOJOSHADER_astExpression;
+
+typedef struct MOJOSHADER_astArguments
+{
+    MOJOSHADER_astNodeInfo ast;  /* Always MOJOSHADER_AST_ARGUMENTS */
+    MOJOSHADER_astExpression *argument;
+    struct MOJOSHADER_astArguments *next;
+} MOJOSHADER_astArguments;
+
+typedef struct MOJOSHADER_astExpressionUnary
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astExpression *operand;
+} MOJOSHADER_astExpressionUnary;
+
+typedef struct MOJOSHADER_astExpressionBinary
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astExpression *left;
+    MOJOSHADER_astExpression *right;
+} MOJOSHADER_astExpressionBinary;
+
+typedef struct MOJOSHADER_astExpressionTernary
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astExpression *left;
+    MOJOSHADER_astExpression *center;
+    MOJOSHADER_astExpression *right;
+} MOJOSHADER_astExpressionTernary;
+
+typedef struct MOJOSHADER_astExpressionIdentifier
+{
+    MOJOSHADER_astNodeInfo ast;  /* Always MOJOSHADER_AST_OP_IDENTIFIER */
+    const char *identifier;
+} MOJOSHADER_astExpressionIdentifier;
+
+typedef struct MOJOSHADER_astExpressionIntLiteral
+{
+    MOJOSHADER_astNodeInfo ast;  /* Always MOJOSHADER_AST_OP_INT_LITERAL */
+    int value;
+} MOJOSHADER_astExpressionIntLiteral;
+
+typedef struct MOJOSHADER_astExpressionFloatLiteral
+{
+    MOJOSHADER_astNodeInfo ast;  /* Always MOJOSHADER_AST_OP_FLOAT_LITERAL */
+    double value;
+} MOJOSHADER_astExpressionFloatLiteral;
+
+typedef struct MOJOSHADER_astExpressionStringLiteral
+{
+    MOJOSHADER_astNodeInfo ast;  /* Always MOJOSHADER_AST_OP_STRING_LITERAL */
+    const char *string;
+} MOJOSHADER_astExpressionStringLiteral;
+
+typedef struct MOJOSHADER_astExpressionBooleanLiteral
+{
+    MOJOSHADER_astNodeInfo ast;  /* Always MOJOSHADER_AST_OP_BOOLEAN_LITERAL */
+    int value;  /* Always 1 or 0. */
+} MOJOSHADER_astExpressionBooleanLiteral;
+
+typedef struct MOJOSHADER_astExpressionConstructor
+{
+    MOJOSHADER_astNodeInfo ast;  /* Always MOJOSHADER_AST_OP_CONSTRUCTOR */
+    const char *datatype;
+    MOJOSHADER_astArguments *args;
+} MOJOSHADER_astExpressionConstructor;
+
+typedef struct MOJOSHADER_astExpressionDerefStruct
+{
+    MOJOSHADER_astNodeInfo ast;  /* Always MOJOSHADER_AST_OP_DEREF_STRUCT */
+    MOJOSHADER_astExpression *identifier;
+    const char *member;
+} MOJOSHADER_astExpressionDerefStruct;
+
+typedef struct MOJOSHADER_astExpressionCallFunction
+{
+    MOJOSHADER_astNodeInfo ast;  /* Always MOJOSHADER_AST_OP_CALLFUNC */
+    MOJOSHADER_astExpression *identifier;
+    MOJOSHADER_astArguments *args;
+} MOJOSHADER_astExpressionCallFunction;
+
+typedef struct MOJOSHADER_astExpressionCast
+{
+    MOJOSHADER_astNodeInfo ast;  /* Always MOJOSHADER_AST_OP_CAST */
+    const char *datatype;
+    MOJOSHADER_astExpression *operand;
+} MOJOSHADER_astExpressionCast;
+
+typedef struct MOJOSHADER_astCompilationUnit
+{
+    MOJOSHADER_astNodeInfo ast;
+    struct MOJOSHADER_astCompilationUnit *next;
+} MOJOSHADER_astCompilationUnit;
+
+typedef enum MOJOSHADER_astFunctionStorageClass
+{
+    MOJOSHADER_AST_FNSTORECLS_NONE,
+    MOJOSHADER_AST_FNSTORECLS_INLINE
+} MOJOSHADER_astFunctionStorageClass;
+
+typedef enum MOJOSHADER_astInputModifier
+{
+    MOJOSHADER_AST_INPUTMOD_NONE,
+    MOJOSHADER_AST_INPUTMOD_IN,
+    MOJOSHADER_AST_INPUTMOD_OUT,
+    MOJOSHADER_AST_INPUTMOD_INOUT,
+    MOJOSHADER_AST_INPUTMOD_UNIFORM
+} MOJOSHADER_astInputModifier;
+
+typedef enum MOJOSHADER_astInterpolationModifier
+{
+    MOJOSHADER_AST_INTERPMOD_NONE,
+    MOJOSHADER_AST_INTERPMOD_LINEAR,
+    MOJOSHADER_AST_INTERPMOD_CENTROID,
+    MOJOSHADER_AST_INTERPMOD_NOINTERPOLATION,
+    MOJOSHADER_AST_INTERPMOD_NOPERSPECTIVE,
+    MOJOSHADER_AST_INTERPMOD_SAMPLE
+} MOJOSHADER_astInterpolationModifier;
+
+typedef struct MOJOSHADER_astFunctionParameters
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astInputModifier input_modifier;
+    const char *datatype;
+    const char *identifier;
+    const char *semantic;
+    MOJOSHADER_astInterpolationModifier interpolation_modifier;
+    MOJOSHADER_astExpression *initializer;
+    struct MOJOSHADER_astFunctionParameters *next;
+} MOJOSHADER_astFunctionParameters;
+
+typedef struct MOJOSHADER_astFunctionSignature
+{
+    MOJOSHADER_astNodeInfo ast;
+    const char *datatype;
+    const char *identifier;
+    MOJOSHADER_astFunctionParameters *params;
+    MOJOSHADER_astFunctionStorageClass storage_class;
+    const char *semantic;
+} MOJOSHADER_astFunctionSignature;
+
+typedef struct MOJOSHADER_astScalarOrArray
+{
+    MOJOSHADER_astNodeInfo ast;
+    const char *identifier;
+    int isarray;  /* boolean: 1 or 0 */
+    MOJOSHADER_astExpression *dimension;
+} MOJOSHADER_astScalarOrArray;
+
+typedef struct MOJOSHADER_astAnnotations
+{
+    MOJOSHADER_astNodeInfo ast;
+    const char *datatype;
+    MOJOSHADER_astExpression *initializer;
+    struct MOJOSHADER_astAnnotations *next;
+} MOJOSHADER_astAnnotations;
+
+typedef struct MOJOSHADER_astPackOffset
+{
+    MOJOSHADER_astNodeInfo ast;
+    const char *ident1;   /* !!! FIXME: rename this. */
+    const char *ident2;
+} MOJOSHADER_astPackOffset;
+
+typedef struct MOJOSHADER_astVariableLowLevel
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astPackOffset *packoffset;
+    const char *register_name;
+} MOJOSHADER_astVariableLowLevel;
+
+typedef struct MOJOSHADER_astStructMembers
+{
+    MOJOSHADER_astNodeInfo ast;
+    const char *datatype;
+    const char *semantic;
+    MOJOSHADER_astScalarOrArray *details;
+    MOJOSHADER_astInterpolationModifier interpolation_mod;
+    struct MOJOSHADER_astStructMembers *next;
+} MOJOSHADER_astStructMembers;
+
+typedef struct MOJOSHADER_astStructDeclaration
+{
+    MOJOSHADER_astNodeInfo ast;
+    const char *name;
+    MOJOSHADER_astStructMembers *members;
+} MOJOSHADER_astStructDeclaration;
+
+typedef struct MOJOSHADER_astVariableDeclaration
+{
+    MOJOSHADER_astNodeInfo ast;
+    int attributes;
+    const char *datatype;
+    MOJOSHADER_astStructDeclaration *anonymous_datatype;
+    MOJOSHADER_astScalarOrArray *details;
+    const char *semantic;
+    MOJOSHADER_astAnnotations *annotations;
+    MOJOSHADER_astExpression *initializer;
+    MOJOSHADER_astVariableLowLevel *lowlevel;
+    struct MOJOSHADER_astVariableDeclaration *next;
+} MOJOSHADER_astVariableDeclaration;
+
+typedef struct MOJOSHADER_astStatement
+{
+    MOJOSHADER_astNodeInfo ast;
+    struct MOJOSHADER_astStatement *next;
+} MOJOSHADER_astStatement;
+
+typedef MOJOSHADER_astStatement MOJOSHADER_astEmptyStatement;
+typedef MOJOSHADER_astStatement MOJOSHADER_astBreakStatement;
+typedef MOJOSHADER_astStatement MOJOSHADER_astContinueStatement;
+typedef MOJOSHADER_astStatement MOJOSHADER_astDiscardStatement;
+
+/* something enclosed in "{}" braces. */
+typedef struct MOJOSHADER_astBlockStatement
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astStatement *next;
+    MOJOSHADER_astStatement *statements;  /* list of child statements. */
+} MOJOSHADER_astBlockStatement;
+
+typedef struct MOJOSHADER_astReturnStatement
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astStatement *next;
+    MOJOSHADER_astExpression *expr;
+} MOJOSHADER_astReturnStatement;
+
+typedef struct MOJOSHADER_astExpressionStatement
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astStatement *next;
+    MOJOSHADER_astExpression *expr;
+} MOJOSHADER_astExpressionStatement;
+
+typedef struct MOJOSHADER_astIfStatement
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astStatement *next;
+    int attributes;
+    MOJOSHADER_astExpression *expr;
+    MOJOSHADER_astStatement *statement;
+    MOJOSHADER_astStatement *else_statement;
+} MOJOSHADER_astIfStatement;
+
+typedef struct MOJOSHADER_astSwitchCases
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astExpression *expr;
+    MOJOSHADER_astStatement *statement;
+    struct MOJOSHADER_astSwitchCases *next;
+} MOJOSHADER_astSwitchCases;
+
+typedef struct MOJOSHADER_astSwitchStatement
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astStatement *next;
+    int attributes;
+    MOJOSHADER_astExpression *expr;
+    MOJOSHADER_astSwitchCases *cases;
+} MOJOSHADER_astSwitchStatement;
+
+typedef struct MOJOSHADER_astWhileStatement
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astStatement *next;
+    int unroll;  /* # times to unroll, 0 to loop, < 0 == compiler's choice. */
+    MOJOSHADER_astExpression *expr;
+    MOJOSHADER_astStatement *statement;
+} MOJOSHADER_astWhileStatement;
+
+typedef MOJOSHADER_astWhileStatement MOJOSHADER_astDoStatement;
+
+typedef struct MOJOSHADER_astForStatement
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astStatement *next;
+    int unroll;  /* # times to unroll, 0 to loop, < 0 == compiler's choice. */
+    MOJOSHADER_astVariableDeclaration *var_decl;
+    MOJOSHADER_astExpression *initializer;
+    MOJOSHADER_astExpression *looptest;
+    MOJOSHADER_astExpression *counter;
+    MOJOSHADER_astStatement *statement;
+} MOJOSHADER_astForStatement;
+
+typedef struct MOJOSHADER_astTypedef
+{
+    MOJOSHADER_astNodeInfo ast;
+    int isconst;  /* boolean: 1 or 0 */
+    const char *datatype;
+    MOJOSHADER_astScalarOrArray *details;
+} MOJOSHADER_astTypedef;
+
+typedef struct MOJOSHADER_astTypedefStatement
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astStatement *next;
+    MOJOSHADER_astTypedef *type_info;
+} MOJOSHADER_astTypedefStatement;
+
+typedef struct MOJOSHADER_astVarDeclStatement
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astStatement *next;
+    MOJOSHADER_astVariableDeclaration *declaration;
+} MOJOSHADER_astVarDeclStatement;
+
+typedef struct MOJOSHADER_astStructStatement
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astStatement *next;
+    MOJOSHADER_astStructDeclaration *struct_info;
+} MOJOSHADER_astStructStatement;
+
+typedef struct MOJOSHADER_astCompilationUnitFunction
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astCompilationUnit *next;
+    MOJOSHADER_astFunctionSignature *declaration;
+    MOJOSHADER_astStatement *definition;
+} MOJOSHADER_astCompilationUnitFunction;
+
+typedef struct MOJOSHADER_astCompilationUnitTypedef
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astCompilationUnit *next;
+    MOJOSHADER_astTypedef *type_info;
+} MOJOSHADER_astCompilationUnitTypedef;
+
+typedef struct MOJOSHADER_astCompilationUnitStruct
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astCompilationUnit *next;
+    MOJOSHADER_astStructDeclaration *struct_info;
+} MOJOSHADER_astCompilationUnitStruct;
+
+typedef struct MOJOSHADER_astCompilationUnitVariable
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astCompilationUnit *next;
+    MOJOSHADER_astVariableDeclaration *declaration;
+} MOJOSHADER_astCompilationUnitVariable;
+
+
+/* this is way cleaner than all the nasty typecasting. */
+typedef union MOJOSHADER_astNode
+{
+    MOJOSHADER_astNodeInfo ast;
+    MOJOSHADER_astGeneric generic;
+    MOJOSHADER_astExpression expression;
+    MOJOSHADER_astArguments arguments;
+    MOJOSHADER_astExpressionUnary unary;
+    MOJOSHADER_astExpressionBinary binary;
+    MOJOSHADER_astExpressionTernary ternary;
+    MOJOSHADER_astExpressionIdentifier identifier;
+    MOJOSHADER_astExpressionIntLiteral intliteral;
+    MOJOSHADER_astExpressionFloatLiteral floatliteral;
+    MOJOSHADER_astExpressionStringLiteral stringliteral;
+    MOJOSHADER_astExpressionBooleanLiteral boolliteral;
+    MOJOSHADER_astExpressionConstructor constructor;
+    MOJOSHADER_astExpressionDerefStruct derefstruct;
+    MOJOSHADER_astExpressionCallFunction callfunc;
+    MOJOSHADER_astExpressionCast cast;
+    MOJOSHADER_astCompilationUnit compunit;
+    MOJOSHADER_astFunctionParameters params;
+    MOJOSHADER_astFunctionSignature funcsig;
+    MOJOSHADER_astScalarOrArray soa;
+    MOJOSHADER_astAnnotations annotations;
+    MOJOSHADER_astPackOffset packoffset;
+    MOJOSHADER_astVariableLowLevel varlowlevel;
+    MOJOSHADER_astStructMembers structmembers;
+    MOJOSHADER_astStructDeclaration structdecl;
+    MOJOSHADER_astVariableDeclaration vardecl;
+    MOJOSHADER_astStatement stmt;
+    MOJOSHADER_astEmptyStatement emptystmt;
+    MOJOSHADER_astBreakStatement breakstmt;
+    MOJOSHADER_astContinueStatement contstmt;
+    MOJOSHADER_astDiscardStatement discardstmt;
+    MOJOSHADER_astBlockStatement blockstmt;
+    MOJOSHADER_astReturnStatement returnstmt;
+    MOJOSHADER_astExpressionStatement exprstmt;
+    MOJOSHADER_astIfStatement ifstmt;
+    MOJOSHADER_astSwitchCases cases;
+    MOJOSHADER_astSwitchStatement switchstmt;
+    MOJOSHADER_astWhileStatement whilestmt;
+    MOJOSHADER_astDoStatement dostmt;
+    MOJOSHADER_astForStatement forstmt;
+    MOJOSHADER_astTypedef typdef;
+    MOJOSHADER_astTypedefStatement typedefstmt;
+    MOJOSHADER_astVarDeclStatement vardeclstmt;
+    MOJOSHADER_astStructStatement structstmt;
+    MOJOSHADER_astCompilationUnitFunction funcunit;
+    MOJOSHADER_astCompilationUnitTypedef typedefunit;
+    MOJOSHADER_astCompilationUnitStruct structunit;
+    MOJOSHADER_astCompilationUnitVariable varunit;
+} MOJOSHADER_astNode;
+
+
+/*
+ * Structure used to return data from parsing of a shader into an AST...
+ */
+/* !!! FIXME: most of these ints should be unsigned. */
+typedef struct MOJOSHADER_astData
+{
+    /*
+     * The number of elements pointed to by (errors).
+     */
+    int error_count;
+
+    /*
+     * (error_count) elements of data that specify errors that were generated
+     *  by parsing this shader.
+     * This can be NULL if there were no errors or if (error_count) is zero.
+     *  Note that this will only produce errors for syntax problems. Most of
+     *  the things we expect a compiler to produce errors for--incompatible
+     *  types, unknown identifiers, etc--are not checked at all during
+     *  initial generation of the syntax tree...bogus programs that would
+     *  fail to compile will pass here without error, if they are syntactically
+     *  correct!
+     */
+    MOJOSHADER_error *errors;
+
+    /*
+     * The name of the source profile used to parse the shader. Will be NULL
+     *  on error.
+     */
+    const char *source_profile;
+
+    /*
+     * The actual syntax tree. You are responsible for walking it yourself.
+     *  CompilationUnits are always the top of the tree (functions, typedefs,
+     *  global variables, etc).
+     */
+    const MOJOSHADER_astNode *ast;
+
+    /*
+     * This is the malloc implementation you passed to MOJOSHADER_parse().
+     */
+    MOJOSHADER_malloc malloc;
+
+    /*
+     * This is the free implementation you passed to MOJOSHADER_parse().
+     */
+    MOJOSHADER_free free;
+
+    /*
+     * This is the pointer you passed as opaque data for your allocator.
+     */
+    void *malloc_data;
+} MOJOSHADER_astData;
+
+
+/*
+ * You almost certainly don't need this function, unless you absolutely know
+ *  why you need it without hesitation. This is almost certainly only good for
+ *  building code analysis tools on top of.
+ *
+ * This is intended to parse HLSL source code, turning it into an abstract
+ *  syntax tree.
+ *
+ * (srcprofile) specifies the source language of the shader. You can specify
+ *  a shader model with this, too. See MOJOSHADER_SRC_PROFILE_* constants.
+ *
+ * (filename) is a NULL-terminated UTF-8 filename. It can be NULL. We do not
+ *  actually access this file, as we obtain our data from (source). This
+ *  string is copied when we need to report errors while processing (source),
+ *  as opposed to errors in a file referenced via the #include directive in
+ *  (source). If this is NULL, then errors will report the filename as NULL,
+ *  too.
+ *
+ * (source) is an UTF-8 string of valid high-level shader source code.
+ *  It does not need to be NULL-terminated.
+ *
+ * (sourcelen) is the length of the string pointed to by (source), in bytes.
+ *
+ * (defines) points to (define_count) preprocessor definitions, and can be
+ *  NULL. These are treated by the preprocessor as if the source code started
+ *  with one #define for each entry you pass in here.
+ *
+ * (include_open) and (include_close) let the app control the preprocessor's
+ *  behaviour for #include statements. Both are optional and can be NULL, but
+ *  both must be specified if either is specified.
+ *
+ * This will return a MOJOSHADER_astData. The data supplied here gives the
+ *  application a tree-like structure they can walk to see the layout of
+ *  a given program. When you are done with this data, pass it to
+ *  MOJOSHADER_freeCompileData() to deallocate resources.
+ *
+ * This function will never return NULL, even if the system is completely
+ *  out of memory upon entry (in which case, this function returns a static
+ *  MOJOSHADER_astData object, which is still safe to pass to
+ *  MOJOSHADER_freeAstData()).
+ *
+ * As parsing requires some memory to be allocated, you may provide a
+ *  custom allocator to this function, which will be used to allocate/free
+ *  memory. They function just like malloc() and free(). We do not use
+ *  realloc(). If you don't care, pass NULL in for the allocator functions.
+ *  If your allocator needs instance-specific data, you may supply it with the
+ *  (d) parameter. This pointer is passed as-is to your (m) and (f) functions.
+ *
+ * This function is thread safe, so long as the various callback functions
+ *  are, too, and that the parameters remains intact for the duration of the
+ *  call. This allows you to parse several shaders on separate CPU cores
+ *  at the same time.
+ */
+const MOJOSHADER_astData *MOJOSHADER_parseAst(const char *srcprofile,
+                                    const char *filename, const char *source,
+                                    unsigned int sourcelen,
+                                    const MOJOSHADER_preprocessorDefine *defs,
+                                    unsigned int define_count,
+                                    MOJOSHADER_includeOpen include_open,
+                                    MOJOSHADER_includeClose include_close,
+                                    MOJOSHADER_malloc m, MOJOSHADER_free f,
+                                    void *d);
+
+/*
+ * Call this to dispose of AST parsing results when you are done with them.
+ *  This will call the MOJOSHADER_free function you provided to
+ *  MOJOSHADER_parseAst() multiple times, if you provided one.
+ *  Passing a NULL here is a safe no-op.
+ *
+ * This function is thread safe, so long as any allocator you passed into
+ *  MOJOSHADER_parseAst() is, too.
+ */
+void MOJOSHADER_freeAstData(const MOJOSHADER_astData *data);
+
+
+
+/* Compiler interface... */
+
+/*
+ * Structure used to return data from parsing of a shader...
+ */
+/* !!! FIXME: most of these ints should be unsigned. */
+typedef struct MOJOSHADER_compileData
+{
+    /*
+     * The number of elements pointed to by (errors).
+     */
+    int error_count;
+
+    /*
+     * (error_count) elements of data that specify errors that were generated
+     *  by compiling this shader.
+     * This can be NULL if there were no errors or if (error_count) is zero.
+     */
+    MOJOSHADER_error *errors;
+
+    /*
+     * The number of elements pointed to by (warnings).
+     */
+    int warning_count;
+
+    /*
+     * (warning_count) elements of data that specify errors that were
+     *  generated by compiling this shader.
+     * This can be NULL if there were no errors or if (warning_count) is zero.
+     */
+    MOJOSHADER_error *warnings;
+
+    /*
+     * The name of the source profile used to compile the shader. Will be NULL
+     *  on error.
+     */
+    const char *source_profile;
+
+    /*
+     * Bytes of output from compiling. This will be a null-terminated ASCII
+     *  string of D3D assembly source code.
+     */
+    const char *output;
+
+    /*
+     * Byte count for output, not counting any null terminator.
+     *  Will be 0 on error.
+     */
+    int output_len;
+
+    /*
+     * The number of elements pointed to by (symbols).
+     */
+    int symbol_count;
+
+    /*
+     * (symbol_count) elements of data that specify high-level symbol data
+     *  for the shader. This can be used by MOJOSHADER_assemble() to
+     *  generate a CTAB section in bytecode, which is needed by
+     *  MOJOSHADER_parseData() to handle some shaders. This can be NULL on
+     *  error or if (symbol_count) is zero.
+     */
+    MOJOSHADER_symbol *symbols;
+
+    /*
+     * This is the malloc implementation you passed to MOJOSHADER_parse().
+     */
+    MOJOSHADER_malloc malloc;
+
+    /*
+     * This is the free implementation you passed to MOJOSHADER_parse().
+     */
+    MOJOSHADER_free free;
+
+    /*
+     * This is the pointer you passed as opaque data for your allocator.
+     */
+    void *malloc_data;
+} MOJOSHADER_compileData;
+
+
+/*
+ * This function is optional. Use this to compile high-level shader programs.
+ *
+ * This is intended to turn HLSL source code into D3D assembly code, which
+ *  can then be passed to MOJOSHADER_assemble() to convert it to D3D bytecode
+ *  (which can then be used with MOJOSHADER_parseData() to support other
+ *  shading targets).
+ *
+ * (srcprofile) specifies the source language of the shader. You can specify
+ *  a shader model with this, too. See MOJOSHADER_SRC_PROFILE_* constants.
+ *
+ * (filename) is a NULL-terminated UTF-8 filename. It can be NULL. We do not
+ *  actually access this file, as we obtain our data from (source). This
+ *  string is copied when we need to report errors while processing (source),
+ *  as opposed to errors in a file referenced via the #include directive in
+ *  (source). If this is NULL, then errors will report the filename as NULL,
+ *  too.
+ *
+ * (source) is an UTF-8 string of valid high-level shader source code.
+ *  It does not need to be NULL-terminated.
+ *
+ * (sourcelen) is the length of the string pointed to by (source), in bytes.
+ *
+ * (defines) points to (define_count) preprocessor definitions, and can be
+ *  NULL. These are treated by the preprocessor as if the source code started
+ *  with one #define for each entry you pass in here.
+ *
+ * (include_open) and (include_close) let the app control the preprocessor's
+ *  behaviour for #include statements. Both are optional and can be NULL, but
+ *  both must be specified if either is specified.
+ *
+ * This will return a MOJOSHADER_compileData. The data supplied here is
+ *  sufficient to supply to MOJOSHADER_assemble() for further processing.
+ *  When you are done with this data, pass it to MOJOSHADER_freeCompileData()
+ *  to deallocate resources.
+ *
+ * This function will never return NULL, even if the system is completely
+ *  out of memory upon entry (in which case, this function returns a static
+ *  MOJOSHADER_compileData object, which is still safe to pass to
+ *  MOJOSHADER_freeCompileData()).
+ *
+ * As compiling requires some memory to be allocated, you may provide a
+ *  custom allocator to this function, which will be used to allocate/free
+ *  memory. They function just like malloc() and free(). We do not use
+ *  realloc(). If you don't care, pass NULL in for the allocator functions.
+ *  If your allocator needs instance-specific data, you may supply it with the
+ *  (d) parameter. This pointer is passed as-is to your (m) and (f) functions.
+ *
+ * This function is thread safe, so long as the various callback functions
+ *  are, too, and that the parameters remains intact for the duration of the
+ *  call. This allows you to compile several shaders on separate CPU cores
+ *  at the same time.
+ */
+const MOJOSHADER_compileData *MOJOSHADER_compile(const char *srcprofile,
+                                    const char *filename, const char *source,
+                                    unsigned int sourcelen,
+                                    const MOJOSHADER_preprocessorDefine *defs,
+                                    unsigned int define_count,
+                                    MOJOSHADER_includeOpen include_open,
+                                    MOJOSHADER_includeClose include_close,
+                                    MOJOSHADER_malloc m, MOJOSHADER_free f,
+                                    void *d);
+
+
 /* OpenGL interface... */
 
 /*
--- a/mojoshader_compiler.c	Tue Oct 26 17:27:31 2010 -0400
+++ b/mojoshader_compiler.c	Thu Oct 28 03:42:12 2010 -0400
@@ -34,6 +34,25 @@
     } \
 }
 
+static inline int operator_is_unary(const MOJOSHADER_astNodeType op)
+{
+    return ( (op > MOJOSHADER_AST_OP_START_RANGE_UNARY) &&
+             (op < MOJOSHADER_AST_OP_END_RANGE_UNARY) );
+} // operator_is_unary
+
+static inline int operator_is_binary(const MOJOSHADER_astNodeType op)
+{
+    return ( (op > MOJOSHADER_AST_OP_START_RANGE_BINARY) &&
+             (op < MOJOSHADER_AST_OP_END_RANGE_BINARY) );
+} // operator_is_binary
+
+static inline int operator_is_ternary(const MOJOSHADER_astNodeType op)
+{
+    return ( (op > MOJOSHADER_AST_OP_START_RANGE_TERNARY) &&
+             (op < MOJOSHADER_AST_OP_END_RANGE_TERNARY) );
+} // operator_is_ternary
+
+
 typedef union TokenData
 {
     int64 i64;
@@ -42,521 +61,6 @@
 } TokenData;
 
 
-// Structures that make up the parse tree...
-
-typedef enum ASTNodeType
-{
-    AST_OP_START_RANGE,
-    AST_OP_START_RANGE_UNARY,
-    AST_OP_POSTINCREMENT,
-    AST_OP_POSTDECREMENT,
-    AST_OP_PREINCREMENT,
-    AST_OP_PREDECREMENT,
-    AST_OP_NEGATE,
-    AST_OP_COMPLEMENT,
-    AST_OP_NOT,
-    AST_OP_END_RANGE_UNARY,
-
-    AST_OP_START_RANGE_BINARY,
-    AST_OP_DEREF_ARRAY,
-    AST_OP_COMMA,
-    AST_OP_MULTIPLY,
-    AST_OP_DIVIDE,
-    AST_OP_MODULO,
-    AST_OP_ADD,
-    AST_OP_SUBTRACT,
-    AST_OP_LSHIFT,
-    AST_OP_RSHIFT,
-    AST_OP_LESSTHAN,
-    AST_OP_GREATERTHAN,
-    AST_OP_LESSTHANOREQUAL,
-    AST_OP_GREATERTHANOREQUAL,
-    AST_OP_EQUAL,
-    AST_OP_NOTEQUAL,
-    AST_OP_BINARYAND,
-    AST_OP_BINARYXOR,
-    AST_OP_BINARYOR,
-    AST_OP_LOGICALAND,
-    AST_OP_LOGICALOR,
-    AST_OP_ASSIGN,
-    AST_OP_MULASSIGN,
-    AST_OP_DIVASSIGN,
-    AST_OP_MODASSIGN,
-    AST_OP_ADDASSIGN,
-    AST_OP_SUBASSIGN,
-    AST_OP_LSHIFTASSIGN,
-    AST_OP_RSHIFTASSIGN,
-    AST_OP_ANDASSIGN,
-    AST_OP_XORASSIGN,
-    AST_OP_ORASSIGN,
-    AST_OP_END_RANGE_BINARY,
-
-    AST_OP_START_RANGE_TERNARY,
-    AST_OP_CONDITIONAL,
-    AST_OP_END_RANGE_TERNARY,
-
-    AST_OP_START_RANGE_DATA,
-    AST_OP_IDENTIFIER,
-    AST_OP_INT_LITERAL,
-    AST_OP_FLOAT_LITERAL,
-    AST_OP_STRING_LITERAL,
-    AST_OP_BOOLEAN_LITERAL,
-    AST_OP_END_RANGE_DATA,
-
-    AST_OP_START_RANGE_MISC,
-    AST_OP_DEREF_STRUCT,
-    AST_OP_CALLFUNC,
-    AST_OP_CONSTRUCTOR,
-    AST_OP_CAST,
-    AST_OP_END_RANGE_MISC,
-    AST_OP_END_RANGE,
-
-    AST_COMPUNIT_START_RANGE,
-    AST_COMPUNIT_FUNCTION,    // function declaration or definition
-    AST_COMPUNIT_TYPEDEF,     // typedef or struct
-    AST_COMPUNIT_STRUCT,      // global struct
-    AST_COMPUNIT_VARIABLE,    // global variable
-    AST_COMPUNIT_END_RANGE,
-
-    AST_STATEMENT_START_RANGE,
-    AST_STATEMENT_BLOCK,
-    AST_STATEMENT_EMPTY,
-    AST_STATEMENT_EXPRESSION,
-    AST_STATEMENT_IF,
-    AST_STATEMENT_SWITCH,
-    AST_STATEMENT_FOR,
-    AST_STATEMENT_DO,
-    AST_STATEMENT_WHILE,
-    AST_STATEMENT_RETURN,
-    AST_STATEMENT_BREAK,
-    AST_STATEMENT_CONTINUE,
-    AST_STATEMENT_DISCARD,
-    AST_STATEMENT_TYPEDEF,
-    AST_STATEMENT_STRUCT,
-    AST_STATEMENT_VARDECL,
-    AST_STATEMENT_END_RANGE,
-
-    AST_MISC_START_RANGE,
-    AST_FUNCTION_PARAMS,
-    AST_FUNCTION_SIGNATURE,
-    AST_SCALAR_OR_ARRAY,
-    AST_TYPEDEF,
-    AST_PACK_OFFSET,
-    AST_VARIABLE_LOWLEVEL,
-    AST_ANNOTATION,
-    AST_VARIABLE_DECLARATION,
-    AST_STRUCT_DECLARATION,
-    AST_STRUCT_MEMBER,
-    AST_SWITCH_CASE,
-    AST_ARGUMENTS,
-    AST_MISC_END_RANGE,
-
-    AST_END_RANGE
-} ASTNodeType;
-
-typedef struct ASTNode
-{
-    ASTNodeType type;
-    const char *filename;
-    uint32 line;
-} ASTNode;
-
-typedef enum VariableAttributes
-{
-    VARATTR_EXTERN = (1 << 0),
-    VARATTR_NOINTERPOLATION = (1 << 1),
-    VARATTR_SHARED = (1 << 2),
-    VARATTR_STATIC = (1 << 3),
-    VARATTR_UNIFORM = (1 << 4),
-    VARATTR_VOLATILE = (1 << 5),
-    VARATTR_CONST = (1 << 6),
-    VARATTR_ROWMAJOR = (1 << 7),
-    VARATTR_COLUMNMAJOR = (1 << 8)
-} VariableAttributes;
-
-typedef enum IfAttributes
-{
-    IFATTR_NONE,
-    IFATTR_BRANCH,
-    IFATTR_FLATTEN,
-    IFATTR_IFALL,
-    IFATTR_IFANY,
-    IFATTR_PREDICATE,
-    IFATTR_PREDICATEBLOCK,
-} IfAttributes;
-
-typedef enum SwitchAttributes
-{
-    SWITCHATTR_NONE,
-    SWITCHATTR_FLATTEN,
-    SWITCHATTR_BRANCH,
-    SWITCHATTR_FORCECASE,
-    SWITCHATTR_CALL
-} SwitchAttributes;
-
-static inline int operator_is_unary(const ASTNodeType op)
-{
-    return ((op > AST_OP_START_RANGE_UNARY) && (op < AST_OP_END_RANGE_UNARY));
-} // operator_is_unary
-
-static inline int operator_is_binary(const ASTNodeType op)
-{
-    return ((op > AST_OP_START_RANGE_BINARY) && (op < AST_OP_END_RANGE_BINARY));
-} // operator_is_binary
-
-static inline int operator_is_ternary(const ASTNodeType op)
-{
-    return ((op > AST_OP_START_RANGE_TERNARY) && (op < AST_OP_END_RANGE_TERNARY));
-} // operator_is_ternary
-
-typedef struct ASTGeneric
-{
-    ASTNode ast;
-} ASTGeneric;
-
-typedef ASTGeneric Expression;
-
-typedef struct Arguments
-{
-    ASTNode ast;  // Always AST_ARGUMENTS
-    Expression *argument;
-    struct Arguments *next;
-} Arguments;
-
-typedef struct ExpressionUnary
-{
-    ASTNode ast;
-    Expression *operand;
-} ExpressionUnary;
-
-typedef struct ExpressionBinary
-{
-    ASTNode ast;
-    Expression *left;
-    Expression *right;
-} ExpressionBinary;
-
-typedef struct ExpressionTernary
-{
-    ASTNode ast;
-    Expression *left;
-    Expression *center;
-    Expression *right;
-} ExpressionTernary;
-
-typedef struct ExpressionIdentifier
-{
-    ASTNode ast;  // Always AST_OP_IDENTIFIER
-    const char *identifier;
-} ExpressionIdentifier;
-
-typedef struct ExpressionIntLiteral
-{
-    ASTNode ast;  // Always AST_OP_INT_LITERAL
-    int64 value;
-} ExpressionIntLiteral;
-
-typedef struct ExpressionFloatLiteral
-{
-    ASTNode ast;  // Always AST_OP_FLOAT_LITERAL
-    double value;
-} ExpressionFloatLiteral;
-
-typedef struct ExpressionStringLiteral
-{
-    ASTNode ast;  // Always AST_OP_STRING_LITERAL
-    const char *string;
-} ExpressionStringLiteral;
-
-typedef struct ExpressionBooleanLiteral
-{
-    ASTNode ast;  // Always AST_OP_BOOLEAN_LITERAL
-    int value;  // Always 1 or 0.
-} ExpressionBooleanLiteral;
-
-typedef struct ExpressionConstructor
-{
-    ASTNode ast;  // Always AST_OP_CONSTRUCTOR
-    const char *datatype;
-    Arguments *args;
-} ExpressionConstructor;
-
-typedef struct ExpressionDerefStruct
-{
-    ASTNode ast;  // Always AST_OP_DEREF_STRUCT
-    Expression *identifier;
-    const char *member;
-} ExpressionDerefStruct;
-
-typedef struct ExpressionCallFunction
-{
-    ASTNode ast;  // Always AST_OP_CALLFUNC
-    Expression *identifier;
-    Arguments *args;
-} ExpressionCallFunction;
-
-typedef struct ExpressionCast
-{
-    ASTNode ast;  // Always AST_OP_CAST
-    const char *datatype;
-    Expression *operand;
-} ExpressionCast;
-
-typedef struct CompilationUnit
-{
-    ASTNode ast;
-    struct CompilationUnit *next;
-} CompilationUnit;
-
-typedef enum FunctionStorageClass
-{
-    FNSTORECLS_NONE,
-    FNSTORECLS_INLINE
-} FunctionStorageClass;
-
-typedef enum InputModifier
-{
-    INPUTMOD_NONE,
-    INPUTMOD_IN,
-    INPUTMOD_OUT,
-    INPUTMOD_INOUT,
-    INPUTMOD_UNIFORM
-} InputModifier;
-
-typedef enum InterpolationModifier
-{
-    INTERPMOD_NONE,
-    INTERPMOD_LINEAR,
-    INTERPMOD_CENTROID,
-    INTERPMOD_NOINTERPOLATION,
-    INTERPMOD_NOPERSPECTIVE,
-    INTERPMOD_SAMPLE
-} InterpolationModifier;
-
-typedef struct FunctionParameters
-{
-    ASTNode ast;
-    InputModifier input_modifier;
-    const char *datatype;
-    const char *identifier;
-    const char *semantic;
-    InterpolationModifier interpolation_modifier;
-    Expression *initializer;
-    struct FunctionParameters *next;
-} FunctionParameters;
-
-typedef struct FunctionSignature
-{
-    ASTNode ast;
-    const char *datatype;
-    const char *identifier;
-    FunctionParameters *params;
-    FunctionStorageClass storage_class;
-    const char *semantic;
-} FunctionSignature;
-
-typedef struct ScalarOrArray
-{
-    ASTNode ast;
-    const char *identifier;
-    int isarray;
-    Expression *dimension;
-} ScalarOrArray;
-
-typedef struct Annotations
-{
-    ASTNode ast;
-    const char *datatype;
-    Expression *initializer;
-    struct Annotations *next;
-} Annotations;
-
-typedef struct PackOffset
-{
-    ASTNode ast;
-    const char *ident1;   // !!! FIXME: rename this.
-    const char *ident2;
-} PackOffset;
-
-typedef struct VariableLowLevel
-{
-    ASTNode ast;
-    PackOffset *packoffset;
-    const char *register_name;
-} VariableLowLevel;
-
-typedef struct StructMembers
-{
-    ASTNode ast;
-    const char *datatype;
-    const char *semantic;
-    ScalarOrArray *details;
-    InterpolationModifier interpolation_mod;
-    struct StructMembers *next;
-} StructMembers;
-
-typedef struct StructDeclaration
-{
-    ASTNode ast;
-    const char *name;
-    StructMembers *members;
-} StructDeclaration;
-
-typedef struct VariableDeclaration
-{
-    ASTNode ast;
-    int attributes;
-    const char *datatype;
-    StructDeclaration *anonymous_datatype;
-    ScalarOrArray *details;
-    const char *semantic;
-    Annotations *annotations;
-    Expression *initializer;
-    VariableLowLevel *lowlevel;
-    struct VariableDeclaration *next;
-} VariableDeclaration;
-
-typedef struct Statement
-{
-    ASTNode ast;
-    struct Statement *next;
-} Statement;
-
-typedef Statement EmptyStatement;
-typedef Statement BreakStatement;
-typedef Statement ContinueStatement;
-typedef Statement DiscardStatement;
-
-typedef struct BlockStatement  // something enclosed in "{}" braces.
-{
-    ASTNode ast;
-    struct Statement *next;
-    Statement *statements;  // list of statements enclosed by this block.
-} BlockStatement;
-
-typedef struct ReturnStatement
-{
-    ASTNode ast;
-    struct Statement *next;
-    Expression *expr;
-} ReturnStatement;
-
-typedef struct ExpressionStatement
-{
-    ASTNode ast;
-    struct Statement *next;
-    Expression *expr;
-} ExpressionStatement;
-
-typedef struct IfStatement
-{
-    ASTNode ast;
-    struct Statement *next;
-    int attributes;
-    Expression *expr;
-    Statement *statement;
-    Statement *else_statement;
-} IfStatement;
-
-typedef struct SwitchCases
-{
-    ASTNode ast;
-    Expression *expr;
-    Statement *statement;
-    struct SwitchCases *next;
-} SwitchCases;
-
-typedef struct SwitchStatement
-{
-    ASTNode ast;
-    struct Statement *next;
-    int attributes;
-    Expression *expr;
-    SwitchCases *cases;
-} SwitchStatement;
-
-typedef struct WhileStatement
-{
-    ASTNode ast;
-    struct Statement *next;
-    int64 unroll;  // # times to unroll, 0 to loop, negative for compiler's choice.
-    Expression *expr;
-    Statement *statement;
-} WhileStatement;
-
-typedef WhileStatement DoStatement;
-
-typedef struct ForStatement
-{
-    ASTNode ast;
-    struct Statement *next;
-    int64 unroll;  // # times to unroll, 0 to loop, negative for compiler's choice.
-    VariableDeclaration *var_decl;
-    Expression *initializer;
-    Expression *looptest;
-    Expression *counter;
-    Statement *statement;
-} ForStatement;
-
-typedef struct Typedef
-{
-    ASTNode ast;
-    int isconst;
-    const char *datatype;
-    ScalarOrArray *details;
-} Typedef;
-
-typedef struct TypedefStatement
-{
-    ASTNode ast;
-    struct Statement *next;
-    Typedef *type_info;
-} TypedefStatement;
-
-typedef struct VarDeclStatement
-{
-    ASTNode ast;
-    struct Statement *next;
-    VariableDeclaration *declaration;
-} VarDeclStatement;
-
-typedef struct StructStatement
-{
-    ASTNode ast;
-    struct Statement *next;
-    StructDeclaration *struct_info;
-} StructStatement;
-
-typedef struct CompilationUnitFunction
-{
-    ASTNode ast;
-    struct CompilationUnit *next;
-    FunctionSignature *declaration;
-    Statement *definition;
-} CompilationUnitFunction;
-
-typedef struct CompilationUnitTypedef
-{
-    ASTNode ast;
-    struct CompilationUnit *next;
-    Typedef *type_info;
-} CompilationUnitTypedef;
-
-typedef struct CompilationUnitStruct
-{
-    ASTNode ast;
-    struct CompilationUnit *next;
-    StructDeclaration *struct_info;
-} CompilationUnitStruct;
-
-typedef struct CompilationUnitVariable
-{
-    ASTNode ast;
-    struct CompilationUnit *next;
-    VariableDeclaration *declaration;
-} CompilationUnitVariable;
-
-
 // This tracks data types and variables, and notes when they enter/leave scope.
 
 typedef struct SymbolScope
@@ -589,7 +93,7 @@
     unsigned int sourceline; // current line in sourcefile that we're parsing.
     SymbolMap usertypes;
     SymbolMap variables;
-    CompilationUnit *ast;  // Abstract Syntax Tree
+    MOJOSHADER_astNode *ast;  // Abstract Syntax Tree
 
     // These are entries allocated in the strcache, so these pointers are
     //  valid from shortly after we create the cache until we destroy it
@@ -787,150 +291,170 @@
     if (!cls) return; \
 } while (0)
 
-static void delete_compilation_unit(Context *ctx, CompilationUnit *unit);
-static void delete_statement(Context *ctx, Statement *stmt);
+static void delete_compilation_unit(Context*, MOJOSHADER_astCompilationUnit*);
+static void delete_statement(Context *ctx, MOJOSHADER_astStatement *stmt);
 
-static Expression *new_callfunc_expr(Context *ctx, Expression *identifier,
-                                     Arguments *args)
+static MOJOSHADER_astExpression *new_callfunc_expr(Context *ctx,
+                                        MOJOSHADER_astExpression *identifier,
+                                        MOJOSHADER_astArguments *args)
 {
-    NEW_AST_NODE(retval, ExpressionCallFunction, AST_OP_CALLFUNC);
+    NEW_AST_NODE(retval, MOJOSHADER_astExpressionCallFunction,
+                 MOJOSHADER_AST_OP_CALLFUNC);
     retval->identifier = identifier;
     retval->args = args;
-    return (Expression *) retval;
+    return (MOJOSHADER_astExpression *) retval;
 } // new_callfunc_expr
 
-static Expression *new_constructor_expr(Context *ctx, const char *datatype,
-                                        Arguments *args)
+static MOJOSHADER_astExpression *new_constructor_expr(Context *ctx,
+                                                const char *datatype,
+                                                MOJOSHADER_astArguments *args)
 {
-    NEW_AST_NODE(retval, ExpressionConstructor, AST_OP_CONSTRUCTOR);
+    NEW_AST_NODE(retval, MOJOSHADER_astExpressionConstructor,
+                 MOJOSHADER_AST_OP_CONSTRUCTOR);
     retval->datatype = datatype;
     retval->args = args;
-    return (Expression *) retval;
+    return (MOJOSHADER_astExpression *) retval;
 } // new_constructor_expr
 
-static Expression *new_cast_expr(Context *ctx, const char *datatype,
-                                 Expression *operand)
+static MOJOSHADER_astExpression *new_cast_expr(Context *ctx,
+                                            const char *datatype,
+                                            MOJOSHADER_astExpression *operand)
 {
-    NEW_AST_NODE(retval, ExpressionCast, AST_OP_CAST);
+    NEW_AST_NODE(retval, MOJOSHADER_astExpressionCast, MOJOSHADER_AST_OP_CAST);
     retval->datatype = datatype;
     retval->operand = operand;
-    return (Expression *) retval;
+    return (MOJOSHADER_astExpression *) retval;
 } // new_cast_expr
 
-static Expression *new_unary_expr(Context *ctx, const ASTNodeType op,
-                                  Expression *operand)
+static MOJOSHADER_astExpression *new_unary_expr(Context *ctx,
+                                            const MOJOSHADER_astNodeType op,
+                                            MOJOSHADER_astExpression *operand)
 {
-    NEW_AST_NODE(retval, ExpressionUnary, op);
+    NEW_AST_NODE(retval, MOJOSHADER_astExpressionUnary, op);
     assert(operator_is_unary(op));
     retval->operand = operand;
-    return (Expression *) retval;
+    return (MOJOSHADER_astExpression *) retval;
 } // new_unary_expr
 
-static Expression *new_binary_expr(Context *ctx, const ASTNodeType op,
-                                   Expression *left, Expression *right)
+static MOJOSHADER_astExpression *new_binary_expr(Context *ctx,
+                                            const MOJOSHADER_astNodeType op,
+                                            MOJOSHADER_astExpression *left,
+                                            MOJOSHADER_astExpression *right)
 {
-    NEW_AST_NODE(retval, ExpressionBinary, op);
+    NEW_AST_NODE(retval, MOJOSHADER_astExpressionBinary, op);
     assert(operator_is_binary(op));
     retval->left = left;
     retval->right = right;
-    return (Expression *) retval;
+    return (MOJOSHADER_astExpression *) retval;
 } // new_binary_expr
 
-static Expression *new_ternary_expr(Context *ctx, const ASTNodeType op,
-                                    Expression *left, Expression *center,
-                                    Expression *right)
+static MOJOSHADER_astExpression *new_ternary_expr(Context *ctx,
+                                            const MOJOSHADER_astNodeType op,
+                                            MOJOSHADER_astExpression *left,
+                                            MOJOSHADER_astExpression *center,
+                                            MOJOSHADER_astExpression *right)
 {
-    NEW_AST_NODE(retval, ExpressionTernary, op);
+    NEW_AST_NODE(retval, MOJOSHADER_astExpressionTernary, op);
     assert(operator_is_ternary(op));
     retval->left = left;
     retval->center = center;
     retval->right = right;
-    return (Expression *) retval;
+    return (MOJOSHADER_astExpression *) retval;
 } // new_ternary_expr
 
-static Expression *new_deref_struct_expr(Context *ctx, Expression *identifier,
-                                         const char *member)
+static MOJOSHADER_astExpression *new_deref_struct_expr(Context *ctx,
+                                        MOJOSHADER_astExpression *identifier,
+                                        const char *member)
 {
-    NEW_AST_NODE(retval, ExpressionDerefStruct, AST_OP_DEREF_STRUCT);
+    NEW_AST_NODE(retval, MOJOSHADER_astExpressionDerefStruct,
+                 MOJOSHADER_AST_OP_DEREF_STRUCT);
     retval->identifier = identifier;
     retval->member = member;  // cached; don't copy string.
-    return (Expression *) retval;
+    return (MOJOSHADER_astExpression *) retval;
 } // new_deref_struct_expr
 
-static Expression *new_identifier_expr(Context *ctx, const char *string)
+static MOJOSHADER_astExpression *new_identifier_expr(Context *ctx,
+                                                     const char *string)
 {
-    NEW_AST_NODE(retval, ExpressionIdentifier, AST_OP_IDENTIFIER);
+    NEW_AST_NODE(retval, MOJOSHADER_astExpressionIdentifier,
+                 MOJOSHADER_AST_OP_IDENTIFIER);
     retval->identifier = string;  // cached; don't copy string.
-    return (Expression *) retval;
+    return (MOJOSHADER_astExpression *) retval;
 } // new_identifier_expr
 
-static Expression *new_literal_int_expr(Context *ctx, const int64 value)
+static MOJOSHADER_astExpression *new_literal_int_expr(Context *ctx,
+                                                       const int value)
 {
-    NEW_AST_NODE(retval, ExpressionIntLiteral, AST_OP_INT_LITERAL);
+    NEW_AST_NODE(retval, MOJOSHADER_astExpressionIntLiteral,
+                 MOJOSHADER_AST_OP_INT_LITERAL);
     retval->value = value;
-    return (Expression *) retval;
+    return (MOJOSHADER_astExpression *) retval;
 } // new_literal_int_expr
 
-static Expression *new_literal_float_expr(Context *ctx, const double dbl)
+static MOJOSHADER_astExpression *new_literal_float_expr(Context *ctx,
+                                                        const double dbl)
 {
-    NEW_AST_NODE(retval, ExpressionFloatLiteral, AST_OP_FLOAT_LITERAL);
+    NEW_AST_NODE(retval, MOJOSHADER_astExpressionFloatLiteral,
+                 MOJOSHADER_AST_OP_FLOAT_LITERAL);
     retval->value = dbl;
-    return (Expression *) retval;
+    return (MOJOSHADER_astExpression *) retval;
 } // new_literal_float_expr
 
-static Expression *new_literal_string_expr(Context *ctx, const char *string)
+static MOJOSHADER_astExpression *new_literal_string_expr(Context *ctx,
+                                                         const char *string)
 {
-    NEW_AST_NODE(retval, ExpressionStringLiteral, AST_OP_STRING_LITERAL);
+    NEW_AST_NODE(retval, MOJOSHADER_astExpressionStringLiteral,
+                 MOJOSHADER_AST_OP_STRING_LITERAL);
     retval->string = string;  // cached; don't copy string.
-    return (Expression *) retval;
+    return (MOJOSHADER_astExpression *) retval;
 } // new_literal_string_expr
 
-static Expression *new_literal_boolean_expr(Context *ctx, const int value)
+static MOJOSHADER_astExpression *new_literal_boolean_expr(Context *ctx,
+                                                          const int value)
 {
-    NEW_AST_NODE(retval, ExpressionBooleanLiteral, AST_OP_BOOLEAN_LITERAL);
+    NEW_AST_NODE(retval, MOJOSHADER_astExpressionBooleanLiteral,
+                 MOJOSHADER_AST_OP_BOOLEAN_LITERAL);
     retval->value = value;
-    return (Expression *) retval;
+    return (MOJOSHADER_astExpression *) retval;
 } // new_literal_boolean_expr
 
-static void delete_arguments(Context *ctx, Arguments *args);
+static void delete_arguments(Context *ctx, MOJOSHADER_astArguments *args);
 
-static void delete_expr(Context *ctx, Expression *expr)
+static void delete_expr(Context *ctx, MOJOSHADER_astExpression *_expr)
 {
+    MOJOSHADER_astNode *expr = (MOJOSHADER_astNode *) _expr;
+
     DELETE_AST_NODE(expr);
-    if (operator_is_unary(expr->ast.type))
-    {
-        const ExpressionUnary *unary = (const ExpressionUnary *) expr;
-        delete_expr(ctx, unary->operand);
-    } // if
+
+    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);
+
     else if (operator_is_binary(expr->ast.type))
     {
-        const ExpressionBinary *binary = (const ExpressionBinary *) expr;
-        delete_expr(ctx, binary->left);
-        delete_expr(ctx, binary->right);
+        delete_expr(ctx, expr->binary.left);
+        delete_expr(ctx, expr->binary.right);
     } // else if
+
     else if (operator_is_ternary(expr->ast.type))
     {
-        const ExpressionTernary *ternary = (const ExpressionTernary *) expr;
-        delete_expr(ctx, ternary->left);
-        delete_expr(ctx, ternary->center);
-        delete_expr(ctx, ternary->right);
+        delete_expr(ctx, expr->ternary.left);
+        delete_expr(ctx, expr->ternary.center);
+        delete_expr(ctx, expr->ternary.right);
     } // else if
-    else if (expr->ast.type == AST_OP_CAST)
-    {
-        delete_expr(ctx, ((ExpressionCast *) expr)->operand);
-    } // else if
-    else if (expr->ast.type == AST_OP_CONSTRUCTOR)
+
+    else if (expr->ast.type == MOJOSHADER_AST_OP_CALLFUNC)
     {
-        delete_arguments(ctx, ((ExpressionConstructor *) expr)->args);
-    } // else if
-    else if (expr->ast.type == AST_OP_DEREF_STRUCT)
-    {
-        delete_expr(ctx, ((ExpressionDerefStruct *) expr)->identifier);
-    } // else if
-    else if (expr->ast.type == AST_OP_CALLFUNC)
-    {
-        delete_expr(ctx, ((ExpressionCallFunction *) expr)->identifier);
-        delete_arguments(ctx, ((ExpressionCallFunction *) expr)->args);
+        delete_expr(ctx, expr->callfunc.identifier);
+        delete_arguments(ctx, expr->callfunc.args);
     } // else if
 
     // rest of operators don't have extra data to free.
@@ -938,15 +462,16 @@
     Free(ctx, expr);
 } // delete_expr
 
-static Arguments *new_argument(Context *ctx, Expression *argument)
+static MOJOSHADER_astArguments *new_argument(Context *ctx,
+                                             MOJOSHADER_astExpression *arg)
 {
-    NEW_AST_NODE(retval, Arguments, AST_ARGUMENTS);
-    retval->argument = argument;
+    NEW_AST_NODE(retval, MOJOSHADER_astArguments, MOJOSHADER_AST_ARGUMENTS);
+    retval->argument = arg;
     retval->next = NULL;
     return retval;
 } // new_argument
 
-static void delete_arguments(Context *ctx, Arguments *args)
+static void delete_arguments(Context *ctx, MOJOSHADER_astArguments *args)
 {
     DELETE_AST_NODE(args);
     delete_arguments(ctx, args->next);
@@ -954,15 +479,15 @@
     Free(ctx, args);
 } // delete_arguments
 
-static FunctionParameters *new_function_param(Context *ctx,
-                                        const InputModifier inputmod,
-                                        const char *datatype,
-                                        const char *identifier,
-                                        const char *semantic,
-                                        const InterpolationModifier interpmod,
-                                        Expression *initializer)
+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)
 {
-    NEW_AST_NODE(retval, FunctionParameters, AST_FUNCTION_PARAMS);
+    NEW_AST_NODE(retval, MOJOSHADER_astFunctionParameters,
+                 MOJOSHADER_AST_FUNCTION_PARAMS);
     retval->input_modifier = inputmod;
     retval->datatype = datatype;
     retval->identifier = identifier;
@@ -973,7 +498,8 @@
     return retval;
 } // new_function_param
 
-static void delete_function_params(Context *ctx, FunctionParameters *params)
+static void delete_function_params(Context *ctx,
+                                   MOJOSHADER_astFunctionParameters *params)
 {
     DELETE_AST_NODE(params);
     delete_function_params(ctx, params->next);
@@ -981,39 +507,43 @@
     Free(ctx, params);
 } // delete_function_params
 
-static FunctionSignature *new_function_signature(Context *ctx,
-                                                 const char *datatype,
-                                                 const char *identifier,
-                                                 FunctionParameters *params)
+static MOJOSHADER_astFunctionSignature *new_function_signature(Context *ctx,
+                                    const char *datatype,
+                                    const char *identifier,
+                                    MOJOSHADER_astFunctionParameters *params)
 {
-    NEW_AST_NODE(retval, FunctionSignature, AST_FUNCTION_SIGNATURE);
+    NEW_AST_NODE(retval, MOJOSHADER_astFunctionSignature,
+                 MOJOSHADER_AST_FUNCTION_SIGNATURE);
     retval->datatype = datatype;
     retval->identifier = identifier;
     retval->params = params;
-    retval->storage_class = FNSTORECLS_NONE;
+    retval->storage_class = MOJOSHADER_AST_FNSTORECLS_NONE;
     retval->semantic = NULL;
     return retval;
 } // new_function_signature
 
-static void delete_function_signature(Context *ctx, FunctionSignature *sig)
+static void delete_function_signature(Context *ctx,
+                                      MOJOSHADER_astFunctionSignature *sig)
 {
     DELETE_AST_NODE(sig);
     delete_function_params(ctx, sig->params);
     Free(ctx, sig);
 } // delete_function_signature
 
-static CompilationUnit *new_function(Context *ctx,
-                                     FunctionSignature *declaration,
-                                     Statement *definition)
+static MOJOSHADER_astCompilationUnit *new_function(Context *ctx,
+                                MOJOSHADER_astFunctionSignature *declaration,
+                                MOJOSHADER_astStatement *definition)
 {
-    NEW_AST_NODE(retval, CompilationUnitFunction, AST_COMPUNIT_FUNCTION);
+    NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitFunction,
+                 MOJOSHADER_AST_COMPUNIT_FUNCTION);
     retval->next = NULL;
     retval->declaration = declaration;
     retval->definition = definition;
-    return (CompilationUnit *) retval;
+    return (MOJOSHADER_astCompilationUnit *) retval;
 } // new_function
 
-static void delete_function(Context *ctx, CompilationUnitFunction *unitfn)
+static void delete_function(Context *ctx,
+                            MOJOSHADER_astCompilationUnitFunction *unitfn)
 {
     DELETE_AST_NODE(unitfn);
     delete_compilation_unit(ctx, unitfn->next);
@@ -1022,95 +552,106 @@
     Free(ctx, unitfn);
 } // delete_function
 
-static ScalarOrArray *new_scalar_or_array(Context *ctx, const char *ident,
-                                          const int isvec, Expression *dim)
+static MOJOSHADER_astScalarOrArray *new_scalar_or_array(Context *ctx,
+                                          const char *ident, const int isvec,
+                                          MOJOSHADER_astExpression *dim)
 {
-    NEW_AST_NODE(retval, ScalarOrArray, AST_SCALAR_OR_ARRAY);
+    NEW_AST_NODE(retval, MOJOSHADER_astScalarOrArray,
+                 MOJOSHADER_AST_SCALAR_OR_ARRAY);
     retval->identifier = ident;
     retval->isarray = isvec;
     retval->dimension = dim;
     return retval;
 } // new_scalar_or_array
 
-static void delete_scalar_or_array(Context *ctx, ScalarOrArray *soa)
+static void delete_scalar_or_array(Context *ctx,MOJOSHADER_astScalarOrArray *s)
 {
-    DELETE_AST_NODE(soa);
-    delete_expr(ctx, soa->dimension);
-    Free(ctx, soa);
+    DELETE_AST_NODE(s);
+    delete_expr(ctx, s->dimension);
+    Free(ctx, s);
 } // delete_scalar_or_array
 
-static Typedef *new_typedef(Context *ctx, int isconst, const char *datatype,
-                            ScalarOrArray *soa)
+static MOJOSHADER_astTypedef *new_typedef(Context *ctx, const int isconst,
+                                          const char *datatype,
+                                          MOJOSHADER_astScalarOrArray *soa)
 {
     // we correct this datatype to the final string during semantic analysis.
-    NEW_AST_NODE(retval, Typedef, AST_TYPEDEF);
+    NEW_AST_NODE(retval, MOJOSHADER_astTypedef, MOJOSHADER_AST_TYPEDEF);
     retval->isconst = isconst;
     retval->datatype = datatype;
     retval->details = soa;
     return retval;
 } // new_typedef
 
-static void delete_typedef(Context *ctx, Typedef *td)
+static void delete_typedef(Context *ctx, MOJOSHADER_astTypedef *td)
 {
     DELETE_AST_NODE(td);
     delete_scalar_or_array(ctx, td->details);
     Free(ctx, td);
 } // delete_typedef
 
-static PackOffset *new_pack_offset(Context *ctx, const char *a, const char *b)
+static MOJOSHADER_astPackOffset *new_pack_offset(Context *ctx,
+                                                 const char *a, const char *b)
 {
-    NEW_AST_NODE(retval, PackOffset, AST_PACK_OFFSET);
+    NEW_AST_NODE(retval, MOJOSHADER_astPackOffset, MOJOSHADER_AST_PACK_OFFSET);
     retval->ident1 = a;
     retval->ident2 = b;
     return retval;
 } // new_pack_offset
 
-static void delete_pack_offset(Context *ctx, PackOffset *o)
+static void delete_pack_offset(Context *ctx, MOJOSHADER_astPackOffset *o)
 {
     DELETE_AST_NODE(o);
     Free(ctx, o);
 } // delete_pack_offset
 
-static VariableLowLevel *new_variable_lowlevel(Context *ctx, PackOffset *po,
+static MOJOSHADER_astVariableLowLevel *new_variable_lowlevel(Context *ctx,
+                                               MOJOSHADER_astPackOffset *po,
                                                const char *reg)
 {
-    NEW_AST_NODE(retval, VariableLowLevel, AST_VARIABLE_LOWLEVEL);
+    NEW_AST_NODE(retval, MOJOSHADER_astVariableLowLevel,
+                 MOJOSHADER_AST_VARIABLE_LOWLEVEL);
     retval->packoffset = po;
     retval->register_name = reg;
     return retval;
 } // new_variable_lowlevel
 
-static void delete_variable_lowlevel(Context *ctx, VariableLowLevel *vll)
+static void delete_variable_lowlevel(Context *ctx,
+                                     MOJOSHADER_astVariableLowLevel *vll)
 {
     DELETE_AST_NODE(vll);
     delete_pack_offset(ctx, vll->packoffset);
     Free(ctx, vll);
 } // delete_variable_lowlevel
 
-static Annotations *new_annotation(Context *ctx, const char *datatype,
-                                   Expression *initializer)
+static MOJOSHADER_astAnnotations *new_annotation(Context *ctx,
+                                        const char *datatype,
+                                        MOJOSHADER_astExpression *initializer)
 {
-    NEW_AST_NODE(retval, Annotations, AST_ANNOTATION);
+    NEW_AST_NODE(retval, MOJOSHADER_astAnnotations, MOJOSHADER_AST_ANNOTATION);
     retval->datatype = datatype;
     retval->initializer = initializer;
     retval->next = NULL;
     return retval;
 } // new_annotation
 
-static void delete_annotation(Context *ctx, Annotations *annotations)
+static void delete_annotation(Context *ctx, MOJOSHADER_astAnnotations *annos)
 {
-    DELETE_AST_NODE(annotations);
-    delete_annotation(ctx, annotations->next);
-    delete_expr(ctx, annotations->initializer);
-    Free(ctx, annotations);
+    DELETE_AST_NODE(annos);
+    delete_annotation(ctx, annos->next);
+    delete_expr(ctx, annos->initializer);
+    Free(ctx, annos);
 } // delete_annotation
 
-static VariableDeclaration *new_variable_declaration(Context *ctx,
-                                    ScalarOrArray *soa, const char *semantic,
-                                    Annotations *annotations, Expression *init,
-                                    VariableLowLevel *vll)
+static MOJOSHADER_astVariableDeclaration *new_variable_declaration(
+                            Context *ctx, MOJOSHADER_astScalarOrArray *soa,
+                            const char *semantic,
+                            MOJOSHADER_astAnnotations *annotations,
+                            MOJOSHADER_astExpression *init,
+                            MOJOSHADER_astVariableLowLevel *vll)
 {
-    NEW_AST_NODE(retval, VariableDeclaration, AST_VARIABLE_DECLARATION);
+    NEW_AST_NODE(retval, MOJOSHADER_astVariableDeclaration,
+                 MOJOSHADER_AST_VARIABLE_DECLARATION);
     retval->attributes = 0;
     retval->datatype = NULL;
     retval->anonymous_datatype = NULL;
@@ -1123,7 +664,8 @@
     return retval;
 } // new_variable_declaration
 
-static void delete_variable_declaration(Context *ctx, VariableDeclaration *dcl)
+static void delete_variable_declaration(Context *ctx,
+                                        MOJOSHADER_astVariableDeclaration *dcl)
 {
     DELETE_AST_NODE(dcl);
     delete_variable_declaration(ctx, dcl->next);
@@ -1134,16 +676,18 @@
     Free(ctx, dcl);
 } // delete_variable_declaration
 
-static CompilationUnit *new_global_variable(Context *ctx,
-                                            VariableDeclaration *decl)
+static MOJOSHADER_astCompilationUnit *new_global_variable(Context *ctx,
+                                      MOJOSHADER_astVariableDeclaration *decl)
 {
-    NEW_AST_NODE(retval, CompilationUnitVariable, AST_COMPUNIT_VARIABLE);
+    NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitVariable,
+                 MOJOSHADER_AST_COMPUNIT_VARIABLE);
     retval->next = NULL;
     retval->declaration = decl;
-    return (CompilationUnit *) retval;
+    return (MOJOSHADER_astCompilationUnit *) retval;
 } // new_global_variable
 
-static void delete_global_variable(Context *ctx, CompilationUnitVariable *var)
+static void delete_global_variable(Context *ctx,
+                                   MOJOSHADER_astCompilationUnitVariable *var)
 {
     DELETE_AST_NODE(var);
     delete_compilation_unit(ctx, var->next);
@@ -1151,15 +695,18 @@
     Free(ctx, var);
 } // delete_global_variable
 
-static CompilationUnit *new_global_typedef(Context *ctx, Typedef *td)
+static MOJOSHADER_astCompilationUnit *new_global_typedef(Context *ctx,
+                                                     MOJOSHADER_astTypedef *td)
 {
-    NEW_AST_NODE(retval, CompilationUnitTypedef, AST_COMPUNIT_TYPEDEF);
+    NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitTypedef,
+                 MOJOSHADER_AST_COMPUNIT_TYPEDEF);
     retval->next = NULL;
     retval->type_info = td;
-    return (CompilationUnit *) retval;
+    return (MOJOSHADER_astCompilationUnit *) retval;
 } // new_global_typedef
 
-static void delete_global_typedef(Context *ctx, CompilationUnitTypedef *unit)
+static void delete_global_typedef(Context *ctx,
+                                  MOJOSHADER_astCompilationUnitTypedef *unit)
 {
     DELETE_AST_NODE(unit);
     delete_compilation_unit(ctx, unit->next);
@@ -1167,19 +714,22 @@
     Free(ctx, unit);
 } // delete_global_typedef
 
-static StructMembers *new_struct_member(Context *ctx, ScalarOrArray *soa,
-                                        const char *semantic)
+static MOJOSHADER_astStructMembers *new_struct_member(Context *ctx,
+                                            MOJOSHADER_astScalarOrArray *soa,
+                                            const char *semantic)
 {
-    NEW_AST_NODE(retval, StructMembers, AST_STRUCT_MEMBER);
+    NEW_AST_NODE(retval, MOJOSHADER_astStructMembers,
+                 MOJOSHADER_AST_STRUCT_MEMBER);
     retval->datatype = NULL;
     retval->semantic = semantic;
     retval->details = soa;
-    retval->interpolation_mod = INTERPMOD_NONE;
+    retval->interpolation_mod = MOJOSHADER_AST_INTERPMOD_NONE;
     retval->next = NULL;
     return retval;
 } // new_struct_member
 
-static void delete_struct_member(Context *ctx, StructMembers *member)
+static void delete_struct_member(Context *ctx,
+                                 MOJOSHADER_astStructMembers *member)
 {
     DELETE_AST_NODE(member);
     delete_struct_member(ctx, member->next);
@@ -1187,31 +737,37 @@
     Free(ctx, member);
 } // delete_struct_member
 
-static StructDeclaration *new_struct_declaration(Context *ctx,
-                                    const char *name, StructMembers *members)
+static MOJOSHADER_astStructDeclaration *new_struct_declaration(Context *ctx,
+                                        const char *name,
+                                        MOJOSHADER_astStructMembers *members)
 {
-    NEW_AST_NODE(retval, StructDeclaration, AST_STRUCT_DECLARATION);
+    NEW_AST_NODE(retval, MOJOSHADER_astStructDeclaration,
+                 MOJOSHADER_AST_STRUCT_DECLARATION);
     retval->name = name;
     retval->members = members;
     return retval;
 } // new_struct_declaration
 
-static void delete_struct_declaration(Context *ctx, StructDeclaration *decl)
+static void delete_struct_declaration(Context *ctx,
+                                      MOJOSHADER_astStructDeclaration *decl)
 {
     DELETE_AST_NODE(decl);
     delete_struct_member(ctx, decl->members);
     Free(ctx, decl);
 } // delete_struct_declaration
 
-static CompilationUnit *new_global_struct(Context *ctx, StructDeclaration *sd)
+static MOJOSHADER_astCompilationUnit *new_global_struct(Context *ctx,
+                                           MOJOSHADER_astStructDeclaration *sd)
 {
-    NEW_AST_NODE(retval, CompilationUnitStruct, AST_COMPUNIT_STRUCT);
+    NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitStruct,
+                 MOJOSHADER_AST_COMPUNIT_STRUCT);
     retval->next = NULL;
     retval->struct_info = sd;
-    return (CompilationUnit *) retval;
+    return (MOJOSHADER_astCompilationUnit *) retval;
 } // new_global_struct
 
-static void delete_global_struct(Context *ctx, CompilationUnitStruct *unit)
+static void delete_global_struct(Context *ctx,
+                                 MOJOSHADER_astCompilationUnitStruct *unit)
 {
     DELETE_AST_NODE(unit);
     delete_compilation_unit(ctx, unit->next);
@@ -1219,7 +775,8 @@
     Free(ctx, unit);
 } // delete_global_struct
 
-static void delete_compilation_unit(Context *ctx, CompilationUnit *unit)
+static void delete_compilation_unit(Context *ctx,
+                                    MOJOSHADER_astCompilationUnit *unit)
 {
     if (!unit) return;
 
@@ -1231,11 +788,11 @@
     // Please note that everyone should _try_ to delete their "next" member,
     //  just in case, but hopefully this cleaned it out.
 
-    CompilationUnit *i = unit->next;
+    MOJOSHADER_astCompilationUnit *i = unit->next;
     unit->next = NULL;
     while (i)
     {
-        CompilationUnit *next = i->next;
+        MOJOSHADER_astCompilationUnit *next = i->next;
         i->next = NULL;
         delete_compilation_unit(ctx, i);
         i = next;
@@ -1244,11 +801,11 @@
     switch (unit->ast.type)
     {
         #define DELETE_UNIT(typ, cls, fn) \
-            case AST_COMPUNIT_##typ: delete_##fn(ctx, (cls *) unit); break;
-        DELETE_UNIT(FUNCTION, CompilationUnitFunction, function);
-        DELETE_UNIT(TYPEDEF, CompilationUnitTypedef, global_typedef);
-        DELETE_UNIT(VARIABLE, CompilationUnitVariable, global_variable);
-        DELETE_UNIT(STRUCT, CompilationUnitStruct, global_struct);
+            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);
         #undef DELETE_UNIT
         default: assert(0 && "missing cleanup code"); break;
     } // switch
@@ -1256,15 +813,18 @@
     // don't free (unit) here, the class-specific functions do it.
 } // delete_compilation_unit
 
-static Statement *new_typedef_statement(Context *ctx, Typedef *td)
+static MOJOSHADER_astStatement *new_typedef_statement(Context *ctx,
+                                                      MOJOSHADER_astTypedef *td)
 {
-    NEW_AST_NODE(retval, TypedefStatement, AST_STATEMENT_TYPEDEF);
+    NEW_AST_NODE(retval, MOJOSHADER_astTypedefStatement,
+                 MOJOSHADER_AST_STATEMENT_TYPEDEF);
     retval->next = NULL;
     retval->type_info = td;
-    return (Statement *) retval;
+    return (MOJOSHADER_astStatement *) retval;
 } // new_typedef_statement
 
-static void delete_typedef_statement(Context *ctx, TypedefStatement *stmt)
+static void delete_typedef_statement(Context *ctx,
+                                     MOJOSHADER_astTypedefStatement *stmt)
 {
     DELETE_AST_NODE(stmt);
     delete_statement(ctx, stmt->next);
@@ -1272,15 +832,18 @@
     Free(ctx, stmt);
 } // delete_typedef_statement
 
-static Statement *new_return_statement(Context *ctx, Expression *expr)
+static MOJOSHADER_astStatement *new_return_statement(Context *ctx,
+                                                MOJOSHADER_astExpression *expr)
 {
-    NEW_AST_NODE(retval, ReturnStatement, AST_STATEMENT_RETURN);
+    NEW_AST_NODE(retval, MOJOSHADER_astReturnStatement,
+                 MOJOSHADER_AST_STATEMENT_RETURN);
     retval->next = NULL;
     retval->expr = expr;
-    return (Statement *) retval;
+    return (MOJOSHADER_astStatement *) retval;
 } // new_return_statement
 
-static void delete_return_statement(Context *ctx, ReturnStatement *stmt)
+static void delete_return_statement(Context *ctx,
+                                    MOJOSHADER_astReturnStatement *stmt)
 {
     DELETE_AST_NODE(stmt);
     delete_statement(ctx, stmt->next);
@@ -1288,15 +851,18 @@
     Free(ctx, stmt);
 } // delete_return_statement
 
-static Statement *new_block_statement(Context *ctx, Statement *statements)
+static MOJOSHADER_astStatement *new_block_statement(Context *ctx,
+                                               MOJOSHADER_astStatement *stmts)
 {
-    NEW_AST_NODE(retval, BlockStatement, AST_STATEMENT_BLOCK);
+    NEW_AST_NODE(retval, MOJOSHADER_astBlockStatement,
+                 MOJOSHADER_AST_STATEMENT_BLOCK);
     retval->next = NULL;
-    retval->statements = statements;
-    return (Statement *) retval;
+    retval->statements = stmts;
+    return (MOJOSHADER_astStatement *) retval;
 } // new_block_statement
 
-static void delete_block_statement(Context *ctx, BlockStatement *stmt)
+static void delete_block_statement(Context *ctx,
+                                   MOJOSHADER_astBlockStatement *stmt)
 {
     DELETE_AST_NODE(stmt);
     delete_statement(ctx, stmt->statements);
@@ -1304,12 +870,15 @@
     Free(ctx, stmt);
 } // delete_statement_block
 
-static Statement *new_for_statement(Context *ctx, VariableDeclaration *decl,
-                                    Expression *initializer,
-                                    Expression *looptest, Expression *counter,
-                                    Statement *statement)
+static MOJOSHADER_astStatement *new_for_statement(Context *ctx,
+                                    MOJOSHADER_astVariableDeclaration *decl,
+                                    MOJOSHADER_astExpression *initializer,
+                                    MOJOSHADER_astExpression *looptest,
+                                    MOJOSHADER_astExpression *counter,
+                                    MOJOSHADER_astStatement *statement)
 {
-    NEW_AST_NODE(retval, ForStatement, AST_STATEMENT_FOR);
+    NEW_AST_NODE(retval, MOJOSHADER_astForStatement,
+                 MOJOSHADER_AST_STATEMENT_FOR);
     retval->next = NULL;
     retval->unroll = -1;
     retval->var_decl = decl;
@@ -1317,10 +886,10 @@
     retval->looptest = looptest;
     retval->counter = counter;
     retval->statement = statement;
-    return (Statement *) retval;
+    return (MOJOSHADER_astStatement *) retval;
 } // new_for_statement
 
-static void delete_for_statement(Context *ctx, ForStatement *stmt)
+static void delete_for_statement(Context *ctx,MOJOSHADER_astForStatement *stmt)
 {
     DELETE_AST_NODE(stmt);
     delete_statement(ctx, stmt->next);
@@ -1332,18 +901,20 @@
     Free(ctx, stmt);
 } // delete_for_statement
 
-static Statement *new_do_statement(Context *ctx, int64 unroll,
-                                   Statement *stmt, Expression *expr)
+static MOJOSHADER_astStatement *new_do_statement(Context *ctx,
+                                                const int unroll,
+                                                MOJOSHADER_astStatement *stmt,
+                                                MOJOSHADER_astExpression *expr)
 {
-    NEW_AST_NODE(retval, DoStatement, AST_STATEMENT_DO);
+    NEW_AST_NODE(retval,MOJOSHADER_astDoStatement,MOJOSHADER_AST_STATEMENT_DO);
     retval->next = NULL;
     retval->unroll = unroll;
     retval->expr = expr;
     retval->statement = stmt;
-    return (Statement *) retval;
+    return (MOJOSHADER_astStatement *) retval;
 } // new_do_statement
 
-static void delete_do_statement(Context *ctx, DoStatement *stmt)
+static void delete_do_statement(Context *ctx, MOJOSHADER_astDoStatement *stmt)
 {
     DELETE_AST_NODE(stmt);
     delete_statement(ctx, stmt->next);
@@ -1352,18 +923,22 @@
     Free(ctx, stmt);
 } // delete_do_statement
 
-static Statement *new_while_statement(Context *ctx, int64 unroll,
-                                      Expression *expr, Statement *stmt)
+static MOJOSHADER_astStatement *new_while_statement(Context *ctx,
+                                                const int unroll,
+                                                MOJOSHADER_astExpression *expr,
+                                                MOJOSHADER_astStatement *stmt)
 {
-    NEW_AST_NODE(retval, WhileStatement, AST_STATEMENT_WHILE);
+    NEW_AST_NODE(retval, MOJOSHADER_astWhileStatement,
+                 MOJOSHADER_AST_STATEMENT_WHILE);
     retval->next = NULL;
     retval->unroll = unroll;
     retval->expr = expr;
     retval->statement = stmt;
-    return (Statement *) retval;
+    return (MOJOSHADER_astStatement *) retval;
 } // new_while_statement
 
-static void delete_while_statement(Context *ctx, WhileStatement *stmt)
+static void delete_while_statement(Context *ctx,
+                                   MOJOSHADER_astWhileStatement *stmt)
 {
     DELETE_AST_NODE(stmt);
     delete_statement(ctx, stmt->next);
@@ -1372,19 +947,22 @@
     Free(ctx, stmt);
 } // delete_while_statement
 
-static Statement *new_if_statement(Context *ctx, int attr, Expression *expr,
-                                   Statement *stmt, Statement *elsestmt)
+static MOJOSHADER_astStatement *new_if_statement(Context *ctx,
+                                            const int attr,
+                                            MOJOSHADER_astExpression *expr,
+                                            MOJOSHADER_astStatement *stmt,
+                                            MOJOSHADER_astStatement *elsestmt)
 {
-    NEW_AST_NODE(retval, IfStatement, AST_STATEMENT_IF);
+    NEW_AST_NODE(retval,MOJOSHADER_astIfStatement,MOJOSHADER_AST_STATEMENT_IF);
     retval->next = NULL;
     retval->attributes = attr;
     retval->expr = expr;
     retval->statement = stmt;
     retval->else_statement = elsestmt;
-    return (Statement *) retval;
+    return (MOJOSHADER_astStatement *) retval;
 } // new_if_statement
 
-static void delete_if_statement(Context *ctx, IfStatement *stmt)
+static void delete_if_statement(Context *ctx, MOJOSHADER_astIfStatement *stmt)
 {
     DELETE_AST_NODE(stmt);
     delete_statement(ctx, stmt->next);
@@ -1394,17 +972,18 @@
     Free(ctx, stmt);
 } // delete_if_statement
 
-static SwitchCases *new_switch_case(Context *ctx, Expression *expr,
-                                    Statement *stmt)
+static MOJOSHADER_astSwitchCases *new_switch_case(Context *ctx,
+                                                MOJOSHADER_astExpression *expr,
+                                                MOJOSHADER_astStatement *stmt)
 {
-    NEW_AST_NODE(retval, SwitchCases, AST_SWITCH_CASE);
+    NEW_AST_NODE(retval, MOJOSHADER_astSwitchCases, MOJOSHADER_AST_SWITCH_CASE);
     retval->expr = expr;
     retval->statement = stmt;
     retval->next = NULL;
     return retval;
 } // new_switch_case
 
-static void delete_switch_case(Context *ctx, SwitchCases *sc)
+static void delete_switch_case(Context *ctx, MOJOSHADER_astSwitchCases *sc)
 {
     DELETE_AST_NODE(sc);
     delete_switch_case(ctx, sc->next);
@@ -1413,71 +992,82 @@
     Free(ctx, sc);
 } // delete_switch_case
 
-static Statement *new_empty_statement(Context *ctx)
+static MOJOSHADER_astStatement *new_empty_statement(Context *ctx)
 {
-    NEW_AST_NODE(retval, EmptyStatement, AST_STATEMENT_EMPTY);
+    NEW_AST_NODE(retval, MOJOSHADER_astEmptyStatement,
+                 MOJOSHADER_AST_STATEMENT_EMPTY);
     retval->next = NULL;
-    return (Statement *) retval;
+    return (MOJOSHADER_astStatement *) retval;
 } // new_empty_statement
 
-static void delete_empty_statement(Context *ctx, EmptyStatement *stmt)
+static void delete_empty_statement(Context *ctx,
+                                   MOJOSHADER_astEmptyStatement *stmt)
 {
     DELETE_AST_NODE(stmt);
     delete_statement(ctx, stmt->next);
     Free(ctx, stmt);
 } // delete_empty_statement
 
-static Statement *new_break_statement(Context *ctx)
+static MOJOSHADER_astStatement *new_break_statement(Context *ctx)
 {
-    NEW_AST_NODE(retval, BreakStatement, AST_STATEMENT_BREAK);
+    NEW_AST_NODE(retval, MOJOSHADER_astBreakStatement,
+                 MOJOSHADER_AST_STATEMENT_BREAK);
     retval->next = NULL;
-    return (Statement *) retval;
+    return (MOJOSHADER_astStatement *) retval;
 } // new_break_statement
 
-static void delete_break_statement(Context *ctx, BreakStatement *stmt)
+static void delete_break_statement(Context *ctx,
+                                   MOJOSHADER_astBreakStatement *stmt)
 {
     DELETE_AST_NODE(stmt);
     delete_statement(ctx, stmt->next);
     Free(ctx, stmt);
 } // delete_break_statement
 
-static Statement *new_continue_statement(Context *ctx)
+static MOJOSHADER_astStatement *new_continue_statement(Context *ctx)
 {
-    NEW_AST_NODE(retval, ContinueStatement, AST_STATEMENT_CONTINUE);
+    NEW_AST_NODE(retval, MOJOSHADER_astContinueStatement,
+                 MOJOSHADER_AST_STATEMENT_CONTINUE);
     retval->next = NULL;
-    return (Statement *) retval;
+    return (MOJOSHADER_astStatement *) retval;
 } // new_continue_statement
 
-static void delete_continue_statement(Context *ctx, ContinueStatement *stmt)
+static void delete_continue_statement(Context *ctx,
+                                      MOJOSHADER_astContinueStatement *stmt)
 {
     DELETE_AST_NODE(stmt);
     delete_statement(ctx, stmt->next);
     Free(ctx, stmt);
 } // delete_continue_statement
 
-static Statement *new_discard_statement(Context *ctx)
+static MOJOSHADER_astStatement *new_discard_statement(Context *ctx)
 {
-    NEW_AST_NODE(retval, DiscardStatement, AST_STATEMENT_DISCARD);
+    NEW_AST_NODE(retval, MOJOSHADER_astDiscardStatement,
+                 MOJOSHADER_AST_STATEMENT_DISCARD);
     retval->next = NULL;
-    return (Statement *) retval;
+    return (MOJOSHADER_astStatement *) retval;
 } // new_discard_statement
 
-static void delete_discard_statement(Context *ctx, DiscardStatement *stmt)
+static void delete_discard_statement(Context *ctx,
+                                     MOJOSHADER_astDiscardStatement *stmt)
 {
     DELETE_AST_NODE(stmt);
     delete_statement(ctx, stmt->next);
     Free(ctx, stmt);
 } // delete_discard_statement
 
-static Statement *new_expr_statement(Context *ctx, Expression *expr)
+static MOJOSHADER_astStatement *new_expr_statement(Context *ctx,
+                                                MOJOSHADER_astExpression *expr)
 {
-    NEW_AST_NODE(retval, ExpressionStatement, AST_STATEMENT_EXPRESSION);
+    NEW_AST_NODE(retval, MOJOSHADER_astExpressionStatement,
+                 MOJOSHADER_AST_STATEMENT_EXPRESSION);
     retval->next = NULL;
     retval->expr = expr;
-    return (Statement *) retval;
+    return (MOJOSHADER_astStatement *) retval;
 } // new_expr_statement
 
-static void delete_expr_statement(Context *ctx, ExpressionStatement *stmt)
+static void delete_expr_statement(Context *ctx,
+                                  MOJOSHADER_astExpressionStatement *stmt)
 {
     DELETE_AST_NODE(stmt);
     delete_statement(ctx, stmt->next);
@@ -1485,18 +1075,22 @@
     Free(ctx, stmt);
 } // delete_expr_statement
 
-static Statement *new_switch_statement(Context *ctx, int attr,
-                                       Expression *expr, SwitchCases *cases)
+static MOJOSHADER_astStatement *new_switch_statement(Context *ctx,
+                                            const int attr,
+                                            MOJOSHADER_astExpression *expr,
+                                            MOJOSHADER_astSwitchCases *cases)
 {
-    NEW_AST_NODE(retval, SwitchStatement, AST_STATEMENT_SWITCH);
+    NEW_AST_NODE(retval, MOJOSHADER_astSwitchStatement,
+                 MOJOSHADER_AST_STATEMENT_SWITCH);
     retval->next = NULL;
     retval->attributes = attr;
     retval->expr = expr;
     retval->cases = cases;
-    return (Statement *) retval;
+    return (MOJOSHADER_astStatement *) retval;
 } // new_switch_statement
 
-static void delete_switch_statement(Context *ctx, SwitchStatement *stmt)
+static void delete_switch_statement(Context *ctx,
+                                    MOJOSHADER_astSwitchStatement *stmt)
 {
     DELETE_AST_NODE(stmt);
     delete_expr(ctx, stmt->expr);
@@ -1504,15 +1098,18 @@
     Free(ctx, stmt);
 } // delete_switch_statement
 
-static Statement *new_struct_statement(Context *ctx, StructDeclaration *sd)
+static MOJOSHADER_astStatement *new_struct_statement(Context *ctx,
+                                        MOJOSHADER_astStructDeclaration *sd)
 {
-    NEW_AST_NODE(retval, StructStatement, AST_STATEMENT_STRUCT);
+    NEW_AST_NODE(retval, MOJOSHADER_astStructStatement,
+                 MOJOSHADER_AST_STATEMENT_STRUCT);
     retval->next = NULL;
     retval->struct_info = sd;
-    return (Statement *) retval;
+    return (MOJOSHADER_astStatement *) retval;
 } // new_struct_statement
 
-static void delete_struct_statement(Context *ctx, StructStatement *stmt)
+static void delete_struct_statement(Context *ctx,
+                                    MOJOSHADER_astStructStatement *stmt)
 {
     DELETE_AST_NODE(stmt);
     delete_statement(ctx, stmt->next);
@@ -1520,15 +1117,18 @@
     Free(ctx, stmt);
 } // delete_struct_statement
 
-static Statement *new_vardecl_statement(Context *ctx, VariableDeclaration *vd)
+static MOJOSHADER_astStatement *new_vardecl_statement(Context *ctx,
+                                        MOJOSHADER_astVariableDeclaration *vd)
 {
-    NEW_AST_NODE(retval, VarDeclStatement, AST_STATEMENT_VARDECL);
+    NEW_AST_NODE(retval, MOJOSHADER_astVarDeclStatement,
+                 MOJOSHADER_AST_STATEMENT_VARDECL);
     retval->next = NULL;
     retval->declaration = vd;
-    return (Statement *) retval;
+    return (MOJOSHADER_astStatement *) retval;
 } // new_vardecl_statement
 
-static void delete_vardecl_statement(Context *ctx, VarDeclStatement *stmt)
+static void delete_vardecl_statement(Context *ctx,
+                                     MOJOSHADER_astVarDeclStatement *stmt)
 {
     DELETE_AST_NODE(stmt);
     delete_statement(ctx, stmt->next);
@@ -1536,7 +1136,7 @@
     Free(ctx, stmt);
 } // delete_vardecl_statement
 
-static void delete_statement(Context *ctx, Statement *stmt)
+static void delete_statement(Context *ctx, MOJOSHADER_astStatement *stmt)
 {
     if (!stmt) return;
 
@@ -1548,11 +1148,11 @@
     // Please note that everyone should _try_ to delete their "next" member,
     //  just in case, but hopefully this cleaned it out.
 
-    Statement *i = stmt->next;
+    MOJOSHADER_astStatement *i = stmt->next;
     stmt->next = NULL;
     while (i)
     {
-        Statement *next = i->next;
+        MOJOSHADER_astStatement *next = i->next;
         i->next = NULL;
         delete_statement(ctx, i);
         i = next;
@@ -1560,23 +1160,24 @@
 
     switch (stmt->ast.type)
     {
-        #define DELETE_STATEMENT(typ, cls, fn) case AST_STATEMENT_##typ: \
-            delete_##fn##_statement(ctx, (cls *) stmt); break;
-        DELETE_STATEMENT(BLOCK, BlockStatement, block);
-        DELETE_STATEMENT(EMPTY, EmptyStatement, empty);
-        DELETE_STATEMENT(IF, IfStatement, if);
-        DELETE_STATEMENT(SWITCH, SwitchStatement, switch);
-        DELETE_STATEMENT(EXPRESSION, ExpressionStatement, expr);
-        DELETE_STATEMENT(FOR, ForStatement, for);
-        DELETE_STATEMENT(DO, DoStatement, do);
-        DELETE_STATEMENT(WHILE, WhileStatement, while);
-        DELETE_STATEMENT(RETURN, ReturnStatement, return);
-        DELETE_STATEMENT(BREAK, BreakStatement, break);
-        DELETE_STATEMENT(CONTINUE, ContinueStatement, continue);
-        DELETE_STATEMENT(DISCARD, DiscardStatement, discard);
-        DELETE_STATEMENT(TYPEDEF, TypedefStatement, typedef);
-        DELETE_STATEMENT(STRUCT, StructStatement, struct);
-        DELETE_STATEMENT(VARDECL, VarDeclStatement, vardecl);
+        #define DELETE_STATEMENT(typ, cls, fn) \
+            case MOJOSHADER_AST_STATEMENT_##typ: \
+                delete_##fn##_statement(ctx, (cls *) stmt); break;
+        DELETE_STATEMENT(BLOCK, MOJOSHADER_astBlockStatement, block);
+        DELETE_STATEMENT(EMPTY, MOJOSHADER_astEmptyStatement, empty);
+        DELETE_STATEMENT(IF, MOJOSHADER_astIfStatement, if);
+        DELETE_STATEMENT(SWITCH, MOJOSHADER_astSwitchStatement, switch);
+        DELETE_STATEMENT(EXPRESSION, MOJOSHADER_astExpressionStatement, expr);
+        DELETE_STATEMENT(FOR, MOJOSHADER_astForStatement, for);
+        DELETE_STATEMENT(DO, MOJOSHADER_astDoStatement, do);
+        DELETE_STATEMENT(WHILE, MOJOSHADER_astWhileStatement, while);
+        DELETE_STATEMENT(RETURN, MOJOSHADER_astReturnStatement, return);
+        DELETE_STATEMENT(BREAK, MOJOSHADER_astBreakStatement, break);
+        DELETE_STATEMENT(CONTINUE, MOJOSHADER_astContinueStatement, continue);
+        DELETE_STATEMENT(DISCARD, MOJOSHADER_astDiscardStatement, discard);
+        DELETE_STATEMENT(TYPEDEF, MOJOSHADER_astTypedefStatement, typedef);
+        DELETE_STATEMENT(STRUCT, MOJOSHADER_astStructStatement, struct);
+        DELETE_STATEMENT(VARDECL, MOJOSHADER_astVarDeclStatement, vardecl);
         #undef DELETE_STATEMENT
         default: assert(0 && "missing cleanup code"); break;
     } // switch
@@ -1597,756 +1198,6 @@
 #include "mojoshader_parser_hlsl.h"
 
 
-// !!! FIXME: this screws up on order of operations.
-static void print_ast(const int substmt, void *ast)
-{
-    const char *nl = substmt ? "" : "\n";
-    static int indent = 0;
-    int isblock = 0;
-    int i;
-
-    if (!ast) return;
-
-    #define DO_INDENT do { \
-        if (!substmt) { for (i = 0; i < indent; i++) printf("    "); } \
-    } while (0)
-
-    switch ( ((ASTGeneric *) ast)->ast.type )
-    {
-        case AST_OP_POSTINCREMENT:
-            print_ast(0, ((ExpressionUnary *) ast)->operand);
-            printf("++");
-            break;
-
-        case AST_OP_POSTDECREMENT:
-            print_ast(0, ((ExpressionUnary *) ast)->operand);
-            printf("--");
-            break;
-
-        case AST_OP_PREINCREMENT:
-            printf("++");
-            print_ast(0, ((ExpressionUnary *) ast)->operand);
-            break;
-
-        case AST_OP_PREDECREMENT:
-            printf("--");
-            print_ast(0, ((ExpressionUnary *) ast)->operand);
-            break;
-
-        case AST_OP_NEGATE:
-            printf("-");
-            print_ast(0, ((ExpressionUnary *) ast)->operand);
-            break;
-
-        case AST_OP_COMPLEMENT:
-            printf("~");
-            print_ast(0, ((ExpressionUnary *) ast)->operand);
-            break;
-
-        case AST_OP_NOT:
-            printf("!");
-            print_ast(0, ((ExpressionUnary *) ast)->operand);
-            break;
-
-        case AST_OP_DEREF_ARRAY:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf("[");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            printf("]");
-            break;
-
-        case AST_OP_DEREF_STRUCT:
-            print_ast(0, ((ExpressionDerefStruct *) ast)->identifier);
-            printf(".");
-            printf("%s", ((ExpressionDerefStruct *) ast)->member);
-            break;
-
-        case AST_OP_COMMA:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(", ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_MULTIPLY:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" * ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_DIVIDE:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" / ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_MODULO:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" %% ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_ADD:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" + ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_SUBTRACT:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" - ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_LSHIFT:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" << ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_RSHIFT:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" >> ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_LESSTHAN:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" < ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_GREATERTHAN:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" > ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_LESSTHANOREQUAL:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" <= ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_GREATERTHANOREQUAL:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" >= ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_EQUAL:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" == ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_NOTEQUAL:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" != ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_BINARYAND:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" & ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_BINARYXOR:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" ^ ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_BINARYOR:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" | ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_LOGICALAND:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" && ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_LOGICALOR:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" || ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_ASSIGN:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" = ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_MULASSIGN:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" *= ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_DIVASSIGN:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" /= ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_MODASSIGN:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" %%= ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_ADDASSIGN:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" += ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_SUBASSIGN:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" -= ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_LSHIFTASSIGN:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" <<= ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_RSHIFTASSIGN:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" >>= ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_ANDASSIGN:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" &= ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_XORASSIGN:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" ^= ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_ORASSIGN:
-            print_ast(0, ((ExpressionBinary *) ast)->left);
-            printf(" |= ");
-            print_ast(0, ((ExpressionBinary *) ast)->right);
-            break;
-
-        case AST_OP_CONDITIONAL:
-            print_ast(0, ((ExpressionTernary *) ast)->left);
-            printf(" ? ");
-            print_ast(0, ((ExpressionTernary *) ast)->center);
-            printf(" : ");
-            print_ast(0, ((ExpressionTernary *) ast)->right);
-            break;
-
-        case AST_OP_IDENTIFIER:
-            printf("%s", ((ExpressionIdentifier *) ast)->identifier);
-            break;
-
-        case AST_OP_INT_LITERAL:
-            printf("%lld", (long long) ((ExpressionIntLiteral *) ast)->value);
-            break;
-
-        case AST_OP_FLOAT_LITERAL:
-        {
-            const float f = ((ExpressionFloatLiteral *) ast)->value;
-            const long long flr = (long long) f;
-            if (((float) flr) == f)
-                printf("%lld.0", flr);
-            else
-                printf("%.16g", f);
-            break;
-        } // case
-
-        case AST_OP_STRING_LITERAL:
-            printf("\"%s\"", ((ExpressionStringLiteral *) ast)->string);
-            break;
-
-        case AST_OP_BOOLEAN_LITERAL:
-            printf("%s", ((ExpressionBooleanLiteral *) ast)->value ? "true" : "false");
-            break;
-
-        case AST_ARGUMENTS:
-            print_ast(0, ((Arguments *) ast)->argument);
-            if (((Arguments *) ast)->next != NULL)
-            {
-                printf(", ");
-                print_ast(0, ((Arguments *) ast)->next);
-            } // if
-            break;
-
-        case AST_OP_CALLFUNC:
-            print_ast(0, ((ExpressionCallFunction *) ast)->identifier);
-            printf("(");
-            print_ast(0, ((ExpressionCallFunction *) ast)->args);
-            printf(")");
-            break;
-
-        case AST_OP_CONSTRUCTOR:
-            printf("%s(", ((ExpressionConstructor *) ast)->datatype);
-            print_ast(0, ((ExpressionConstructor *) ast)->args);
-            printf(")");
-            break;
-
-        case AST_OP_CAST:
-            printf("(%s) (", ((ExpressionCast *) ast)->datatype);
-            print_ast(0, ((ExpressionCast *) ast)->operand);
-            printf(")");
-            break;
-
-        case AST_STATEMENT_EMPTY:
-            DO_INDENT;
-            printf(";%s", nl);
-            print_ast(0, ((Statement *) ast)->next);
-            break;
-
-        case AST_STATEMENT_EXPRESSION:
-            DO_INDENT;
-            print_ast(0, ((ExpressionStatement *) ast)->expr);  // !!! FIXME: This is named badly...
-            printf(";%s", nl);
-            print_ast(0, ((Statement *) ast)->next);
-            break;
-
-        case AST_STATEMENT_IF:
-            DO_INDENT;
-            printf("if (");
-            print_ast(0, ((IfStatement *) ast)->expr);
-            printf(")\n");
-            isblock = ((IfStatement *) ast)->statement->ast.type == AST_STATEMENT_BLOCK;
-            if (!isblock) indent++;
-            print_ast(0, ((IfStatement *) ast)->statement);
-            if (!isblock) indent--;
-            print_ast(0, ((Statement *) ast)->next);
-            break;
-
-        case AST_STATEMENT_TYPEDEF:
-            DO_INDENT;
-            print_ast(1, ((TypedefStatement *) ast)->type_info);
-            printf("%s", nl);
-            print_ast(0, ((Statement *) ast)->next);
-            break;
-
-        case AST_STATEMENT_SWITCH:
-            DO_INDENT;
-            switch ( ((SwitchStatement *) ast)->attributes )
-            {
-                case SWITCHATTR_NONE: break;
-                case SWITCHATTR_FLATTEN: printf("[flatten] "); break;
-                case SWITCHATTR_BRANCH: printf("[branch] "); break;
-                case SWITCHATTR_FORCECASE: printf("[forcecase] "); break;
-                case SWITCHATTR_CALL: printf("[call] "); break;
-            } // switch
-
-            printf("switch (");
-            print_ast(0, ((SwitchStatement *) ast)->expr);
-            printf(")\n");
-            DO_INDENT;
-            printf("{\n");
-            indent++;
-            print_ast(0, ((SwitchStatement *) ast)->cases);
-            indent--;
-            printf("\n");
-            DO_INDENT;
-            printf("}\n");
-            print_ast(0, ((Statement *) ast)->next);
-            break;
-
-        case AST_SWITCH_CASE:
-            DO_INDENT;
-            printf("case ");
-            print_ast(0, ((SwitchCases *) ast)->expr);
-            printf(":\n");
-            isblock = ((SwitchCases *) ast)->statement->ast.type == AST_STATEMENT_BLOCK;
-            if (!isblock) indent++;
-            print_ast(0, ((SwitchCases *) ast)->statement);
-            if (!isblock) indent--;
-            print_ast(0, ((SwitchCases *) ast)->next);
-            break;
-
-        case AST_STATEMENT_STRUCT:
-            DO_INDENT;
-            print_ast(0, ((CompilationUnitStruct *) ast)->struct_info);
-            printf(";%s%s", nl, nl);  // always space these out.
-            print_ast(0, ((Statement *) ast)->next);
-            break;
-
-        case AST_STATEMENT_VARDECL:
-            DO_INDENT;
-            print_ast(1, ((VarDeclStatement *) ast)->declaration);
-            printf(";%s", nl);
-            print_ast(0, ((Statement *) ast)->next);
-            break;
-
-        case AST_STATEMENT_BLOCK:
-            DO_INDENT;
-            printf("{\n");
-            indent++;
-            print_ast(0, ((BlockStatement *) ast)->statements);
-            indent--;
-            DO_INDENT;
-            printf("}\n");
-            print_ast(0, ((Statement *) ast)->next);
-            break;
-
-        case AST_STATEMENT_FOR:
-            DO_INDENT;
-            if (((ForStatement *) ast)->unroll == 0)
-                printf("[loop] ");
-            else if (((ForStatement *) ast)->unroll == -1)
-                printf("[unroll] ");
-            else if (((ForStatement *) ast)->unroll > 0)
-            {
-                printf("[unroll(%lld)] ",
-                        (long long) (((ForStatement *) ast)->unroll) );
-            } // else if
-
-            printf("for (");
-            print_ast(1, ((ForStatement *) ast)->var_decl);
-            if (((ForStatement *) ast)->initializer != NULL)
-            {
-                printf(" = ");
-                print_ast(1, ((ForStatement *) ast)->initializer);
-            } // if
-            printf("; ");
-            print_ast(1, ((ForStatement *) ast)->looptest);
-            printf("; ");
-            print_ast(1, ((ForStatement *) ast)->counter);
-
-            printf(")\n");
-            isblock = ((ForStatement *) ast)->statement->ast.type == AST_STATEMENT_BLOCK;
-            if (!isblock) indent++;
-            print_ast(0, ((ForStatement *) ast)->statement);
-            if (!isblock) indent--;
-
-            print_ast(0, ((Statement *) ast)->next);
-            break;
-
-        case AST_STATEMENT_DO:
-            DO_INDENT;
-            if (((DoStatement *) ast)->unroll == 0)
-                printf("[loop] ");
-            else if (((DoStatement *) ast)->unroll == -1)
-                printf("[unroll] ");
-            else if (((DoStatement *) ast)->unroll > 0)
-            {
-                printf("[unroll(%lld)] ",
-                        (long long) (((DoStatement *) ast)->unroll) );
-            } // else if
-
-            printf("do\n");
-
-            isblock = ((DoStatement *) ast)->statement->ast.type == AST_STATEMENT_BLOCK;
-            if (!isblock) indent++;
-            print_ast(0, ((DoStatement *) ast)->statement);
-            if (!isblock) indent--;
-
-            DO_INDENT;
-            printf("while (");
-            print_ast(0, ((DoStatement *) ast)->expr);
-            printf(");\n");
-
-            print_ast(0, ((Statement *) ast)->next);
-            break;
-
-        case AST_STATEMENT_WHILE:
-            DO_INDENT;
-            if (((WhileStatement *) ast)->unroll == 0)
-                printf("[loop] ");
-            else if (((WhileStatement *) ast)->unroll == -1)
-                printf("[unroll] ");
-            else if (((WhileStatement *) ast)->unroll > 0)
-            {
-                printf("[unroll(%lld)] ",
-                        (long long) (((WhileStatement *) ast)->unroll) );
-            } // else if
-
-            printf("while (");
-            print_ast(0, ((WhileStatement *) ast)->expr);
-            printf(")\n");
-
-            isblock = ((WhileStatement *) ast)->statement->ast.type == AST_STATEMENT_BLOCK;
-            if (!isblock) indent++;
-            print_ast(0, ((WhileStatement *) ast)->statement);
-            if (!isblock) indent--;
-
-            print_ast(0, ((Statement *) ast)->next);
-            break;
-
-        case AST_STATEMENT_RETURN:
-            DO_INDENT;
-            printf("return");
-            if (((ReturnStatement *) ast)->expr)
-            {
-                printf(" ");
-                print_ast(0, ((ReturnStatement *) ast)->expr);
-            } // if
-            printf(";%s", nl);
-            print_ast(0, ((Statement *) ast)->next);
-            break;
-
-        case AST_STATEMENT_BREAK:
-            DO_INDENT;
-            printf("break;%s", nl);
-            print_ast(0, ((Statement *) ast)->next);
-            break;
-
-        case AST_STATEMENT_CONTINUE:
-            DO_INDENT;
-            printf("continue;%s", nl);
-            print_ast(0, ((Statement *) ast)->next);
-            break;
-
-        case AST_STATEMENT_DISCARD:
-            DO_INDENT;
-            printf("discard;%s", nl);
-            print_ast(0, ((Statement *) ast)->next);
-            break;
-
-        case AST_COMPUNIT_FUNCTION:
-            DO_INDENT;
-            print_ast(0, ((CompilationUnitFunction *) ast)->declaration);
-            if (((CompilationUnitFunction *) ast)->definition == NULL)
-                printf(";%s", nl);
-            else
-            {
-                printf("%s", nl);
-                print_ast(0, ((CompilationUnitFunction *) ast)->definition);
-                printf("%s", nl);
-            } // else
-            print_ast(0, ((CompilationUnit *) ast)->next);
-            break;
-
-        case AST_COMPUNIT_TYPEDEF:
-            DO_INDENT;
-            print_ast(0, ((CompilationUnitTypedef *) ast)->type_info);
-            printf("%s", nl);
-            print_ast(0, ((Statement *) ast)->next);
-            break;
-
-        case AST_COMPUNIT_STRUCT:
-            DO_INDENT;
-            print_ast(0, ((CompilationUnitStruct *) ast)->struct_info);
-            printf(";%s%s", nl, nl);  // always space these out.
-            print_ast(0, ((CompilationUnit *) ast)->next);
-            break;
-
-        case AST_COMPUNIT_VARIABLE:
-            DO_INDENT;
-            print_ast(1, ((CompilationUnitVariable *) ast)->declaration);
-            printf(";%s", nl);
-            if (((CompilationUnit *) ast)->next && ((CompilationUnit *) ast)->next->ast.type != AST_COMPUNIT_VARIABLE)
-                printf("%s", nl);  // group vars together, and space out other things.
-            print_ast(0, ((CompilationUnit *) ast)->next);
-            break;
-
-        case AST_SCALAR_OR_ARRAY:
-            printf("%s", ((ScalarOrArray*) ast)->identifier);
-            if (((ScalarOrArray*) ast)->isarray)
-            {
-                printf("[");
-                print_ast(0, ((ScalarOrArray*) ast)->dimension);
-                printf("]");
-            } // if
-            break;
-
-        case AST_TYPEDEF:
-            DO_INDENT;
-            printf("typedef %s%s ",
-                    (((Typedef *) ast)->isconst) ? "const " : "",
-                    (((Typedef *) ast)->datatype));
-            print_ast(0, ((Typedef *) ast)->details);
-            printf(";%s", nl);
-            break;
-
-        case AST_FUNCTION_PARAMS:
-            switch (((FunctionParameters *) ast)->input_modifier)
-            {
-                case INPUTMOD_NONE: break;
-                case INPUTMOD_IN: printf("in "); break;
-                case INPUTMOD_OUT: printf("out "); break;
-                case INPUTMOD_INOUT: printf("in out "); break;
-                case INPUTMOD_UNIFORM: printf("uniform "); break;
-            } // switch
-
-            printf("%s %s", (((FunctionParameters *) ast)->datatype),
-                   (((FunctionParameters *) ast)->identifier));
-            if (((FunctionParameters *) ast)->semantic)
-                printf(" : %s", ((FunctionParameters *) ast)->semantic);
-
-            switch (((FunctionParameters *) ast)->interpolation_modifier)
-            {
-                case INTERPMOD_NONE: break;
-                case INTERPMOD_LINEAR: printf(" linear"); break;
-                case INTERPMOD_CENTROID: printf(" centroid"); break;
-                case INTERPMOD_NOINTERPOLATION: printf(" nointerpolation"); break;
-                case INTERPMOD_NOPERSPECTIVE: printf(" noperspective"); break;
-                case INTERPMOD_SAMPLE: printf(" sample"); break;
-            } // switch
-
-            if (((FunctionParameters *) ast)->initializer)
-            {
-                printf(" = ");
-                print_ast(0, ((FunctionParameters *) ast)->initializer);
-            } // if
-
-            if (((FunctionParameters *) ast)->next)
-            {
-                printf(", ");
-                print_ast(0, ((FunctionParameters *) ast)->next);
-            } // if
-            break;
-
-        case AST_FUNCTION_SIGNATURE:
-            switch (((FunctionSignature *) ast)->storage_class)
-            {
-                case FNSTORECLS_NONE: break;
-                case FNSTORECLS_INLINE: printf("inline "); break;
-            } // switch
-            printf("%s %s(",
-                    ((FunctionSignature *) ast)->datatype ?
-                        ((FunctionSignature *) ast)->datatype : "void",
-                    ((FunctionSignature *) ast)->identifier);
-            print_ast(0, ((FunctionSignature *) ast)->params);
-            printf(")");
-            if (((FunctionSignature *) ast)->semantic)
-                printf(" : %s", ((FunctionSignature *) ast)->semantic);
-            break;
-
-        case AST_STRUCT_DECLARATION:
-            printf("struct %s\n", ((StructDeclaration *) ast)->name);
-            DO_INDENT;
-            printf("{\n");
-            indent++;
-            print_ast(0, ((StructDeclaration *) ast)->members);
-            indent--;
-            DO_INDENT;
-            printf("}");
-            break;
-
-        case AST_STRUCT_MEMBER:
-            DO_INDENT;
-            switch (((StructMembers *) ast)->interpolation_mod)
-            {
-                case INTERPMOD_NONE: break;
-                case INTERPMOD_LINEAR: printf("linear "); break;
-                case INTERPMOD_CENTROID: printf("centroid "); break;
-                case INTERPMOD_NOINTERPOLATION: printf("nointerpolation "); break;
-                case INTERPMOD_NOPERSPECTIVE: printf("noperspective "); break;
-                case INTERPMOD_SAMPLE: printf("sample "); break;
-            } // switch
-            printf("%s ", ((StructMembers *) ast)->datatype);
-            print_ast(0, ((StructMembers *) ast)->details);
-            if (((StructMembers *) ast)->semantic)
-                printf(" : %s", ((StructMembers *) ast)->semantic);
-            printf(";%s", nl);
-            print_ast(0, ((StructMembers *) ast)->next);
-            break;
-
-        case AST_VARIABLE_DECLARATION:
-            DO_INDENT;
-            if (((VariableDeclaration *) ast)->attributes & VARATTR_EXTERN)
-                printf("extern ");
-            if (((VariableDeclaration *) ast)->attributes & VARATTR_NOINTERPOLATION)
-                printf("nointerpolation ");
-            if (((VariableDeclaration *) ast)->attributes & VARATTR_SHARED)
-                printf("shared");
-            if (((VariableDeclaration *) ast)->attributes & VARATTR_STATIC)
-                printf("static ");
-            if (((VariableDeclaration *) ast)->attributes & VARATTR_UNIFORM)
-                printf("uniform ");
-            if (((VariableDeclaration *) ast)->attributes & VARATTR_VOLATILE)
-                printf("nointerpolation ");
-            if (((VariableDeclaration *) ast)->attributes & VARATTR_CONST)
-                printf("const ");
-            if (((VariableDeclaration *) ast)->attributes & VARATTR_ROWMAJOR)
-                printf("rowmajor ");
-            if (((VariableDeclaration *) ast)->attributes & VARATTR_COLUMNMAJOR)
-                printf("columnmajor ");
-
-            if (((VariableDeclaration *) ast)->datatype)
-                printf("%s", ((VariableDeclaration *) ast)->datatype);
-            else
-                print_ast(0, ((VariableDeclaration *) ast)->anonymous_datatype);
-            printf(" ");
-            print_ast(0, ((VariableDeclaration *) ast)->details);
-            if (((VariableDeclaration *) ast)->semantic)
-                printf(" : %s", ((VariableDeclaration *) ast)->semantic);
-            if (((VariableDeclaration *) ast)->annotations)
-            {
-                printf(" ");
-                print_ast(0, ((VariableDeclaration *) ast)->annotations);
-            } // if
-            if (((VariableDeclaration *) ast)->initializer != NULL)
-            {
-                printf(" = ");
-                print_ast(0, ((VariableDeclaration *) ast)->initializer);
-            } // if
-            print_ast(0, ((VariableDeclaration *) ast)->lowlevel);
-
-            if (((VariableDeclaration *) ast)->next == NULL)
-                printf("%s", nl);
-            else
-            {
-                int attr = (((VariableDeclaration *) ast)->next)->attributes;
-                printf(", ");
-                (((VariableDeclaration *) ast)->next)->attributes = 0;
-                print_ast(1, ((VariableDeclaration *) ast)->next);
-                (((VariableDeclaration *) ast)->next)->attributes = attr;
-            } // if
-            break;
-
-        case AST_PACK_OFFSET:
-            printf(" : packoffset(%s%s%s)",
-                    ((PackOffset *) ast)->ident1,
-                    ((PackOffset *) ast)->ident2 ? "." : "",
-                    ((PackOffset *) ast)->ident2 ? ((PackOffset *) ast)->ident2 : "");
-            break;
-
-        case AST_VARIABLE_LOWLEVEL:
-            print_ast(0, ((VariableLowLevel *) ast)->packoffset);
-            if (((VariableLowLevel *) ast)->register_name)
-                printf(" : register(%s)", ((VariableLowLevel *) ast)->register_name);
-            break;
-
-        case AST_ANNOTATION:
-        {
-            const Annotations *a = (Annotations *) ast;
-            printf("<");
-            while (a)
-            {
-                printf(" %s ", a->datatype);
-                if (a->initializer != NULL)
-                {
-                    printf(" = ");
-                    print_ast(0, a->initializer);
-                } // if
-                if (a->next)
-                    printf(",");
-                a = a->next;
-            } // while
-            printf(" >");
-            break;
-        } // case
-
-        default:
-            assert(0 && "unexpected type");
-            break;
-    } // switch
-
-    #undef DO_INDENT
-} // print_ast
-
-
 /*
  * datatype strings...
  *
@@ -2472,8 +1323,10 @@
 // Returns final datatype used once implicit casting is complete.
 // The datatypes must be pointers from the string cache.
 static const char *add_type_coercion(Context *ctx,
-                                     Expression **left, const char *ldatatype,
-                                     Expression **right, const char *rdatatype)
+                                     MOJOSHADER_astExpression **left,
+                                     const char *ldatatype,
+                                     MOJOSHADER_astExpression **right,
+                                     const char *rdatatype)
 {
     // !!! FIXME: this whole function is probably naive at best.
 
@@ -2556,159 +1409,129 @@
 //  continue (but code generation will be skipped due to errors).
 // This means further processing can assume the AST is sane and not have to
 //  spend effort verifying it again.
-static const char *type_check_ast(Context *ctx, void *ast)
+static const char *type_check_ast(Context *ctx, void *_ast)
 {
+    MOJOSHADER_astNode *ast = (MOJOSHADER_astNode *) _ast;
+    const char *datatype;
+    const char *datatype2;
+    const char *datatype3;
+
     if (!ast)
         return NULL;
 
     // upkeep so we report correct error locations...
-    ctx->sourcefile = ((ASTGeneric *) ast)->ast.filename;
-    ctx->sourceline = ((ASTGeneric *) ast)->ast.line;
+    ctx->sourcefile = ast->ast.filename;
+    ctx->sourceline = ast->ast.line;
 
-    switch ( ((ASTGeneric *) ast)->ast.type )
+    switch (ast->ast.type)
     {
-        case AST_OP_POSTINCREMENT:
-        case AST_OP_POSTDECREMENT:
-        case AST_OP_PREINCREMENT:
-        case AST_OP_PREDECREMENT:
-        case AST_OP_COMPLEMENT:
-        case AST_OP_NEGATE:
-        {
-            ExpressionUnary *expr = (ExpressionUnary *) ast;
-            const char *datatype = type_check_ast(ctx, expr->operand);
+        case MOJOSHADER_AST_OP_POSTINCREMENT:
+        case MOJOSHADER_AST_OP_POSTDECREMENT:
+        case MOJOSHADER_AST_OP_PREINCREMENT:
+        case MOJOSHADER_AST_OP_PREDECREMENT:
+        case MOJOSHADER_AST_OP_COMPLEMENT:
+        case MOJOSHADER_AST_OP_NEGATE:
+            datatype = type_check_ast(ctx, ast->unary.operand);
             require_numeric_datatype(ctx, datatype);
             return datatype;
-        } // case
 
-        case AST_OP_NOT:
-        {
-            ExpressionUnary *expr = (ExpressionUnary *) ast;
-            const char *datatype = type_check_ast(ctx, expr->operand);
+        case MOJOSHADER_AST_OP_NOT:
+            datatype = type_check_ast(ctx, ast->unary.operand);
             require_boolean_datatype(ctx, datatype);
             return datatype;
-        } // case
 
-        case AST_OP_DEREF_ARRAY:
-        {
-            ExpressionBinary *expr = (ExpressionBinary *) ast;
-            const char *datatype = type_check_ast(ctx, expr->left);
-            const char *datatype2 = type_check_ast(ctx, expr->right);
+        case MOJOSHADER_AST_OP_DEREF_ARRAY:
+            datatype = type_check_ast(ctx, ast->binary.left);
+            datatype2 = type_check_ast(ctx, ast->binary.right);
             require_array_datatype(ctx, datatype);
             require_numeric_datatype(ctx, datatype2);
-            add_type_coercion(ctx, NULL, ctx->str_i, &expr->right, datatype2);
+            add_type_coercion(ctx, NULL, ctx->str_i, &ast->binary.right, datatype2);
             return array_element_datatype(ctx, datatype);
-        } // case
 
-        case AST_OP_DEREF_STRUCT:
-        {
-            ExpressionDerefStruct *expr = (ExpressionDerefStruct *) ast;
-            const char *datatype = type_check_ast(ctx, expr->identifier);
+        case MOJOSHADER_AST_OP_DEREF_STRUCT:
+            datatype = type_check_ast(ctx, ast->derefstruct.identifier);
             require_struct_datatype(ctx, datatype);
 // !!! FIXME: map member to datatype
 datatype = "!!! FIXME";
             return datatype;
-        } // case
 
-        case AST_OP_COMMA:
-        {
+        case MOJOSHADER_AST_OP_COMMA:
             // evaluate and throw away left, return right.
-            ExpressionBinary *expr = (ExpressionBinary *) ast;
-            type_check_ast(ctx, expr->left);
-            return type_check_ast(ctx, expr->right);
-        } // case
+            type_check_ast(ctx, ast->binary.left);
+            return type_check_ast(ctx, ast->binary.right);
 
-        case AST_OP_MULTIPLY:
-        case AST_OP_DIVIDE:
-        case AST_OP_MODULO:
-        case AST_OP_ADD:
-        case AST_OP_SUBTRACT:
-        case AST_OP_LSHIFT:
-        case AST_OP_RSHIFT:
-        {
-            ExpressionBinary *expr = (ExpressionBinary *) ast;
-            const char *datatype = type_check_ast(ctx, expr->left);
-            const char *datatype2 = type_check_ast(ctx, expr->right);
+        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:
+            datatype = type_check_ast(ctx, ast->binary.left);
+            datatype2 = type_check_ast(ctx, ast->binary.right);
             require_numeric_datatype(ctx, datatype);
             require_numeric_datatype(ctx, datatype2);
-            return add_type_coercion(ctx, &expr->left, datatype,
-                                     &expr->right, datatype2);
-        } // case
+            return add_type_coercion(ctx, &ast->binary.left, datatype,
+                                     &ast->binary.right, datatype2);
 
-        case AST_OP_LESSTHAN:
-        case AST_OP_GREATERTHAN:
-        case AST_OP_LESSTHANOREQUAL:
-        case AST_OP_GREATERTHANOREQUAL:
-        case AST_OP_NOTEQUAL:
-        case AST_OP_EQUAL:
-        {
-            ExpressionBinary *expr = (ExpressionBinary *) ast;
-            const char *datatype = type_check_ast(ctx, expr->left);
-            const char *datatype2 = type_check_ast(ctx, expr->right);
-            add_type_coercion(ctx, &expr->left, datatype,
-                              &expr->right, datatype2);
+        case MOJOSHADER_AST_OP_LESSTHAN:
+        case MOJOSHADER_AST_OP_GREATERTHAN:
+        case MOJOSHADER_AST_OP_LESSTHANOREQUAL:
+        case MOJOSHADER_AST_OP_GREATERTHANOREQUAL:
+        case MOJOSHADER_AST_OP_NOTEQUAL:
+        case MOJOSHADER_AST_OP_EQUAL:
+            datatype = type_check_ast(ctx, ast->binary.left);
+            datatype2 = type_check_ast(ctx, ast->binary.right);
+            add_type_coercion(ctx, &ast->binary.left, datatype,
+                              &ast->binary.right, datatype2);
             return ctx->str_b;
-        } // case
 
-        case AST_OP_BINARYAND:
-        case AST_OP_BINARYXOR:
-        case AST_OP_BINARYOR:
-        {
-            ExpressionBinary *expr = (ExpressionBinary *) ast;
-            const char *datatype = type_check_ast(ctx, expr->left);
-            const char *datatype2 = type_check_ast(ctx, expr->right);
+        case MOJOSHADER_AST_OP_BINARYAND:
+        case MOJOSHADER_AST_OP_BINARYXOR:
+        case MOJOSHADER_AST_OP_BINARYOR:
+            datatype = type_check_ast(ctx, ast->binary.left);
+            datatype2 = type_check_ast(ctx, ast->binary.right);
             require_integer_datatype(ctx, datatype);
             require_integer_datatype(ctx, datatype2);
-            return add_type_coercion(ctx, &expr->left, datatype,
-                                     &expr->right, datatype2);
-        } // case
+            return add_type_coercion(ctx, &ast->binary.left, datatype,
+                                     &ast->binary.right, datatype2);
 
-        case AST_OP_LOGICALAND:
-        case AST_OP_LOGICALOR:
-        {
-            ExpressionBinary *expr = (ExpressionBinary *) ast;
-            const char *datatype = type_check_ast(ctx, expr->left);
-            const char *datatype2 = type_check_ast(ctx, expr->right);
+        case MOJOSHADER_AST_OP_LOGICALAND:
+        case MOJOSHADER_AST_OP_LOGICALOR:
+            datatype = type_check_ast(ctx, ast->binary.left);
+            datatype2 = type_check_ast(ctx, ast->binary.right);
             require_boolean_datatype(ctx, datatype);
             require_boolean_datatype(ctx, datatype2);
-            add_type_coercion(ctx, &expr->left, datatype,
-                              &expr->right, datatype2);
+            add_type_coercion(ctx, &ast->binary.left, datatype,
+                              &ast->binary.right, datatype2);
             return ctx->str_b;
-        } // case
 
-        case AST_OP_ASSIGN:
-        case AST_OP_MULASSIGN:
-        case AST_OP_DIVASSIGN:
-        case AST_OP_MODASSIGN:
-        case AST_OP_ADDASSIGN:
-        case AST_OP_SUBASSIGN:
-        case AST_OP_LSHIFTASSIGN:
-        case AST_OP_RSHIFTASSIGN:
-        case AST_OP_ANDASSIGN:
-        case AST_OP_XORASSIGN:
-        case AST_OP_ORASSIGN:
-        {
-            ExpressionBinary *expr = (ExpressionBinary *) ast;
-            const char *datatype = type_check_ast(ctx, expr->left);
-            const char *datatype2 = type_check_ast(ctx, expr->right);
-            add_type_coercion(ctx, NULL, datatype, &expr->right, datatype2);
+        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:
+            datatype = type_check_ast(ctx, ast->binary.left);
+            datatype2 = type_check_ast(ctx, ast->binary.right);
+            add_type_coercion(ctx, NULL, datatype, &ast->binary.right, datatype2);
             return datatype;
-        } // case
 
-        case AST_OP_CONDITIONAL:
-        {
-            ExpressionTernary *tern = (ExpressionTernary *) ast;
-            const char *datatype = type_check_ast(ctx, tern->left);
-            const char *datatype2 = type_check_ast(ctx, tern->center);
-            const char *datatype3 = type_check_ast(ctx, tern->right);
+        case MOJOSHADER_AST_OP_CONDITIONAL:
+            type_check_ast(ctx, ast->ternary.left);
+            type_check_ast(ctx, ast->ternary.center);
+            type_check_ast(ctx, ast->ternary.right);
             require_boolean_datatype(ctx, datatype);
-            return add_type_coercion(ctx, &tern->center, datatype2,
-                                     &tern->right, datatype3);
-        } // case
+            return add_type_coercion(ctx, &ast->ternary.center, datatype2,
+                                     &ast->ternary.right, datatype3);
 
-        case AST_OP_IDENTIFIER:
-        {
-            ExpressionIdentifier *expr = (ExpressionIdentifier *) ast;
-            const char *datatype = find_variable(ctx, expr->identifier);
+        case MOJOSHADER_AST_OP_IDENTIFIER:
+            datatype = find_variable(ctx, ast->identifier.identifier);
             if (datatype == NULL)
             {
                 fail(ctx, "Unknown identifier");
@@ -2716,107 +1539,82 @@
                 datatype = ctx->str_i;
             } // if
             return datatype;
-        } // case
 
-        case AST_OP_INT_LITERAL:
+        case MOJOSHADER_AST_OP_INT_LITERAL:
             return ctx->str_i;
 
-        case AST_OP_FLOAT_LITERAL:
+        case MOJOSHADER_AST_OP_FLOAT_LITERAL:
             return ctx->str_f;
 
-        case AST_OP_STRING_LITERAL:
+        case MOJOSHADER_AST_OP_STRING_LITERAL:
             return ctx->str_S;
 
-        case AST_OP_BOOLEAN_LITERAL:
+        case MOJOSHADER_AST_OP_BOOLEAN_LITERAL:
             return ctx->str_b;
 
-        case AST_ARGUMENTS:
-        {
-            Arguments *arguments = (Arguments *) ast;
-            const char *datatype = type_check_ast(ctx, arguments->argument);
-            if (arguments->next != NULL)
+        case MOJOSHADER_AST_ARGUMENTS:
+            datatype = type_check_ast(ctx, ast->arguments.argument);
+            if (ast->arguments.next != NULL)
             {
-                const char *datatype2 = type_check_ast(ctx, arguments->next);
+                datatype2 = type_check_ast(ctx, ast->arguments.next);
                 datatype = stringcache_fmt(ctx->strcache, "%s%s",
                                            datatype, datatype2);
             } // if
             return datatype;
-        } // case
 
-        case AST_OP_CALLFUNC:
-        {
-            ExpressionCallFunction *expr = (ExpressionCallFunction *) ast;
-            const char *datatype = type_check_ast(ctx, expr->identifier);
-            /*const char *datatype2 =*/ type_check_ast(ctx, expr->args);
-            const char *retval = require_function_datatype(ctx, datatype);
+        case MOJOSHADER_AST_OP_CALLFUNC:
+            datatype = type_check_ast(ctx, ast->callfunc.identifier);
+            datatype2 = type_check_ast(ctx, ast->callfunc.args);
+            return require_function_datatype(ctx, datatype);
 // !!! FIXME: test each arg against function datatype.
-            return retval;  // this is the datatype of the func's return value.
-        } // case
+            //return retval;  // this is the datatype of the func's return value.
 
-        case AST_OP_CONSTRUCTOR:
-        {
-            ExpressionConstructor *expr = (ExpressionConstructor *) ast;
+        case MOJOSHADER_AST_OP_CONSTRUCTOR:
 // !!! FIXME: test each arg against constructor datatype.
-            type_check_ast(ctx, expr->args);
-            return expr->datatype;
-        } // case
+            type_check_ast(ctx, ast->constructor.args);
+            return ast->constructor.datatype;
 
-        case AST_OP_CAST:
-        {
-            ExpressionCast *expr = (ExpressionCast *) ast;
-            const char *datatype = expr->datatype;
-            const char *datatype2 = type_check_ast(ctx, expr->operand);
+        case MOJOSHADER_AST_OP_CAST:
+            datatype = ast->cast.datatype;
+            datatype2 = type_check_ast(ctx, ast->cast.operand);
             // you still need type coercion, since you could do a wrong cast,
             //  like "int x = (short) mychar;"
-            add_type_coercion(ctx, NULL, datatype, &expr->operand, datatype2);
+            add_type_coercion(ctx, NULL, datatype, &ast->cast.operand, datatype2);
             return datatype;
-        } // case
 
-        case AST_STATEMENT_BREAK:
-        case AST_STATEMENT_CONTINUE:
-        case AST_STATEMENT_DISCARD:
-        case AST_STATEMENT_EMPTY:
-        {
-            type_check_ast(ctx, ((Statement *) ast)->next);
+        case MOJOSHADER_AST_STATEMENT_BREAK:
+        case MOJOSHADER_AST_STATEMENT_CONTINUE:
+        case MOJOSHADER_AST_STATEMENT_DISCARD:
+        case MOJOSHADER_AST_STATEMENT_EMPTY:
+            type_check_ast(ctx, ast->stmt.next);
             return NULL;
-        } // case
 
-        case AST_STATEMENT_EXPRESSION:
-        {
-            ExpressionStatement *stmt = (ExpressionStatement *) ast;
+        case MOJOSHADER_AST_STATEMENT_EXPRESSION:
             // !!! FIXME: warn about expressions without a side-effect here?
-            type_check_ast(ctx, stmt->expr);  // !!! FIXME: This is named badly...
-            type_check_ast(ctx, stmt->next);
+            type_check_ast(ctx, ast->exprstmt.expr);  // !!! FIXME: This is named badly...
+            type_check_ast(ctx, ast->exprstmt.next);
             return NULL;
-        } // case
 
-        case AST_STATEMENT_IF:
-        {
-            IfStatement *stmt = (IfStatement *) ast;
+        case MOJOSHADER_AST_STATEMENT_IF:
             push_scope(ctx);  // new scope for "if ((int x = blah()) != 0)"
-            type_check_ast(ctx, stmt->expr);
-            type_check_ast(ctx, stmt->statement);
+            type_check_ast(ctx, ast->ifstmt.expr);
+            type_check_ast(ctx, ast->ifstmt.statement);
             pop_scope(ctx);
-            type_check_ast(ctx, stmt->next);
+            type_check_ast(ctx, ast->ifstmt.next);
             return NULL;
-        } // case
 
-        case AST_STATEMENT_TYPEDEF:
-        {
-            TypedefStatement *stmt = (TypedefStatement *) ast;
-            type_check_ast(ctx, stmt->type_info);
-            type_check_ast(ctx, stmt->next);
+        case MOJOSHADER_AST_STATEMENT_TYPEDEF:
+            type_check_ast(ctx, ast->typedefstmt.type_info);
+            type_check_ast(ctx, ast->typedefstmt.next);
             return NULL;
-        } // case
 
-        case AST_STATEMENT_SWITCH:
+        case MOJOSHADER_AST_STATEMENT_SWITCH:
         {
-            SwitchStatement *stmt = (SwitchStatement *) ast;
-            SwitchCases *cases = stmt->cases;
-            const char *datatype = type_check_ast(ctx, stmt->expr);
+            MOJOSHADER_astSwitchCases *cases = ast->switchstmt.cases;
+            datatype = type_check_ast(ctx, ast->switchstmt.expr);
             while (cases)
             {
-                const char *datatype2 = type_check_ast(ctx, cases->expr);
+                datatype2 = type_check_ast(ctx, cases->expr);
                 add_type_coercion(ctx, NULL, datatype,
                                   &cases->expr, datatype2);
                 type_check_ast(ctx, cases->statement);
@@ -2825,161 +1623,122 @@
             return NULL;
         } // case
 
-        case AST_SWITCH_CASE:
-        {
-            assert(0 && "Should have been handled by AST_STATEMENT_SWITCH.");
+        case MOJOSHADER_AST_SWITCH_CASE:
+            assert(0 && "Should be done by MOJOSHADER_AST_STATEMENT_SWITCH.");
             return NULL;
-        } // case
 
-        case AST_STATEMENT_STRUCT:
-        {
-            StructStatement *stmt = (StructStatement *) ast;
-            type_check_ast(ctx, stmt->struct_info);
-            type_check_ast(ctx, stmt->next);
+        case MOJOSHADER_AST_STATEMENT_STRUCT:
+            type_check_ast(ctx, ast->structstmt.struct_info);
+            type_check_ast(ctx, ast->structstmt.next);
             return NULL;
-        } // case
 
-        case AST_STATEMENT_VARDECL:
-        {
-            VarDeclStatement *stmt = (VarDeclStatement *) ast;
-            type_check_ast(ctx, stmt->declaration);
-            type_check_ast(ctx, stmt->next);
+        case MOJOSHADER_AST_STATEMENT_VARDECL:
+            type_check_ast(ctx, ast->vardeclstmt.declaration);
+            type_check_ast(ctx, ast->vardeclstmt.next);
             return NULL;
-        } // case
 
-        case AST_STATEMENT_BLOCK:
-        {
-            BlockStatement *bs = (BlockStatement *) ast;
+        case MOJOSHADER_AST_STATEMENT_BLOCK:
             push_scope(ctx);  // new vars declared here live until '}'.
-            type_check_ast(ctx, bs->statements);
+            type_check_ast(ctx, ast->blockstmt.statements);
             pop_scope(ctx);
-            type_check_ast(ctx, bs->next);
+            type_check_ast(ctx, ast->blockstmt.next);
             return NULL;
-        } // case
 
-        case AST_STATEMENT_FOR:
-        {
-            ForStatement *fs = (ForStatement *) ast;
+        case MOJOSHADER_AST_STATEMENT_FOR:
             push_scope(ctx);  // new scope for "for (int x = 0; ...)"
-            type_check_ast(ctx, fs->var_decl);
-            type_check_ast(ctx, fs->initializer);
-            type_check_ast(ctx, fs->looptest);
-            type_check_ast(ctx, fs->counter);
-            type_check_ast(ctx, fs->statement);
+            type_check_ast(ctx, ast->forstmt.var_decl);
+            type_check_ast(ctx, ast->forstmt.initializer);
+            type_check_ast(ctx, ast->forstmt.looptest);
+            type_check_ast(ctx, ast->forstmt.counter);
+            type_check_ast(ctx, ast->forstmt.statement);
             pop_scope(ctx);
-            type_check_ast(ctx, fs->next);
+            type_check_ast(ctx, ast->forstmt.next);
             return NULL;
-        } // case
-
-        case AST_STATEMENT_DO:
-        {
-            DoStatement *ds = (DoStatement *) ast;
-            type_check_ast(ctx, ds->statement);
-            push_scope(ctx);  // new scope for "while ((int x = blah()) != 0)"
-            type_check_ast(ctx, ds->expr);
-            pop_scope(ctx);
-            type_check_ast(ctx, ds->next);
-            return NULL;
-        } // case
 
-        case AST_STATEMENT_WHILE:
-        {
-            WhileStatement *ws = (WhileStatement *) ast;
+        case MOJOSHADER_AST_STATEMENT_DO:
+            type_check_ast(ctx, ast->dostmt.statement);
             push_scope(ctx);  // new scope for "while ((int x = blah()) != 0)"
-            type_check_ast(ctx, ws->expr);
-            type_check_ast(ctx, ws->statement);
+            type_check_ast(ctx, ast->dostmt.expr);
             pop_scope(ctx);
-            type_check_ast(ctx, ws->next);
+            type_check_ast(ctx, ast->dostmt.next);
             return NULL;
-        } // case
 
-        case AST_STATEMENT_RETURN:
-        {
-            ReturnStatement *stmt = (ReturnStatement *) ast;
-            type_check_ast(ctx, stmt->expr);
-            type_check_ast(ctx, stmt->next);
+        case MOJOSHADER_AST_STATEMENT_WHILE:
+            push_scope(ctx);  // new scope for "while ((int x = blah()) != 0)"
+            type_check_ast(ctx, ast->whilestmt.expr);
+            type_check_ast(ctx, ast->whilestmt.statement);
+            pop_scope(ctx);
+            type_check_ast(ctx, ast->whilestmt.next);
             return NULL;
-        } // case
 
-        case AST_COMPUNIT_FUNCTION:
-        {
-            CompilationUnitFunction *unit = (CompilationUnitFunction *) ast;
-            const char *sig = get_usertype(ctx, unit->declaration->identifier);
-            if (sig == NULL)
+        case MOJOSHADER_AST_STATEMENT_RETURN:
+            type_check_ast(ctx, ast->returnstmt.expr);
+            type_check_ast(ctx, ast->returnstmt.next);
+
+        case MOJOSHADER_AST_COMPUNIT_FUNCTION:
+            datatype = get_usertype(ctx, ast->funcunit.declaration->identifier);
+            if (datatype == NULL)
             {
                 // add function declaration if we've not seen it.
-                sig = unit->declaration->datatype;
-                push_usertype(ctx, unit->declaration->identifier, sig);
+                datatype = ast->funcunit.declaration->datatype;
+                push_usertype(ctx, ast->funcunit.declaration->identifier, datatype);
             } // if
 
             // declarations can be done multiple times if they match.
-            else if (sig != unit->declaration->datatype)
+            else if (datatype != ast->funcunit.declaration->datatype)
             {
                 // !!! FIXME: function overloading is legal.
                 fail(ctx, "function sigs don't match");
             } // else
 
             push_scope(ctx);  // so function params are in function scope.
-            type_check_ast(ctx, unit->declaration);
-            if (unit->definition == NULL)
+            type_check_ast(ctx, ast->funcunit.declaration);
+            if (ast->funcunit.definition == NULL)
                 pop_scope(ctx);
             else
             {
-                type_check_ast(ctx, unit->definition);
+                type_check_ast(ctx, ast->funcunit.definition);
                 pop_scope(ctx);
-                push_variable(ctx, unit->declaration->identifier, sig);
+                push_variable(ctx, ast->funcunit.declaration->identifier, datatype);
             } // else
 
-            type_check_ast(ctx, unit->next);
-            return NULL;
-        } // case
-
-        case AST_COMPUNIT_TYPEDEF:
-        {
-            CompilationUnitTypedef *unit = (CompilationUnitTypedef *) ast;
-            type_check_ast(ctx, unit->type_info);
-            type_check_ast(ctx, unit->next);
+            type_check_ast(ctx, ast->funcunit.next);
             return NULL;
-        } // case
 
-        case AST_COMPUNIT_STRUCT:
-        {
-            CompilationUnitStruct *unit = (CompilationUnitStruct *) ast;
-            type_check_ast(ctx, unit->struct_info);
-            type_check_ast(ctx, unit->next);
+        case MOJOSHADER_AST_COMPUNIT_TYPEDEF:
+            type_check_ast(ctx, ast->typedefunit.type_info);
+            type_check_ast(ctx, ast->typedefunit.next);
             return NULL;
-        } // case
+
+        case MOJOSHADER_AST_COMPUNIT_STRUCT:
+            type_check_ast(ctx, ast->structunit.struct_info);
+            type_check_ast(ctx, ast->structunit.next);
+            return NULL;
 
-        case AST_COMPUNIT_VARIABLE:
-        {
-            CompilationUnitVariable *unit = (CompilationUnitVariable *) ast;
-            type_check_ast(ctx, unit->declaration);
-            type_check_ast(ctx, unit->next);
+        case MOJOSHADER_AST_COMPUNIT_VARIABLE:
+            type_check_ast(ctx, ast->varunit.declaration);
+            type_check_ast(ctx, ast->varunit.next);
             return NULL;
-        } // case
 
-        case AST_SCALAR_OR_ARRAY:
+        case MOJOSHADER_AST_SCALAR_OR_ARRAY:
+            datatype = type_check_ast(ctx, ast->soa.dimension);
+            require_integer_datatype(ctx, datatype);
+assert(0); // !!! FIXME: figure out datatype of identifier.
+            return NULL;
+
+        case MOJOSHADER_AST_TYPEDEF:
         {
-            ScalarOrArray *soa = (ScalarOrArray *) ast;
-            const char *datatype = type_check_ast(ctx, soa->dimension);
-            require_integer_datatype(ctx, datatype);
-            assert(0); // !!! FIXME: figure out datatype of identifier.
-            return NULL;
-        } // case
-
-        case AST_TYPEDEF:
-        {
-            ScalarOrArray *soa = ((Typedef *) ast)->details;
-            const char *datatype = get_usertype(ctx, soa->identifier);
+            MOJOSHADER_astScalarOrArray *soa = ast->typdef.details;
+            datatype = get_usertype(ctx, soa->identifier);
             if (datatype != NULL)
             {
                 fail(ctx, "typedef already defined");
                 return datatype;
             } // if
 
-            datatype = ((Typedef *) ast)->datatype;
+            datatype = ast->typdef.datatype;
 
-            // don't walk into AST_SCALAR_OR_ARRAY here, since it can't resolve the identifier.
+            // don't walk into MOJOSHADER_AST_SCALAR_OR_ARRAY here, since it can't resolve the identifier.
             // !!! FIXME: SCALAR_OR_ARRAY is sort of a mess.
             // !!! FIXME: this part is cut and paste.
             assert( (soa->isarray && soa->dimension) ||
@@ -2987,110 +1746,97 @@
 
             if (soa->isarray)
             {
-                if (soa->dimension->ast.type != AST_OP_INT_LITERAL)
+                if (soa->dimension->ast.type != MOJOSHADER_AST_OP_INT_LITERAL)
                 {
                     fail(ctx, "Expected integer");
                     delete_expr(ctx, soa->dimension);  // make sane.
                     soa->dimension = new_literal_int_expr(ctx, 1);
                 } // if
 
-                int64 dim = ((ExpressionIntLiteral *) soa->dimension)->value;
-                datatype = stringcache_fmt(ctx->strcache, "a{%lld,%s}",
-                                           (long long) dim, datatype);
+                const int dim = ((MOJOSHADER_astExpressionIntLiteral *) soa->dimension)->value;
+                datatype = stringcache_fmt(ctx->strcache, "a{%d,%s}",
+                                           dim, datatype);
             } // if
 
-            ((Typedef *) ast)->datatype = datatype;  // make sane.
+            ast->typdef.datatype = datatype;  // make sane.
             push_usertype(ctx, soa->identifier, datatype);
             return datatype;
         } // case
 
-        case AST_FUNCTION_PARAMS:
-        {
-            FunctionParameters *params = (FunctionParameters *) ast;
-            push_variable(ctx, params->identifier, params->datatype);
-            type_check_ast(ctx, params->initializer);
-            type_check_ast(ctx, params->next);
+        case MOJOSHADER_AST_FUNCTION_PARAMS:
+            push_variable(ctx, ast->params.identifier, ast->params.datatype);
+            type_check_ast(ctx, ast->params.initializer);
+            type_check_ast(ctx, ast->params.next);
             return NULL;
-        } // case
 
-        case AST_FUNCTION_SIGNATURE:
-        {
-            FunctionSignature *sig = (FunctionSignature *) ast;
-            type_check_ast(ctx, sig->params);
-            return sig->datatype;
-        } // case
+        case MOJOSHADER_AST_FUNCTION_SIGNATURE:
+            type_check_ast(ctx, ast->funcsig.params);
+            return ast->funcsig.datatype;
 
-        case AST_STRUCT_DECLARATION:
-        {
-            StructDeclaration *decl = (StructDeclaration *) ast;
-            const char *datatype = type_check_ast(ctx, decl->members);
+        case MOJOSHADER_AST_STRUCT_DECLARATION:
+            datatype = type_check_ast(ctx, ast->structdecl.members);
             datatype = stringcache_fmt(ctx->strcache, "X{%s}", datatype);
-            push_usertype(ctx, decl->name, datatype);
-            return stringcache_fmt(ctx->strcache, "U{%s}", decl->name);
-        } // case
+            push_usertype(ctx, ast->structdecl.name, datatype);
+            return stringcache_fmt(ctx->strcache, "U{%s}", ast->structdecl.name);
 
-        case AST_STRUCT_MEMBER:
-        {
-            StructMembers *members = (StructMembers *) ast;
-            const char *dtype = type_check_ast(ctx, members->details);
-            const char *dtype2 = type_check_ast(ctx, members->next);
-            if (dtype2)
-                return stringcache_fmt(ctx->strcache, "%s%s", dtype, dtype2);
-            return dtype;
-        } // case
+        case MOJOSHADER_AST_STRUCT_MEMBER:
+            datatype = type_check_ast(ctx, ast->structmembers.details);
+            datatype2 = type_check_ast(ctx, ast->structmembers.next);
+            if (datatype2)
+            {
+                return stringcache_fmt(ctx->strcache, "%s%s",
+                                       datatype, datatype2);
+            } // if
+            return datatype;
 
-        case AST_VARIABLE_DECLARATION:
-        {
-            VariableDeclaration *decl = (VariableDeclaration *) ast;
-            ScalarOrArray *soa = decl->details;
-            const char *datatype;
-            const char *datatype2;
-
+        case MOJOSHADER_AST_VARIABLE_DECLARATION:
             // this is true now, but we'll fill in ->datatype no matter what.
-            assert( (decl->datatype && !decl->anonymous_datatype) ||
-                    (!decl->datatype && decl->anonymous_datatype) );
+            assert((ast->vardecl.datatype && !ast->vardecl.anonymous_datatype) ||
+                   (!ast->vardecl.datatype && ast->vardecl.anonymous_datatype));
 
             // fix up if necessary.
-            if (decl->anonymous_datatype != NULL)
-                decl->datatype = type_check_ast(ctx, decl->anonymous_datatype);
-            datatype = decl->datatype;
+            if (ast->vardecl.anonymous_datatype != NULL)
+                ast->vardecl.datatype = type_check_ast(ctx, ast->vardecl.anonymous_datatype);
+            datatype = ast->vardecl.datatype;
 
-            // don't walk into AST_SCALAR_OR_ARRAY here, since it can't resolve the identifier.
+            // don't walk into MOJOSHADER_AST_SCALAR_OR_ARRAY here, since it can't resolve the identifier.
             // !!! FIXME: SCALAR_OR_ARRAY is sort of a mess.
             // !!! FIXME: this part is cut and paste.
-            assert( (soa->isarray && soa->dimension) ||
-                    (!soa->isarray && !soa->dimension) );
+            assert( (ast->vardecl.details->isarray &&
+                     ast->vardecl.details->dimension) ||
+                     (!ast->vardecl.details->isarray &&
+                      !ast->vardecl.details->dimension) );
 
-            if (soa->isarray)
+            if (ast->vardecl.details->isarray)
             {
-                if (soa->dimension->ast.type != AST_OP_INT_LITERAL)
+                MOJOSHADER_astScalarOrArray *soa = ast->vardecl.details;
+                if (soa->dimension->ast.type != MOJOSHADER_AST_OP_INT_LITERAL)
                 {
                     fail(ctx, "Expected integer");
                     delete_expr(ctx, soa->dimension);  // make sane.
                     soa->dimension = new_literal_int_expr(ctx, 1);
                 } // if
 
-                int64 dim = ((ExpressionIntLiteral *) soa->dimension)->value;
-                datatype = stringcache_fmt(ctx->strcache, "a{%lld,%s}",
-                                           (long long) dim, datatype);
+                const int dim = ((MOJOSHADER_astExpressionIntLiteral *) soa->dimension)->value;
+                datatype = stringcache_fmt(ctx->strcache, "a{%d,%s}",
+                                           dim, datatype);
             } // if
 
-            decl->datatype = datatype;  // make sane.
-            push_variable(ctx, soa->identifier, datatype);
-            datatype2 = type_check_ast(ctx, decl->initializer);
-            add_type_coercion(ctx, NULL, datatype, &decl->initializer, datatype2);
+            ast->vardecl.datatype = datatype;  // make sane.
+            push_variable(ctx, ast->vardecl.details->identifier, datatype);
+            datatype2 = type_check_ast(ctx, ast->vardecl.initializer);
+            add_type_coercion(ctx, NULL, datatype, &ast->vardecl.initializer, datatype2);
 
-            type_check_ast(ctx, decl->annotations);
-            type_check_ast(ctx, decl->lowlevel);
+            type_check_ast(ctx, ast->vardecl.annotations);
+            type_check_ast(ctx, ast->vardecl.lowlevel);
 
-            datatype2 = type_check_ast(ctx, decl->next);
+            datatype2 = type_check_ast(ctx, ast->vardecl.next);
             assert(datatype == datatype2);
             return datatype;
-        } // case
 
-        case AST_ANNOTATION:
+        case MOJOSHADER_AST_ANNOTATION:
         {
-            Annotations *anno = (Annotations *) ast;
+            MOJOSHADER_astAnnotations *anno = &ast->annotations;
             while (anno)
             {
                 type_check_ast(ctx, anno->initializer);
@@ -3099,8 +1845,8 @@
             return NULL;
         } // case
 
-        case AST_PACK_OFFSET:
-        case AST_VARIABLE_LOWLEVEL:
+        case MOJOSHADER_AST_PACK_OFFSET:
+        case MOJOSHADER_AST_VARIABLE_LOWLEVEL:
             return NULL;  // no-op (for now, at least).
 
         default:
@@ -3115,9 +1861,13 @@
 static inline void semantic_analysis(Context *ctx)
 {
     type_check_ast(ctx, ctx->ast);
+
     // !!! FIXME: build an IR here.
-    delete_compilation_unit(ctx, ctx->ast);  // done with the AST, nuke it.
+
+    // done with the AST, nuke it.
+    delete_compilation_unit(ctx, (MOJOSHADER_astCompilationUnit *) ctx->ast);
     ctx->ast = NULL;
+
     // !!! FIXME: do everything else.  :)
 } // semantic_analysis
 
@@ -3355,7 +2105,7 @@
         void *d = ctx->malloc_data;
 
         // !!! FIXME: free ctx->errors
-        delete_compilation_unit(ctx, ctx->ast);
+        delete_compilation_unit(ctx, (MOJOSHADER_astCompilationUnit*)ctx->ast);
         destroy_symbolmap(ctx, &ctx->usertypes);
         destroy_symbolmap(ctx, &ctx->variables);
 
@@ -3552,30 +2302,115 @@
 } // parse_source
 
 
-void MOJOSHADER_compile(const char *filename,
-                        const char *source, unsigned int sourcelen,
-                        const MOJOSHADER_preprocessorDefine *defines,
-                        unsigned int define_count,
-                        MOJOSHADER_includeOpen include_open,
-                        MOJOSHADER_includeClose include_close,
-                        MOJOSHADER_malloc m, MOJOSHADER_free f, void *d)
+#if 0
+/* !!! FIXME: most of these ints should be unsigned. */
+typedef struct MOJOSHADER_astData
+{
+    /*
+     * The number of elements pointed to by (errors).
+     */
+    int error_count;
+
+    /*
+     * (error_count) elements of data that specify errors that were generated
+     *  by parsing this shader.
+     * This can be NULL if there were no errors or if (error_count) is zero.
+     *  Note that this will only produce errors for syntax problems. Most of
+     *  the things we expect a compiler to produce errors for--incompatible
+     *  types, unknown identifiers, etc--are not checked at all during
+     *  initial generation of the syntax tree...bogus programs that would
+     *  fail to compile will pass here without error, if they are syntactically
+     *  correct!
+     */
+    MOJOSHADER_error *errors;
+
+    /*
+     * The name of the source profile used to parse the shader. Will be NULL
+     *  on error.
+     */
+    const char *source_profile;
+
+    /*
+     * The actual syntax tree. You are responsible for walking it yourself.
+     *  CompilationUnits are always the top of the tree (functions, typedefs,
+     *  global variables, etc).
+     */
+    const MOJOSHADER_astNode *ast;
+
+    /*
+     * This is the malloc implementation you passed to MOJOSHADER_parse().
+     */
+    MOJOSHADER_malloc malloc;
+
+    /*
+     * This is the free implementation you passed to MOJOSHADER_parse().
+     */
+    MOJOSHADER_free free;
+
+    /*
+     * This is the pointer you passed as opaque data for your allocator.
+     */
+    void *malloc_data;
+} MOJOSHADER_astData;
+#endif
+
+
+// !!! FIXME: move this (and a lot of other things) to mojoshader_ast.c.
+const MOJOSHADER_astData *MOJOSHADER_parseAst(const char *srcprofile,
+                                    const char *filename, const char *source,
+                                    unsigned int sourcelen,
+                                    const MOJOSHADER_preprocessorDefine *defs,
+                                    unsigned int define_count,
+                                    MOJOSHADER_includeOpen include_open,
+                                    MOJOSHADER_includeClose include_close,
+                                    MOJOSHADER_malloc m, MOJOSHADER_free f,
+                                    void *d)
 {
     Context *ctx = build_context(m, f, d);
     if (!ctx)
-        return;  // !!! FIXME: report error.
+        return NULL;  // !!! FIXME: report error.
+
+    parse_source(ctx, filename, source, sourcelen, defs, define_count,
+                 include_open, include_close);
+
+    destroy_context(ctx);
+
+    // !!! FIXME: report success/error.
+    return NULL;
+} // MOJOSHADER_ast
+
+
+void MOJOSHADER_freeAstData(const MOJOSHADER_astData *data)
+{
+} // MOJOSHADER_freeAstData
+
 
-    parse_source(ctx, filename, source, sourcelen, defines, define_count,
+
+const MOJOSHADER_compileData *MOJOSHADER_compile(const char *srcprofile,
+                                    const char *filename, const char *source,
+                                    unsigned int sourcelen,
+                                    const MOJOSHADER_preprocessorDefine *defs,
+                                    unsigned int define_count,
+                                    MOJOSHADER_includeOpen include_open,
+                                    MOJOSHADER_includeClose include_close,
+                                    MOJOSHADER_malloc m, MOJOSHADER_free f,
+                                    void *d)
+{
+    Context *ctx = build_context(m, f, d);
+    if (!ctx)
+        return NULL;  // !!! FIXME: report error.
+
+    parse_source(ctx, filename, source, sourcelen, defs, define_count,
                  include_open, include_close);
 
     // !!! FIXME: check (ctx->ast != NULL), and maybe isfail().
 
-    print_ast(0, ctx->ast);
-
     semantic_analysis(ctx);
 
     destroy_context(ctx);
 
     // !!! FIXME: report success/error.
+    return NULL;
 } // MOJOSHADER_compile
 
 // end of mojoshader_compiler.c ...
--- a/mojoshader_parser_hlsl.lemon	Tue Oct 26 17:27:31 2010 -0400
+++ b/mojoshader_parser_hlsl.lemon	Thu Oct 28 03:42:12 2010 -0400
@@ -75,14 +75,14 @@
 
 // The rules...
 
-shader ::= compilation_units(B). { assert(ctx->ast == NULL); REVERSE_LINKED_LIST(CompilationUnit, B); ctx->ast = B; }
+shader ::= compilation_units(B). { assert(ctx->ast == NULL); REVERSE_LINKED_LIST(MOJOSHADER_astCompilationUnit, B); ctx->ast = (MOJOSHADER_astNode *) B; }
 
-%type compilation_units { CompilationUnit * }
+%type compilation_units { MOJOSHADER_astCompilationUnit * }
 %destructor compilation_units { delete_compilation_unit(ctx, $$); }
 compilation_units(A) ::= compilation_unit(B). { A = B; }
 compilation_units(A) ::= compilation_units(B) compilation_unit(C). { if (C) { C->next = B; A = C; } }
 
-%type compilation_unit { CompilationUnit * }
+%type compilation_unit { MOJOSHADER_astCompilationUnit * }
 %destructor compilation_unit { delete_compilation_unit(ctx, $$); }
 //compilation_unit(A) ::= PRAGMA . { A = NULL; }   // !!! FIXME: deal with pragmas.
 compilation_unit(A) ::= variable_declaration(B). { A = new_global_variable(ctx, B); }
@@ -92,20 +92,20 @@
 compilation_unit(A) ::= struct_declaration(B) SEMICOLON. { A = new_global_struct(ctx, B); }
 //compilation_unit(A) ::= error SEMICOLON. { A = NULL; }  // !!! FIXME: research using the error nonterminal
 
-%type typedef { Typedef * }
+%type typedef { MOJOSHADER_astTypedef * }
 %destructor typedef { delete_typedef(ctx, $$); }
 // !!! FIXME: should CONST be here, or in datatype?
 typedef(A) ::= TYPEDEF CONST datatype(B) scalar_or_array(C). { A = new_typedef(ctx, 1, B, C); push_usertype(ctx, C->identifier, NULL); }
 typedef(A) ::= TYPEDEF datatype(B) scalar_or_array(C). { A = new_typedef(ctx, 0, B, C); push_usertype(ctx, C->identifier, NULL); }
 
-%type function_signature { FunctionSignature * }
+%type function_signature { MOJOSHADER_astFunctionSignature * }
 %destructor function_signature { delete_function_signature(ctx, $$); }
 function_signature(A) ::= function_storageclass(B) function_details(C) semantic(D). { A = C; A->storage_class = B; A->semantic = D; }
 function_signature(A) ::= function_storageclass(B) function_details(C). { A = C; A->storage_class = B; }
 function_signature(A) ::= function_details(B) semantic(C). { A = B; A->semantic = C; }
 function_signature(A) ::= function_details(B). { A = B; }
 
-%type function_details { FunctionSignature * }
+%type function_details { MOJOSHADER_astFunctionSignature * }
 %destructor function_details { delete_function_signature(ctx, $$); }
 function_details(A) ::= datatype(B) IDENTIFIER(C) LPAREN function_parameters(D) RPAREN. { A = new_function_signature(ctx, B, C.string, D); }
 function_details(A) ::= VOID IDENTIFIER(B) LPAREN function_parameters(C) RPAREN. { A = new_function_signature(ctx, NULL, B.string, C); }
@@ -116,87 +116,87 @@
 
 // !!! FIXME: Also, the docs say "one of" inline or target, but I bet you can
 // !!! FIXME:  specify both.
-%type function_storageclass { FunctionStorageClass }
+%type function_storageclass { MOJOSHADER_astFunctionStorageClass }
 //function_storageclass(A) ::= target(B). { A = B; }
-function_storageclass(A) ::= INLINE. { A = FNSTORECLS_INLINE; }
+function_storageclass(A) ::= INLINE. { A = MOJOSHADER_AST_FNSTORECLS_INLINE; }
 
-%type function_parameters { FunctionParameters * }
+%type function_parameters { MOJOSHADER_astFunctionParameters * }
 %destructor function_parameters { delete_function_params(ctx, $$); }
 function_parameters(A) ::= VOID. { A = NULL; }
-function_parameters(A) ::= function_parameter_list(B). { REVERSE_LINKED_LIST(FunctionParameters, B); A = B; }
+function_parameters(A) ::= function_parameter_list(B). { REVERSE_LINKED_LIST(MOJOSHADER_astFunctionParameters, B); A = B; }
 function_parameters(A) ::= . { A = NULL; }
 
-%type function_parameter_list { FunctionParameters * }
+%type function_parameter_list { MOJOSHADER_astFunctionParameters * }
 %destructor function_parameter_list { delete_function_params(ctx, $$); }
 function_parameter_list(A) ::= function_parameter(B). { A = B; }
 function_parameter_list(A) ::= function_parameter_list(B) COMMA function_parameter(C). { C->next = B; A = C; }
 
 // !!! FIXME: this is pretty unreadable.
-%type function_parameter { FunctionParameters * }
+%type function_parameter { MOJOSHADER_astFunctionParameters * }
 %destructor function_parameter { delete_function_params(ctx, $$); }
 function_parameter(A) ::= input_modifier(B) datatype(C) IDENTIFIER(D) semantic(E) interpolation_mod(F) initializer(G). { A = new_function_param(ctx, B, C, D.string, E, F, G); }
 function_parameter(A) ::= input_modifier(B) datatype(C) IDENTIFIER(D) semantic(E) interpolation_mod(F). { A = new_function_param(ctx, B, C, D.string, E, F, NULL); }
-function_parameter(A) ::= input_modifier(B) datatype(C) IDENTIFIER(D) semantic(E) initializer(F). { A = new_function_param(ctx, B, C, D.string, E, INTERPMOD_NONE, F); }
-function_parameter(A) ::= input_modifier(B) datatype(C) IDENTIFIER(D) semantic(E). { A = new_function_param(ctx, B, C, D.string, E, INTERPMOD_NONE, NULL); }
+function_parameter(A) ::= input_modifier(B) datatype(C) IDENTIFIER(D) semantic(E) initializer(F). { A = new_function_param(ctx, B, C, D.string, E, MOJOSHADER_AST_INTERPMOD_NONE, F); }
+function_parameter(A) ::= input_modifier(B) datatype(C) IDENTIFIER(D) semantic(E). { A = new_function_param(ctx, B, C, D.string, E, MOJOSHADER_AST_INTERPMOD_NONE, NULL); }
 function_parameter(A) ::= input_modifier(B) datatype(C) IDENTIFIER(D) interpolation_mod(E) initializer(F). { A = new_function_param(ctx, B, C, D.string, NULL, E, F); }
 function_parameter(A) ::= input_modifier(B) datatype(C) IDENTIFIER(D) interpolation_mod(E). { A = new_function_param(ctx, B, C, D.string, NULL, E, NULL); }
-function_parameter(A) ::= input_modifier(B) datatype(C) IDENTIFIER(D) initializer(E). { A = new_function_param(ctx, B, C, D.string, NULL, INTERPMOD_NONE, E); }
-function_parameter(A) ::= input_modifier(B) datatype(C) IDENTIFIER(D). { A = new_function_param(ctx, B, C, D.string, NULL, INTERPMOD_NONE, NULL); }
-function_parameter(A) ::= datatype(B) IDENTIFIER(C) semantic(D) interpolation_mod(E) initializer(F). { A = new_function_param(ctx, INPUTMOD_NONE, B, C.string, D, E, F); }
-function_parameter(A) ::= datatype(B) IDENTIFIER(C) semantic(D) interpolation_mod(E). { A = new_function_param(ctx, INPUTMOD_NONE, B, C.string, D, E, NULL); }
-function_parameter(A) ::= datatype(B) IDENTIFIER(C) semantic(D) initializer(E). { A = new_function_param(ctx, INPUTMOD_NONE, B, C.string, D, INTERPMOD_NONE, E); }
-function_parameter(A) ::= datatype(B) IDENTIFIER(C) semantic(D). { A = new_function_param(ctx, INPUTMOD_NONE, B, C.string, D, INTERPMOD_NONE, NULL); }
-function_parameter(A) ::= datatype(B) IDENTIFIER(C) interpolation_mod(D) initializer(E). { A = new_function_param(ctx, INPUTMOD_NONE, B, C.string, NULL, D, E); }
-function_parameter(A) ::= datatype(B) IDENTIFIER(C) interpolation_mod(D). { A = new_function_param(ctx, INPUTMOD_NONE, B, C.string, NULL, D, NULL); }
-function_parameter(A) ::= datatype(B) IDENTIFIER(C) initializer(D). { A = new_function_param(ctx, INPUTMOD_NONE, B, C.string, NULL, INTERPMOD_NONE, D); }
-function_parameter(A) ::= datatype(B) IDENTIFIER(C). { A = new_function_param(ctx, INPUTMOD_NONE, B, C.string, NULL, INTERPMOD_NONE, NULL); }
+function_parameter(A) ::= input_modifier(B) datatype(C) IDENTIFIER(D) initializer(E). { A = new_function_param(ctx, B, C, D.string, NULL, MOJOSHADER_AST_INTERPMOD_NONE, E); }
+function_parameter(A) ::= input_modifier(B) datatype(C) IDENTIFIER(D). { A = new_function_param(ctx, B, C, D.string, NULL, MOJOSHADER_AST_INTERPMOD_NONE, NULL); }
+function_parameter(A) ::= datatype(B) IDENTIFIER(C) semantic(D) interpolation_mod(E) initializer(F). { A = new_function_param(ctx, MOJOSHADER_AST_INPUTMOD_NONE, B, C.string, D, E, F); }
+function_parameter(A) ::= datatype(B) IDENTIFIER(C) semantic(D) interpolation_mod(E). { A = new_function_param(ctx, MOJOSHADER_AST_INPUTMOD_NONE, B, C.string, D, E, NULL); }
+function_parameter(A) ::= datatype(B) IDENTIFIER(C) semantic(D) initializer(E). { A = new_function_param(ctx, MOJOSHADER_AST_INPUTMOD_NONE, B, C.string, D, MOJOSHADER_AST_INTERPMOD_NONE, E); }
+function_parameter(A) ::= datatype(B) IDENTIFIER(C) semantic(D). { A = new_function_param(ctx, MOJOSHADER_AST_INPUTMOD_NONE, B, C.string, D, MOJOSHADER_AST_INTERPMOD_NONE, NULL); }
+function_parameter(A) ::= datatype(B) IDENTIFIER(C) interpolation_mod(D) initializer(E). { A = new_function_param(ctx, MOJOSHADER_AST_INPUTMOD_NONE, B, C.string, NULL, D, E); }
+function_parameter(A) ::= datatype(B) IDENTIFIER(C) interpolation_mod(D). { A = new_function_param(ctx, MOJOSHADER_AST_INPUTMOD_NONE, B, C.string, NULL, D, NULL); }
+function_parameter(A) ::= datatype(B) IDENTIFIER(C) initializer(D). { A = new_function_param(ctx, MOJOSHADER_AST_INPUTMOD_NONE, B, C.string, NULL, MOJOSHADER_AST_INTERPMOD_NONE, D); }
+function_parameter(A) ::= datatype(B) IDENTIFIER(C). { A = new_function_param(ctx, MOJOSHADER_AST_INPUTMOD_NONE, B, C.string, NULL, MOJOSHADER_AST_INTERPMOD_NONE, NULL); }
 
-%type input_modifier { InputModifier }
-input_modifier(A) ::= IN. { A = INPUTMOD_IN; }
-input_modifier(A) ::= INOUT. { A = INPUTMOD_INOUT; }
-input_modifier(A) ::= OUT. { A = INPUTMOD_OUT; }
-input_modifier(A) ::= IN OUT. { A = INPUTMOD_INOUT; }
-input_modifier(A) ::= OUT IN. { A = INPUTMOD_INOUT; }
-input_modifier(A) ::= UNIFORM. { A = INPUTMOD_UNIFORM; }
+%type input_modifier { MOJOSHADER_astInputModifier }
+input_modifier(A) ::= IN. { A = MOJOSHADER_AST_INPUTMOD_IN; }
+input_modifier(A) ::= INOUT. { A = MOJOSHADER_AST_INPUTMOD_INOUT; }
+input_modifier(A) ::= OUT. { A = MOJOSHADER_AST_INPUTMOD_OUT; }
+input_modifier(A) ::= IN OUT. { A = MOJOSHADER_AST_INPUTMOD_INOUT; }
+input_modifier(A) ::= OUT IN. { A = MOJOSHADER_AST_INPUTMOD_INOUT; }
+input_modifier(A) ::= UNIFORM. { A = MOJOSHADER_AST_INPUTMOD_UNIFORM; }
 
 %type semantic { const char * }
 semantic(A) ::= COLON IDENTIFIER(B). { A = B.string; }
 
 // DX10 only?
-%type interpolation_mod { InterpolationModifier }
-interpolation_mod(A) ::= LINEAR. { A = INTERPMOD_LINEAR; }
-interpolation_mod(A) ::= CENTROID. { A = INTERPMOD_CENTROID; }
-interpolation_mod(A) ::= NOINTERPOLATION. { A = INTERPMOD_NOINTERPOLATION; }
-interpolation_mod(A) ::= NOPERSPECTIVE. { A = INTERPMOD_NOPERSPECTIVE; }
-interpolation_mod(A) ::= SAMPLE. { A = INTERPMOD_SAMPLE; }
+%type interpolation_mod { MOJOSHADER_astInterpolationModifier }
+interpolation_mod(A) ::= LINEAR. { A = MOJOSHADER_AST_INTERPMOD_LINEAR; }
+interpolation_mod(A) ::= CENTROID. { A = MOJOSHADER_AST_INTERPMOD_CENTROID; }
+interpolation_mod(A) ::= NOINTERPOLATION. { A = MOJOSHADER_AST_INTERPMOD_NOINTERPOLATION; }
+interpolation_mod(A) ::= NOPERSPECTIVE. { A = MOJOSHADER_AST_INTERPMOD_NOPERSPECTIVE; }
+interpolation_mod(A) ::= SAMPLE. { A = MOJOSHADER_AST_INTERPMOD_SAMPLE; }
 
-%type variable_declaration { VariableDeclaration * }
+%type variable_declaration { MOJOSHADER_astVariableDeclaration * }
 %destructor variable_declaration { delete_variable_declaration(ctx, $$); }
-variable_declaration(A) ::= variable_attribute_list(B) datatype(C) variable_declaration_details_list(D) SEMICOLON. { REVERSE_LINKED_LIST(VariableDeclaration, D); A = D; A->attributes = B; A->datatype = C; }
-variable_declaration(A) ::= datatype(B) variable_declaration_details_list(C) SEMICOLON. { REVERSE_LINKED_LIST(VariableDeclaration, C); A = C; A->datatype = B; }
-variable_declaration(A) ::= struct_declaration(B) variable_declaration_details_list(C) SEMICOLON. { REVERSE_LINKED_LIST(VariableDeclaration, C); A = C; A->anonymous_datatype = B; }
+variable_declaration(A) ::= variable_attribute_list(B) datatype(C) variable_declaration_details_list(D) SEMICOLON. { REVERSE_LINKED_LIST(MOJOSHADER_astVariableDeclaration, D); A = D; A->attributes = B; A->datatype = C; }
+variable_declaration(A) ::= datatype(B) variable_declaration_details_list(C) SEMICOLON. { REVERSE_LINKED_LIST(MOJOSHADER_astVariableDeclaration, C); A = C; A->datatype = B; }
+variable_declaration(A) ::= struct_declaration(B) variable_declaration_details_list(C) SEMICOLON. { REVERSE_LINKED_LIST(MOJOSHADER_astVariableDeclaration, C); A = C; A->anonymous_datatype = B; }
 
 %type variable_attribute_list { int }
 variable_attribute_list(A) ::= variable_attribute(B). { A = B; }
 variable_attribute_list(A) ::= variable_attribute_list(B) variable_attribute(C). { A = B | C; }
 
 %type variable_attribute { int }
-variable_attribute(A) ::= EXTERN. { A = VARATTR_EXTERN; }
-variable_attribute(A) ::= NOINTERPOLATION. { A = VARATTR_NOINTERPOLATION; }
-variable_attribute(A) ::= SHARED. { A = VARATTR_SHARED; }
-variable_attribute(A) ::= STATIC. { A = VARATTR_STATIC; }
-variable_attribute(A) ::= UNIFORM. { A = VARATTR_UNIFORM; }
-variable_attribute(A) ::= VOLATILE. { A = VARATTR_VOLATILE; }
-variable_attribute(A) ::= CONST. { A = VARATTR_CONST; }
-variable_attribute(A) ::= ROWMAJOR. { A = VARATTR_ROWMAJOR; }
-variable_attribute(A) ::= COLUMNMAJOR. { A = VARATTR_COLUMNMAJOR; }
+variable_attribute(A) ::= EXTERN. { A = MOJOSHADER_AST_VARATTR_EXTERN; }
+variable_attribute(A) ::= NOINTERPOLATION. { A = MOJOSHADER_AST_VARATTR_NOINTERPOLATION; }
+variable_attribute(A) ::= SHARED. { A = MOJOSHADER_AST_VARATTR_SHARED; }
+variable_attribute(A) ::= STATIC. { A = MOJOSHADER_AST_VARATTR_STATIC; }
+variable_attribute(A) ::= UNIFORM. { A = MOJOSHADER_AST_VARATTR_UNIFORM; }
+variable_attribute(A) ::= VOLATILE. { A = MOJOSHADER_AST_VARATTR_VOLATILE; }
+variable_attribute(A) ::= CONST. { A = MOJOSHADER_AST_VARATTR_CONST; }
+variable_attribute(A) ::= ROWMAJOR. { A = MOJOSHADER_AST_VARATTR_ROWMAJOR; }
+variable_attribute(A) ::= COLUMNMAJOR. { A = MOJOSHADER_AST_VARATTR_COLUMNMAJOR; }
 
-%type variable_declaration_details_list { VariableDeclaration * }
+%type variable_declaration_details_list { MOJOSHADER_astVariableDeclaration * }
 %destructor variable_declaration_details_list { delete_variable_declaration(ctx, $$); }
 variable_declaration_details_list(A) ::= variable_declaration_details(B). { A = B; }
 variable_declaration_details_list(A) ::= variable_declaration_details_list(B) COMMA variable_declaration_details(C). { A = C; A->next = B; }
 
-%type variable_declaration_details { VariableDeclaration * }
+%type variable_declaration_details { MOJOSHADER_astVariableDeclaration * }
 %destructor variable_declaration_details { delete_variable_declaration(ctx, $$); }
 variable_declaration_details(A) ::= scalar_or_array(B) semantic(C) annotations(D) initializer(E) variable_lowlevel(F). { A = new_variable_declaration(ctx, B, C, D, E, F); }
 variable_declaration_details(A) ::= scalar_or_array(B) semantic(C) annotations(D) initializer(E). { A = new_variable_declaration(ctx, B, C, D, E, NULL); }
@@ -218,35 +218,35 @@
 // !!! FIXME: we don't handle full sampler declarations at the moment.
 
 
-%type struct_declaration { StructDeclaration * }
+%type struct_declaration { MOJOSHADER_astStructDeclaration * }
 %destructor struct_declaration { delete_struct_declaration(ctx, $$); }
-struct_declaration(A) ::= struct_intro(B) LBRACE struct_member_list(C) RBRACE. { REVERSE_LINKED_LIST(StructMembers, C); A = new_struct_declaration(ctx, B, C); }
+struct_declaration(A) ::= struct_intro(B) LBRACE struct_member_list(C) RBRACE. { REVERSE_LINKED_LIST(MOJOSHADER_astStructMembers, C); A = new_struct_declaration(ctx, B, C); }
 
 // This has to be separate from struct_declaration so that the struct is in the usertypemap when parsing its members.
 %type struct_intro { const char * }
 struct_intro(A) ::= STRUCT IDENTIFIER(B). { A = B.string; push_usertype(ctx, A, NULL); }
 
-%type struct_member_list { StructMembers * }
+%type struct_member_list { MOJOSHADER_astStructMembers * }
 %destructor struct_member_list { delete_struct_member(ctx, $$); }
 struct_member_list(A) ::= struct_member(B). { A = B; }
 struct_member_list(A) ::= struct_member_list(B) struct_member(C). { A = C; A->next = B; }
 
-%type struct_member { StructMembers * }
+%type struct_member { MOJOSHADER_astStructMembers * }
 %destructor struct_member { delete_struct_member(ctx, $$); }
-struct_member(A) ::= interpolation_mod(B) struct_member_details(C). { StructMembers *i = C; A = C; while (i) { i->interpolation_mod = B; i = i->next; } }
+struct_member(A) ::= interpolation_mod(B) struct_member_details(C). { MOJOSHADER_astStructMembers *i = C; A = C; while (i) { i->interpolation_mod = B; i = i->next; } }
 struct_member(A) ::= struct_member_details(B). { A = B; }
 
-%type struct_member_details { StructMembers * }
+%type struct_member_details { MOJOSHADER_astStructMembers * }
 %destructor struct_member_details { delete_struct_member(ctx, $$); }
-struct_member_details(A) ::= datatype(B) struct_member_item_list(C) SEMICOLON. { StructMembers *i = C; A = C; while (i) { i->datatype = B; i = i->next; } }
+struct_member_details(A) ::= datatype(B) struct_member_item_list(C) SEMICOLON. { MOJOSHADER_astStructMembers *i = C; A = C; while (i) { i->datatype = B; i = i->next; } }
 
-%type struct_member_item_list { StructMembers * }
+%type struct_member_item_list { MOJOSHADER_astStructMembers * }
 %destructor struct_member_item_list { delete_struct_member(ctx, $$); }
 struct_member_item_list(A) ::= scalar_or_array(B). { A = new_struct_member(ctx, B, NULL); }
 struct_member_item_list(A) ::= scalar_or_array(B) semantic(C). { A = new_struct_member(ctx, B, C); }
 struct_member_item_list(A) ::= struct_member_item_list(B) COMMA IDENTIFIER(C). { A = new_struct_member(ctx, new_scalar_or_array(ctx, C.string, 0, NULL), NULL); A->next = B; A->semantic = B->semantic; }
 
-%type variable_lowlevel { VariableLowLevel * }
+%type variable_lowlevel { MOJOSHADER_astVariableLowLevel * }
 %destructor variable_lowlevel { delete_variable_lowlevel(ctx, $$); }
 variable_lowlevel(A) ::= packoffset(B) register(C). { A = new_variable_lowlevel(ctx, B, C); }
 variable_lowlevel(A) ::= register(B) packoffset(C). { A = new_variable_lowlevel(ctx, C, B); }
@@ -254,13 +254,13 @@
 variable_lowlevel(A) ::= register(B). { A = new_variable_lowlevel(ctx, NULL, B); }
 
 // !!! FIXME: I sort of hate this type name.
-%type scalar_or_array { ScalarOrArray * }
+%type scalar_or_array { MOJOSHADER_astScalarOrArray * }
 %destructor scalar_or_array { delete_scalar_or_array(ctx, $$); }
 scalar_or_array(A) ::= IDENTIFIER(B) LBRACKET RBRACKET. { A = new_scalar_or_array(ctx, B.string, 1, NULL); }
 scalar_or_array(A) ::= IDENTIFIER(B) LBRACKET expression(C) RBRACKET. { A = new_scalar_or_array(ctx, B.string, 1, C); }
 scalar_or_array(A) ::= IDENTIFIER(B). { A = new_scalar_or_array(ctx, B.string, 0, NULL); }
 
-%type packoffset { PackOffset * }
+%type packoffset { MOJOSHADER_astPackOffset * }
 %destructor packoffset { delete_pack_offset(ctx, $$); }
 packoffset(A) ::= COLON PACKOFFSET LPAREN IDENTIFIER(B) DOT IDENTIFIER(C) RPAREN. { A = new_pack_offset(ctx, B.string, C.string); }
 packoffset(A) ::= COLON PACKOFFSET LPAREN IDENTIFIER(B) RPAREN. { A = new_pack_offset(ctx, B.string, NULL); }
@@ -271,31 +271,31 @@
 %type register { const char * }
 register(A) ::= COLON REGISTER LPAREN IDENTIFIER(B) RPAREN. { A = B.string; }
 
-%type annotations { Annotations * }
+%type annotations { MOJOSHADER_astAnnotations * }
 %destructor annotations { delete_annotation(ctx, $$); }
-annotations(A) ::= LT annotation_list(B) GT. { REVERSE_LINKED_LIST(Annotations, B); A = B; }
+annotations(A) ::= LT annotation_list(B) GT. { REVERSE_LINKED_LIST(MOJOSHADER_astAnnotations, B); A = B; }
 
-%type annotation_list { Annotations * }
+%type annotation_list { MOJOSHADER_astAnnotations * }
 %destructor annotation_list { delete_annotation(ctx, $$); }
 annotation_list(A) ::= annotation(B). { A = B; }
 annotation_list(A) ::= annotation_list(B) annotation(C). { A = C; A->next = B; }
 
 // !!! FIXME: can this take a USERTYPE if we typedef'd a scalar type?
-%type annotation { Annotations * }
+%type annotation { MOJOSHADER_astAnnotations * }
 %destructor annotation { delete_annotation(ctx, $$); }
 annotation(A) ::= datatype_scalar(B) initializer(C) SEMICOLON. { A = new_annotation(ctx, B, C); }
 
-%type initializer_block_list { Expression * }
+%type initializer_block_list { MOJOSHADER_astExpression * }
 %destructor initializer_block_list { delete_expr(ctx, $$); }
 initializer_block_list(A) ::= expression(B). { A = B; }
 initializer_block_list(A) ::= LBRACE initializer_block_list(B) RBRACE. { A = B; }
-initializer_block_list(A) ::= initializer_block_list(B) COMMA initializer_block_list(C). { A = new_binary_expr(ctx, AST_OP_COMMA, B, C); }
+initializer_block_list(A) ::= initializer_block_list(B) COMMA initializer_block_list(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_COMMA, B, C); }
 
-%type initializer_block { Expression * }
+%type initializer_block { MOJOSHADER_astExpression * }
 %destructor initializer_block { delete_expr(ctx, $$); }
 initializer_block(A) ::= LBRACE initializer_block_list(B) RBRACE. { A = B; }
 
-%type initializer { Expression * }
+%type initializer { MOJOSHADER_astExpression * }
 %destructor initializer { delete_expr(ctx, $$); }
 initializer(A) ::= ASSIGN initializer_block(B). { A = B; }
 initializer(A) ::= ASSIGN expression(B). { A = B; }
@@ -343,12 +343,12 @@
 %type datatype_matrix { const char * }
 datatype_matrix(A) ::= MATRIX LT datatype_scalar(B) COMMA INT_CONSTANT(C) COMMA INT_CONSTANT(D) GT. { A = stringcache_fmt(ctx->strcache, "M{%d,%d,%s}", (int) C.i64, (int) D.i64, B); }
 
-%type statement_block { Statement * }
+%type statement_block { MOJOSHADER_astStatement * }
 %destructor statement_block { delete_statement(ctx, $$); }
 statement_block(A) ::= LBRACE RBRACE. { A = new_block_statement(ctx, NULL); }
-statement_block(A) ::= LBRACE statement_list(B) RBRACE. { REVERSE_LINKED_LIST(Statement, B); A = new_block_statement(ctx, B); }
+statement_block(A) ::= LBRACE statement_list(B) RBRACE. { REVERSE_LINKED_LIST(MOJOSHADER_astStatement, B); A = new_block_statement(ctx, B); }
 
-%type statement_list { Statement * }
+%type statement_list { MOJOSHADER_astStatement * }
 %destructor statement_list { delete_statement(ctx, $$); }
 statement_list(A) ::= statement(B). { A = B; }
 statement_list(A) ::= statement_list(B) statement(C). { A = C; A->next = B; }
@@ -364,7 +364,7 @@
 statement_attribute(A) ::= UNUSED. { A = 0; }  // !!! FIXME
 statement_attribute(A) ::= XPS. { A = 0; }  // !!! FIXME
 
-%type statement { Statement * }
+%type statement { MOJOSHADER_astStatement * }
 %destructor statement { delete_statement(ctx, $$); }
 statement(A) ::= BREAK SEMICOLON. { A = new_break_statement(ctx); }
 statement(A) ::= CONTINUE SEMICOLON. { A = new_continue_statement(ctx); }
@@ -376,7 +376,7 @@
 statement(A) ::= while_intro(B) LPAREN expression(C) RPAREN statement(D). { A = new_while_statement(ctx, B, C, D); }
 statement(A) ::= if_intro(B) LPAREN expression(C) RPAREN statement(D). { A = new_if_statement(ctx, B, C, D, NULL); }
 statement(A) ::= if_intro(B) LPAREN expression(C) RPAREN statement(D) ELSE statement(E). { A = new_if_statement(ctx, B, C, D, E); }
-statement(A) ::= switch_intro(B) LPAREN expression(C) RPAREN LBRACE switch_case_list(D) RBRACE. { REVERSE_LINKED_LIST(SwitchCases, D); A = new_switch_statement(ctx, B, C, D); }
+statement(A) ::= switch_intro(B) LPAREN expression(C) RPAREN LBRACE switch_case_list(D) RBRACE. { REVERSE_LINKED_LIST(MOJOSHADER_astSwitchCases, D); A = new_switch_statement(ctx, B, C, D); }
 statement(A) ::= typedef(B). { A = new_typedef_statement(ctx, B); }
 statement(A) ::= SEMICOLON. { A = new_empty_statement(ctx); }
 statement(A) ::= expression(B) SEMICOLON. { A = new_expr_statement(ctx, B); }
@@ -386,23 +386,23 @@
 statement(A) ::= for_statement(B). { A = B; }
 //statement(A) ::= error SEMICOLON. { A = NULL; }  // !!! FIXME: research using the error nonterminal
 
-%type while_intro { int64 }
+%type while_intro { int }
 while_intro(A) ::= LBRACKET UNROLL LPAREN INT_CONSTANT(B) RPAREN RBRACKET WHILE. { A = (B.i64 < 0) ? 0 : B.i64; }
 while_intro(A) ::= LBRACKET UNROLL RBRACKET WHILE. { A = -1; }
 while_intro(A) ::= LBRACKET LOOP RBRACKET WHILE. { A = 0; }
 while_intro(A) ::= WHILE. { A = -2; }
 
-%type for_statement { Statement * }
+%type for_statement { MOJOSHADER_astStatement * }
 %destructor for_statement { delete_statement(ctx, $$); }
-for_statement(A) ::= for_intro(B) for_details(C). { A = C; ((ForStatement *) A)->unroll = B; }
+for_statement(A) ::= for_intro(B) for_details(C). { A = C; ((MOJOSHADER_astForStatement *) A)->unroll = B; }
 
-%type for_intro { int64 }
+%type for_intro { int }
 for_intro(A) ::= LBRACKET UNROLL LPAREN INT_CONSTANT(B) RPAREN RBRACKET FOR. { A = (B.i64 < 0) ? 0 : B.i64; }
 for_intro(A) ::= LBRACKET UNROLL RBRACKET FOR. { A = -1; }
 for_intro(A) ::= LBRACKET LOOP RBRACKET FOR. { A = 0; }
 for_intro(A) ::= FOR. { A = -2; }
 
-%type for_details { Statement * }
+%type for_details { MOJOSHADER_astStatement * }
 %destructor for_details { delete_statement(ctx, $$); }
 for_details(A) ::= LPAREN expression(B) SEMICOLON expression(C) SEMICOLON expression(D) RPAREN statement(E). { A = new_for_statement(ctx, NULL, B, C, D, E); }
 for_details(A) ::= LPAREN SEMICOLON SEMICOLON RPAREN statement(B). { A = new_for_statement(ctx, NULL, NULL, NULL, NULL, B); }
@@ -417,44 +417,44 @@
 for_details(A) ::= LPAREN variable_declaration(B) SEMICOLON expression(C) RPAREN statement(D). { A = new_for_statement(ctx, B, NULL, C, NULL, D); }
 for_details(A) ::= LPAREN variable_declaration(B) expression(C) SEMICOLON RPAREN statement(D). { A = new_for_statement(ctx, B, NULL, C, NULL, D); }
 
-%type do_intro { int64 }
+%type do_intro { int }
 do_intro(A) ::= LBRACKET UNROLL LPAREN INT_CONSTANT(B) RPAREN RBRACKET DO. { A = (B.i64 < 0) ? 0 : (int) B.i64; }
 do_intro(A) ::= LBRACKET UNROLL RBRACKET DO. { A = -1; }
 do_intro(A) ::= LBRACKET LOOP RBRACKET DO. { A = 0; }
 do_intro(A) ::= DO. { A = -2; }
 
 %type if_intro { int }
-if_intro(A) ::= LBRACKET BRANCH RBRACKET IF. { A = IFATTR_BRANCH; }
-if_intro(A) ::= LBRACKET FLATTEN RBRACKET IF. { A = IFATTR_FLATTEN; }
-if_intro(A) ::= LBRACKET IFALL RBRACKET IF. { A = IFATTR_IFALL; }
-if_intro(A) ::= LBRACKET IFANY RBRACKET IF. { A = IFATTR_IFANY; }
-if_intro(A) ::= LBRACKET PREDICATE RBRACKET IF. { A = IFATTR_PREDICATE; }
-if_intro(A) ::= LBRACKET PREDICATEBLOCK RBRACKET IF. { A = IFATTR_PREDICATEBLOCK; }
-if_intro(A) ::= IF. { A = IFATTR_NONE; }
+if_intro(A) ::= LBRACKET BRANCH RBRACKET IF. { A = MOJOSHADER_AST_IFATTR_BRANCH; }
+if_intro(A) ::= LBRACKET FLATTEN RBRACKET IF. { A = MOJOSHADER_AST_IFATTR_FLATTEN; }
+if_intro(A) ::= LBRACKET IFALL RBRACKET IF. { A = MOJOSHADER_AST_IFATTR_IFALL; }
+if_intro(A) ::= LBRACKET IFANY RBRACKET IF. { A = MOJOSHADER_AST_IFATTR_IFANY; }
+if_intro(A) ::= LBRACKET PREDICATE RBRACKET IF. { A = MOJOSHADER_AST_IFATTR_PREDICATE; }
+if_intro(A) ::= LBRACKET PREDICATEBLOCK RBRACKET IF. { A = MOJOSHADER_AST_IFATTR_PREDICATEBLOCK; }
+if_intro(A) ::= IF. { A = MOJOSHADER_AST_IFATTR_NONE; }
 
 %type switch_intro { int }
-switch_intro(A) ::= LBRACKET FLATTEN RBRACKET SWITCH. { A = SWITCHATTR_FLATTEN; }
-switch_intro(A) ::= LBRACKET BRANCH RBRACKET SWITCH. { A = SWITCHATTR_BRANCH; }
-switch_intro(A) ::= LBRACKET FORCECASE RBRACKET SWITCH. { A = SWITCHATTR_FORCECASE; }
-switch_intro(A) ::= LBRACKET CALL RBRACKET SWITCH. { A = SWITCHATTR_CALL; }
-switch_intro(A) ::= SWITCH. { A = SWITCHATTR_NONE; }
+switch_intro(A) ::= LBRACKET FLATTEN RBRACKET SWITCH. { A = MOJOSHADER_AST_SWITCHATTR_FLATTEN; }
+switch_intro(A) ::= LBRACKET BRANCH RBRACKET SWITCH. { A = MOJOSHADER_AST_SWITCHATTR_BRANCH; }
+switch_intro(A) ::= LBRACKET FORCECASE RBRACKET SWITCH. { A = MOJOSHADER_AST_SWITCHATTR_FORCECASE; }
+switch_intro(A) ::= LBRACKET CALL RBRACKET SWITCH. { A = MOJOSHADER_AST_SWITCHATTR_CALL; }
+switch_intro(A) ::= SWITCH. { A = MOJOSHADER_AST_SWITCHATTR_NONE; }
 
-%type switch_case_list { SwitchCases * }
+%type switch_case_list { MOJOSHADER_astSwitchCases * }
 %destructor switch_case_list { delete_switch_case(ctx, $$); }
 switch_case_list(A) ::= switch_case(B). { A = B; }
 switch_case_list(A) ::= switch_case_list(B) switch_case(C). { A = C; A->next = B; }
 
 // You can do math here, apparently, as long as it produces an int constant.
 //  ...so "case 3+2:" works.
-%type switch_case { SwitchCases * }
+%type switch_case { MOJOSHADER_astSwitchCases * }
 %destructor switch_case { delete_switch_case(ctx, $$); }
-switch_case(A) ::= CASE expression(B) COLON statement_list(C). { REVERSE_LINKED_LIST(Statement, C); A = new_switch_case(ctx, B, C); }
+switch_case(A) ::= CASE expression(B) COLON statement_list(C). { REVERSE_LINKED_LIST(MOJOSHADER_astStatement, C); A = new_switch_case(ctx, B, C); }
 switch_case(A) ::= CASE expression(B) COLON. { A = new_switch_case(ctx, B, NULL); }
-switch_case(A) ::= DEFAULT COLON statement_list(B). { REVERSE_LINKED_LIST(Statement, B); A = new_switch_case(ctx, NULL, B); }
+switch_case(A) ::= DEFAULT COLON statement_list(B). { REVERSE_LINKED_LIST(MOJOSHADER_astStatement, B); A = new_switch_case(ctx, NULL, B); }
 switch_case(A) ::= DEFAULT COLON. { A = new_switch_case(ctx, NULL, NULL); }
 
 // the expression stuff is based on Jeff Lee's ANSI C grammar.
-%type primary_expr { Expression * }
+%type primary_expr { MOJOSHADER_astExpression * }
 %destructor primary_expr { delete_expr(ctx, $$); }
 primary_expr(A) ::= IDENTIFIER(B). { A = new_identifier_expr(ctx, B.string); }
 primary_expr(A) ::= INT_CONSTANT(B). { A = new_literal_int_expr(ctx, B.i64); }
@@ -464,123 +464,123 @@
 primary_expr(A) ::= FALSE. { A = new_literal_boolean_expr(ctx, 0); }
 primary_expr(A) ::= LPAREN expression(B) RPAREN. { A = B; }
 
-%type postfix_expr { Expression * }
+%type postfix_expr { MOJOSHADER_astExpression * }
 %destructor postfix_expr { delete_expr(ctx, $$); }
 postfix_expr(A) ::= primary_expr(B). { A = B; }
-postfix_expr(A) ::= postfix_expr(B) LBRACKET expression(C) RBRACKET. { A = new_binary_expr(ctx, AST_OP_DEREF_ARRAY, B, C); }
+postfix_expr(A) ::= postfix_expr(B) LBRACKET expression(C) RBRACKET. { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_DEREF_ARRAY, B, C); }
 postfix_expr(A) ::= postfix_expr(B) arguments(C). { A = new_callfunc_expr(ctx, B, C); }
 postfix_expr(A) ::= datatype(B) arguments(C). { A = new_constructor_expr(ctx, B, C); } // HLSL constructor
 postfix_expr(A) ::= postfix_expr(B) DOT IDENTIFIER(C). { A = new_deref_struct_expr(ctx, B, C.string); }
-postfix_expr(A) ::= postfix_expr(B) PLUSPLUS. { A = new_unary_expr(ctx, AST_OP_POSTINCREMENT, B); }
-postfix_expr(A) ::= postfix_expr(B) MINUSMINUS. { A = new_unary_expr(ctx, AST_OP_POSTDECREMENT, B); }
+postfix_expr(A) ::= postfix_expr(B) PLUSPLUS. { A = new_unary_expr(ctx, MOJOSHADER_AST_OP_POSTINCREMENT, B); }
+postfix_expr(A) ::= postfix_expr(B) MINUSMINUS. { A = new_unary_expr(ctx, MOJOSHADER_AST_OP_POSTDECREMENT, B); }
 
-%type arguments { Arguments * }
+%type arguments { MOJOSHADER_astArguments * }
 %destructor arguments { delete_arguments(ctx, $$); }
 arguments(A) ::= LPAREN RPAREN. { A = NULL; }
-arguments(A) ::= LPAREN argument_list(B) RPAREN. { REVERSE_LINKED_LIST(Arguments, B); A = B; }
+arguments(A) ::= LPAREN argument_list(B) RPAREN. { REVERSE_LINKED_LIST(MOJOSHADER_astArguments, B); A = B; }
 
-%type argument_list { Arguments * }
+%type argument_list { MOJOSHADER_astArguments * }
 %destructor argument_list { delete_arguments(ctx, $$); }
 argument_list(A) ::= assignment_expr(B). { A = new_argument(ctx, B); }
 argument_list(A) ::= argument_list(B) COMMA assignment_expr(C). { A = new_argument(ctx, C); A->next = B; }
 
-%type unary_expr { Expression * }
+%type unary_expr { MOJOSHADER_astExpression * }
 %destructor unary_expr { delete_expr(ctx, $$); }
 unary_expr(A) ::= postfix_expr(B). { A = B; }
-unary_expr(A) ::= PLUSPLUS unary_expr(B). { A = new_unary_expr(ctx, AST_OP_PREINCREMENT, B); }
-unary_expr(A) ::= MINUSMINUS unary_expr(B). { A = new_unary_expr(ctx, AST_OP_PREDECREMENT, B); }
+unary_expr(A) ::= PLUSPLUS unary_expr(B). { A = new_unary_expr(ctx, MOJOSHADER_AST_OP_PREINCREMENT, B); }
+unary_expr(A) ::= MINUSMINUS unary_expr(B). { A = new_unary_expr(ctx, MOJOSHADER_AST_OP_PREDECREMENT, B); }
 unary_expr(A) ::= PLUS cast_expr(B). { A = B; }  // unary "+x" is always a no-op, so throw it away here.
-unary_expr(A) ::= MINUS cast_expr(B). { A = new_unary_expr(ctx, AST_OP_NEGATE, B); }
-unary_expr(A) ::= COMPLEMENT cast_expr(B). { A = new_unary_expr(ctx, AST_OP_COMPLEMENT, B); }
-unary_expr(A) ::= EXCLAMATION cast_expr(B). { A = new_unary_expr(ctx, AST_OP_NOT, B); }
+unary_expr(A) ::= MINUS cast_expr(B). { A = new_unary_expr(ctx, MOJOSHADER_AST_OP_NEGATE, B); }
+unary_expr(A) ::= COMPLEMENT cast_expr(B). { A = new_unary_expr(ctx, MOJOSHADER_AST_OP_COMPLEMENT, B); }
+unary_expr(A) ::= EXCLAMATION cast_expr(B). { A = new_unary_expr(ctx, MOJOSHADER_AST_OP_NOT, B); }
 
-%type cast_expr { Expression * }
+%type cast_expr { MOJOSHADER_astExpression * }
 %destructor cast_expr { delete_expr(ctx, $$); }
 cast_expr(A) ::= unary_expr(B). { A = B; }
 cast_expr(A) ::= LPAREN datatype(B) RPAREN cast_expr(C). { A = new_cast_expr(ctx, B, C); }
 
-%type multiplicative_expr { Expression * }
+%type multiplicative_expr { MOJOSHADER_astExpression * }
 %destructor multiplicative_expr { delete_expr(ctx, $$); }
 multiplicative_expr(A) ::= cast_expr(B). { A = B; }
-multiplicative_expr(A) ::= multiplicative_expr(B) STAR cast_expr(C). { A = new_binary_expr(ctx, AST_OP_MULTIPLY, B, C); }
-multiplicative_expr(A) ::= multiplicative_expr(B) SLASH cast_expr(C). { A = new_binary_expr(ctx, AST_OP_DIVIDE, B, C); }
-multiplicative_expr(A) ::= multiplicative_expr(B) PERCENT cast_expr(C). { A = new_binary_expr(ctx, AST_OP_MODULO, B, C); }
+multiplicative_expr(A) ::= multiplicative_expr(B) STAR cast_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_MULTIPLY, B, C); }
+multiplicative_expr(A) ::= multiplicative_expr(B) SLASH cast_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_DIVIDE, B, C); }
+multiplicative_expr(A) ::= multiplicative_expr(B) PERCENT cast_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_MODULO, B, C); }
 
-%type additive_expr { Expression * }
+%type additive_expr { MOJOSHADER_astExpression * }
 %destructor additive_expr { delete_expr(ctx, $$); }
 additive_expr(A) ::= multiplicative_expr(B). { A = B; }
-additive_expr(A) ::= additive_expr(B) PLUS multiplicative_expr(C). { A = new_binary_expr(ctx, AST_OP_ADD, B, C); }
-additive_expr(A) ::= additive_expr(B) MINUS multiplicative_expr(C). { A = new_binary_expr(ctx, AST_OP_SUBTRACT, B, C); }
+additive_expr(A) ::= additive_expr(B) PLUS multiplicative_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_ADD, B, C); }
+additive_expr(A) ::= additive_expr(B) MINUS multiplicative_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_SUBTRACT, B, C); }
 
-%type shift_expr { Expression * }
+%type shift_expr { MOJOSHADER_astExpression * }
 %destructor shift_expr { delete_expr(ctx, $$); }
 shift_expr(A) ::= additive_expr(B). { A = B; }
-shift_expr(A) ::= shift_expr(B) LSHIFT additive_expr(C). { A = new_binary_expr(ctx, AST_OP_LSHIFT, B, C); }
-shift_expr(A) ::= shift_expr(B) RSHIFT additive_expr(C). { A = new_binary_expr(ctx, AST_OP_RSHIFT, B, C); }
+shift_expr(A) ::= shift_expr(B) LSHIFT additive_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_LSHIFT, B, C); }
+shift_expr(A) ::= shift_expr(B) RSHIFT additive_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_RSHIFT, B, C); }
 
-%type relational_expr { Expression * }
+%type relational_expr { MOJOSHADER_astExpression * }
 %destructor relational_expr { delete_expr(ctx, $$); }
 relational_expr(A) ::= shift_expr(B). { A = B; }
-relational_expr(A) ::= relational_expr(B) LT shift_expr(C). { A = new_binary_expr(ctx, AST_OP_LESSTHAN, B, C); }
-relational_expr(A) ::= relational_expr(B) GT shift_expr(C). { A = new_binary_expr(ctx, AST_OP_GREATERTHAN, B, C); }
-relational_expr(A) ::= relational_expr(B) LEQ shift_expr(C). { A = new_binary_expr(ctx, AST_OP_LESSTHANOREQUAL, B, C); }
-relational_expr(A) ::= relational_expr(B) GEQ shift_expr(C). { A = new_binary_expr(ctx, AST_OP_GREATERTHANOREQUAL, B, C); }
+relational_expr(A) ::= relational_expr(B) LT shift_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_LESSTHAN, B, C); }
+relational_expr(A) ::= relational_expr(B) GT shift_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_GREATERTHAN, B, C); }
+relational_expr(A) ::= relational_expr(B) LEQ shift_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_LESSTHANOREQUAL, B, C); }
+relational_expr(A) ::= relational_expr(B) GEQ shift_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_GREATERTHANOREQUAL, B, C); }
 
-%type equality_expr { Expression * }
+%type equality_expr { MOJOSHADER_astExpression * }
 %destructor equality_expr { delete_expr(ctx, $$); }
 equality_expr(A) ::= relational_expr(B). { A = B; }
-equality_expr(A) ::= equality_expr(B) EQL relational_expr(C). { A = new_binary_expr(ctx, AST_OP_EQUAL, B, C); }
-equality_expr(A) ::= equality_expr(B) NEQ relational_expr(C). { A = new_binary_expr(ctx, AST_OP_NOTEQUAL, B, C); }
+equality_expr(A) ::= equality_expr(B) EQL relational_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_EQUAL, B, C); }
+equality_expr(A) ::= equality_expr(B) NEQ relational_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_NOTEQUAL, B, C); }
 
-%type and_expr { Expression * }
+%type and_expr { MOJOSHADER_astExpression * }
 %destructor and_expr { delete_expr(ctx, $$); }
 and_expr(A) ::= equality_expr(B). { A = B; }
-and_expr(A) ::= and_expr(B) AND equality_expr(C). { A = new_binary_expr(ctx, AST_OP_BINARYAND, B, C); }
+and_expr(A) ::= and_expr(B) AND equality_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_BINARYAND, B, C); }
 
-%type exclusive_or_expr { Expression * }
+%type exclusive_or_expr { MOJOSHADER_astExpression * }
 %destructor exclusive_or_expr { delete_expr(ctx, $$); }
 exclusive_or_expr(A) ::= and_expr(B). { A = B; }
-exclusive_or_expr(A) ::= exclusive_or_expr(B) XOR and_expr(C). { A = new_binary_expr(ctx, AST_OP_BINARYXOR, B, C); }
+exclusive_or_expr(A) ::= exclusive_or_expr(B) XOR and_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_BINARYXOR, B, C); }
 
-%type inclusive_or_expr { Expression * }
+%type inclusive_or_expr { MOJOSHADER_astExpression * }
 %destructor inclusive_or_expr { delete_expr(ctx, $$); }
 inclusive_or_expr(A) ::= exclusive_or_expr(B). { A = B; }
-inclusive_or_expr(A) ::= inclusive_or_expr(B) OR exclusive_or_expr(C). { A = new_binary_expr(ctx, AST_OP_BINARYOR, B, C); }
+inclusive_or_expr(A) ::= inclusive_or_expr(B) OR exclusive_or_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_BINARYOR, B, C); }
 
-%type logical_and_expr { Expression * }
+%type logical_and_expr { MOJOSHADER_astExpression * }
 %destructor logical_and_expr { delete_expr(ctx, $$); }
 logical_and_expr(A) ::= inclusive_or_expr(B). { A = B; }
-logical_and_expr(A) ::= logical_and_expr(B) ANDAND inclusive_or_expr(C). { A = new_binary_expr(ctx, AST_OP_LOGICALAND, B, C); }
+logical_and_expr(A) ::= logical_and_expr(B) ANDAND inclusive_or_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_LOGICALAND, B, C); }
 
-%type logical_or_expr { Expression * }
+%type logical_or_expr { MOJOSHADER_astExpression * }
 %destructor logical_or_expr { delete_expr(ctx, $$); }
 logical_or_expr(A) ::= logical_and_expr(B). { A = B; }
-logical_or_expr(A) ::= logical_or_expr(B) OROR logical_and_expr(C). { A = new_binary_expr(ctx, AST_OP_LOGICALOR, B, C); }
+logical_or_expr(A) ::= logical_or_expr(B) OROR logical_and_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_LOGICALOR, B, C); }
 
-%type conditional_expr { Expression * }
+%type conditional_expr { MOJOSHADER_astExpression * }
 %destructor conditional_expr { delete_expr(ctx, $$); }
 conditional_expr(A) ::= logical_or_expr(B). { A = B; }
-conditional_expr(A) ::= logical_or_expr(B) QUESTION logical_or_expr(C) COLON conditional_expr(D). { A = new_ternary_expr(ctx, AST_OP_CONDITIONAL, B, C, D); }
+conditional_expr(A) ::= logical_or_expr(B) QUESTION logical_or_expr(C) COLON conditional_expr(D). { A = new_ternary_expr(ctx, MOJOSHADER_AST_OP_CONDITIONAL, B, C, D); }
 
-%type assignment_expr { Expression * }
+%type assignment_expr { MOJOSHADER_astExpression * }
 %destructor assignment_expr { delete_expr(ctx, $$); }
 assignment_expr(A) ::= conditional_expr(B). { A = B; }
-assignment_expr(A) ::= unary_expr(B) ASSIGN assignment_expr(C). { A = new_binary_expr(ctx, AST_OP_ASSIGN, B, C); }
-assignment_expr(A) ::= unary_expr(B) MULASSIGN assignment_expr(C). { A = new_binary_expr(ctx, AST_OP_MULASSIGN, B, C); }
-assignment_expr(A) ::= unary_expr(B) DIVASSIGN assignment_expr(C). { A = new_binary_expr(ctx, AST_OP_DIVASSIGN, B, C); }
-assignment_expr(A) ::= unary_expr(B) MODASSIGN assignment_expr(C). { A = new_binary_expr(ctx, AST_OP_MODASSIGN, B, C); }
-assignment_expr(A) ::= unary_expr(B) ADDASSIGN assignment_expr(C). { A = new_binary_expr(ctx, AST_OP_ADDASSIGN, B, C); }
-assignment_expr(A) ::= unary_expr(B) SUBASSIGN assignment_expr(C). { A = new_binary_expr(ctx, AST_OP_SUBASSIGN, B, C); }
-assignment_expr(A) ::= unary_expr(B) LSHIFTASSIGN assignment_expr(C). { A = new_binary_expr(ctx, AST_OP_LSHIFTASSIGN, B, C); }
-assignment_expr(A) ::= unary_expr(B) RSHIFTASSIGN assignment_expr(C). { A = new_binary_expr(ctx, AST_OP_RSHIFTASSIGN, B, C); }
-assignment_expr(A) ::= unary_expr(B) ANDASSIGN assignment_expr(C). { A = new_binary_expr(ctx, AST_OP_ANDASSIGN, B, C); }
-assignment_expr(A) ::= unary_expr(B) XORASSIGN assignment_expr(C). { A = new_binary_expr(ctx, AST_OP_XORASSIGN, B, C); }
-assignment_expr(A) ::= unary_expr(B) ORASSIGN assignment_expr(C). { A = new_binary_expr(ctx, AST_OP_ORASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) ASSIGN assignment_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_ASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) MULASSIGN assignment_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_MULASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) DIVASSIGN assignment_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_DIVASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) MODASSIGN assignment_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_MODASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) ADDASSIGN assignment_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_ADDASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) SUBASSIGN assignment_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_SUBASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) LSHIFTASSIGN assignment_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_LSHIFTASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) RSHIFTASSIGN assignment_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_RSHIFTASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) ANDASSIGN assignment_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_ANDASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) XORASSIGN assignment_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_XORASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) ORASSIGN assignment_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_ORASSIGN, B, C); }
 
-%type expression { Expression * }
+%type expression { MOJOSHADER_astExpression * }
 %destructor expression { delete_expr(ctx, $$); }
 expression(A) ::= assignment_expr(B). { A = B; }
-expression(A) ::= expression(B) COMMA assignment_expr(C). { A = new_binary_expr(ctx, AST_OP_COMMA, B, C); }
+expression(A) ::= expression(B) COMMA assignment_expr(C). { A = new_binary_expr(ctx, MOJOSHADER_AST_OP_COMMA, B, C); }
 
 // end of mojoshader_parser_hlsl.lemon ...
 
--- a/utils/mojoshader-compiler.c	Tue Oct 26 17:27:31 2010 -0400
+++ b/utils/mojoshader-compiler.c	Thu Oct 28 03:42:12 2010 -0400
@@ -10,8 +10,14 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <assert.h>
+
 #include "mojoshader.h"
 
+#ifndef _WIN32
+#define stricmp(a,b) strcasecmp(a,b)
+#endif
+
 static const char **include_paths = NULL;
 static unsigned int include_path_count = 0;
 
@@ -48,6 +54,555 @@
     exit(1);
 } // fail
 
+static void print_unroll_attr(const int unroll)
+{
+    if (unroll == 0)
+        printf("[loop] ");
+    else if (unroll < 0)
+        printf("[unroll] ");
+    else
+        printf("[unroll(%d)] ", unroll);
+} // print_unroll_attr
+
+// !!! FIXME: this screws up on order of operations.
+static void print_ast(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++) printf("    "); } \
+    } 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:
+            printf("%s", pre_unary[(typeint-MOJOSHADER_AST_OP_START_RANGE_UNARY)-1]);
+            print_ast(0, ast->unary.operand);
+            break;
+
+        case MOJOSHADER_AST_OP_POSTINCREMENT:
+        case MOJOSHADER_AST_OP_POSTDECREMENT:
+            print_ast(0, ast->unary.operand);
+            printf("%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:
+            printf(" ");  // then fall through! (no space before the comma).
+        case MOJOSHADER_AST_OP_COMMA:
+            print_ast(0, ast->binary.left);
+            printf("%s ", binary[
+                (typeint - MOJOSHADER_AST_OP_START_RANGE_BINARY) - 1]);
+            print_ast(0, ast->binary.right);
+            break;
+
+        case MOJOSHADER_AST_OP_DEREF_ARRAY:
+            print_ast(0, ast->binary.left);
+            printf("[");
+            print_ast(0, ast->binary.right);
+            printf("]");
+            break;
+
+        case MOJOSHADER_AST_OP_DEREF_STRUCT:
+            print_ast(0, ast->derefstruct.identifier);
+            printf(".");
+            printf("%s", ast->derefstruct.member);
+            break;
+
+        case MOJOSHADER_AST_OP_CONDITIONAL:
+            print_ast(0, ast->ternary.left);
+            printf(" ? ");
+            print_ast(0, ast->ternary.center);
+            printf(" : ");
+            print_ast(0, ast->ternary.right);
+            break;
+
+        case MOJOSHADER_AST_OP_IDENTIFIER:
+            printf("%s", ast->identifier.identifier);
+            break;
+
+        case MOJOSHADER_AST_OP_INT_LITERAL:
+            printf("%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)
+                printf("%lld.0", flr);
+            else
+                printf("%.16g", f);
+            break;
+        } // case
+
+        case MOJOSHADER_AST_OP_STRING_LITERAL:
+            printf("\"%s\"", ast->stringliteral.string);
+            break;
+
+        case MOJOSHADER_AST_OP_BOOLEAN_LITERAL:
+            printf("%s", ast->boolliteral.value ? "true" : "false");
+            break;
+
+        case MOJOSHADER_AST_ARGUMENTS:
+            print_ast(0, ast->arguments.argument);
+            if (ast->arguments.next != NULL)
+            {
+                printf(", ");
+                print_ast(0, ast->arguments.next);
+            } // if
+            break;
+
+        case MOJOSHADER_AST_OP_CALLFUNC:
+            print_ast(0, ast->callfunc.identifier);
+            printf("(");
+            print_ast(0, ast->callfunc.args);
+            printf(")");
+            break;
+
+        case MOJOSHADER_AST_OP_CONSTRUCTOR:
+            printf("%s(", ast->constructor.datatype);
+            print_ast(0, ast->constructor.args);
+            printf(")");
+            break;
+
+        case MOJOSHADER_AST_OP_CAST:
+            printf("(%s) (", ast->cast.datatype);
+            print_ast(0, ast->cast.operand);
+            printf(")");
+            break;
+
+        case MOJOSHADER_AST_STATEMENT_EXPRESSION:
+            DO_INDENT;
+            print_ast(0, ast->exprstmt.expr);  // !!! FIXME: This is named badly...
+            printf(";%s", nl);
+            print_ast(0, ast->exprstmt.next);
+            break;
+
+        case MOJOSHADER_AST_STATEMENT_IF:
+            DO_INDENT;
+            printf("if (");
+            print_ast(0, ast->ifstmt.expr);
+            printf(")\n");
+            isblock = ast->ifstmt.statement->ast.type == MOJOSHADER_AST_STATEMENT_BLOCK;
+            if (!isblock) indent++;
+            print_ast(0, ast->ifstmt.statement);
+            if (!isblock) indent--;
+            print_ast(0, ast->ifstmt.next);
+            break;
+
+        case MOJOSHADER_AST_STATEMENT_TYPEDEF:
+            DO_INDENT;
+            print_ast(1, ast->typedefstmt.type_info);
+            printf("%s", nl);
+            print_ast(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: printf("[flatten] "); break;
+                case MOJOSHADER_AST_SWITCHATTR_BRANCH: printf("[branch] "); break;
+                case MOJOSHADER_AST_SWITCHATTR_FORCECASE: printf("[forcecase] "); break;
+                case MOJOSHADER_AST_SWITCHATTR_CALL: printf("[call] "); break;
+            } // switch
+
+            printf("switch (");
+            print_ast(0, ast->switchstmt.expr);
+            printf(")\n");
+            DO_INDENT;
+            printf("{\n");
+            indent++;
+            print_ast(0, ast->switchstmt.cases);
+            indent--;
+            printf("\n");
+            DO_INDENT;
+            printf("}\n");
+            print_ast(0, ast->switchstmt.next);
+            break;
+
+        case MOJOSHADER_AST_SWITCH_CASE:
+            DO_INDENT;
+            printf("case ");
+            print_ast(0, ast->cases.expr);
+            printf(":\n");
+            isblock = ast->cases.statement->ast.type == MOJOSHADER_AST_STATEMENT_BLOCK;
+            if (!isblock) indent++;
+            print_ast(0, ast->cases.statement);
+            if (!isblock) indent--;
+            print_ast(0, ast->cases.next);
+            break;
+
+        case MOJOSHADER_AST_STATEMENT_STRUCT:
+            DO_INDENT;
+            print_ast(0, ast->structstmt.struct_info);
+            printf(";%s%s", nl, nl);  // always space these out.
+            print_ast(0, ast->structstmt.next);
+            break;
+
+        case MOJOSHADER_AST_STATEMENT_VARDECL:
+            DO_INDENT;
+            print_ast(1, ast->vardeclstmt.declaration);
+            printf(";%s", nl);
+            print_ast(0, ast->vardeclstmt.next);
+            break;
+
+        case MOJOSHADER_AST_STATEMENT_BLOCK:
+            DO_INDENT;
+            printf("{\n");
+            indent++;
+            print_ast(0, ast->blockstmt.statements);
+            indent--;
+            DO_INDENT;
+            printf("}\n");
+            print_ast(0, ast->blockstmt.next);
+            break;
+
+        case MOJOSHADER_AST_STATEMENT_FOR:
+            DO_INDENT;
+            print_unroll_attr(ast->forstmt.unroll);
+            printf("for (");
+            print_ast(1, ast->forstmt.var_decl);
+            if (ast->forstmt.initializer != NULL)
+            {
+                printf(" = ");
+                print_ast(1, ast->forstmt.initializer);
+            } // if
+            printf("; ");
+            print_ast(1, ast->forstmt.looptest);
+            printf("; ");
+            print_ast(1, ast->forstmt.counter);
+
+            printf(")\n");
+            isblock = ast->forstmt.statement->ast.type == MOJOSHADER_AST_STATEMENT_BLOCK;
+            if (!isblock) indent++;
+            print_ast(0, ast->forstmt.statement);
+            if (!isblock) indent--;
+
+            print_ast(0, ast->forstmt.next);
+            break;
+
+        case MOJOSHADER_AST_STATEMENT_DO:
+            DO_INDENT;
+            print_unroll_attr(ast->dostmt.unroll);
+            printf("do\n");
+
+            isblock = ast->dostmt.statement->ast.type == MOJOSHADER_AST_STATEMENT_BLOCK;
+            if (!isblock) indent++;
+            print_ast(0, ast->dostmt.statement);
+            if (!isblock) indent--;
+
+            DO_INDENT;
+            printf("while (");
+            print_ast(0, ast->dostmt.expr);
+            printf(");\n");
+
+            print_ast(0, ast->dostmt.next);
+            break;
+
+        case MOJOSHADER_AST_STATEMENT_WHILE:
+            DO_INDENT;
+            print_unroll_attr(ast->whilestmt.unroll);
+            printf("while (");
+            print_ast(0, ast->whilestmt.expr);
+            printf(")\n");
+
+            isblock = ast->whilestmt.statement->ast.type == MOJOSHADER_AST_STATEMENT_BLOCK;
+            if (!isblock) indent++;
+            print_ast(0, ast->whilestmt.statement);
+            if (!isblock) indent--;
+
+            print_ast(0, ast->whilestmt.next);
+            break;
+
+        case MOJOSHADER_AST_STATEMENT_RETURN:
+            DO_INDENT;
+            printf("return");
+            if (ast->returnstmt.expr)
+            {
+                printf(" ");
+                print_ast(0, ast->returnstmt.expr);
+            } // if
+            printf(";%s", nl);
+            print_ast(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;
+            printf("%s;%s",
+                simple_stmt[(typeint-MOJOSHADER_AST_STATEMENT_START_RANGE)-1],
+                nl);
+            print_ast(0, ast->stmt.next);
+            break;
+
+        case MOJOSHADER_AST_COMPUNIT_FUNCTION:
+            DO_INDENT;
+            print_ast(0, ast->funcunit.declaration);
+            if (ast->funcunit.definition == NULL)
+                printf(";%s", nl);
+            else
+            {
+                printf("%s", nl);
+                print_ast(0, ast->funcunit.definition);
+                printf("%s", nl);
+            } // else
+            print_ast(0, ast->funcunit.next);
+            break;
+
+        case MOJOSHADER_AST_COMPUNIT_TYPEDEF:
+            DO_INDENT;
+            print_ast(0, ast->typedefunit.type_info);
+            printf("%s", nl);
+            print_ast(0, ast->typedefunit.next);
+            break;
+
+        case MOJOSHADER_AST_COMPUNIT_STRUCT:
+            DO_INDENT;
+            print_ast(0, ast->structunit.struct_info);
+            printf(";%s%s", nl, nl);  // always space these out.
+            print_ast(0, ast->structunit.next);
+            break;
+
+        case MOJOSHADER_AST_COMPUNIT_VARIABLE:
+            DO_INDENT;
+            print_ast(1, ast->varunit.declaration);
+            printf(";%s", nl);
+            if (ast->varunit.next &&
+                ast->varunit.next->ast.type!=MOJOSHADER_AST_COMPUNIT_VARIABLE)
+            {
+                printf("%s", nl);  // group vars together, and space out other things.
+            } // if
+            print_ast(0, ast->varunit.next);
+            break;
+
+        case MOJOSHADER_AST_SCALAR_OR_ARRAY:
+            printf("%s", ast->soa.identifier);
+            if (ast->soa.isarray)
+            {
+                printf("[");
+                print_ast(0, ast->soa.dimension);
+                printf("]");
+            } // if
+            break;
+
+        case MOJOSHADER_AST_TYPEDEF:
+            DO_INDENT;
+            printf("typedef %s%s ",
+                   ast->typdef.isconst ? "const " : "", ast->typdef.datatype);
+            print_ast(0, ast->typdef.details);
+            printf(";%s", nl);
+            break;
+
+        case MOJOSHADER_AST_FUNCTION_PARAMS:
+            printf("%s", inpmod[(int) ast->params.input_modifier]);
+            printf("%s %s", ast->params.datatype, ast->params.identifier);
+            if (ast->params.semantic)
+                printf(" : %s", ast->params.semantic);
+            printf("%s", interpmod[(int) ast->params.interpolation_modifier]);
+
+            if (ast->params.initializer)
+            {
+                printf(" = ");
+                print_ast(0, ast->params.initializer);
+            } // if
+
+            if (ast->params.next)
+            {
+                printf(", ");
+                print_ast(0, ast->params.next);
+            } // if
+            break;
+
+        case MOJOSHADER_AST_FUNCTION_SIGNATURE:
+            printf("%s", fnstorage[(int) ast->funcsig.storage_class]);
+            printf("%s %s(",
+                    ast->funcsig.datatype ? ast->funcsig.datatype : "void",
+                    ast->funcsig.identifier);
+            print_ast(0, ast->funcsig.params);
+            printf(")");
+            if (ast->funcsig.semantic)
+                printf(" : %s", ast->funcsig.semantic);
+            break;
+
+        case MOJOSHADER_AST_STRUCT_DECLARATION:
+            printf("struct %s\n", ast->structdecl.name);
+            DO_INDENT;
+            printf("{\n");
+            indent++;
+            print_ast(0, ast->structdecl.members);
+            indent--;
+            DO_INDENT;
+            printf("}");
+            break;
+
+        case MOJOSHADER_AST_STRUCT_MEMBER:
+            DO_INDENT;
+            printf("%s", interpmod[(int)ast->structmembers.interpolation_mod]);
+            printf("%s ", ast->structmembers.datatype);
+            print_ast(0, ast->structmembers.details);
+            if (ast->structmembers.semantic)
+                printf(" : %s", ast->structmembers.semantic);
+            printf(";%s", nl);
+            print_ast(0, ast->structmembers.next);
+            break;
+
+        case MOJOSHADER_AST_VARIABLE_DECLARATION:
+            DO_INDENT;
+            if (ast->vardecl.attributes & MOJOSHADER_AST_VARATTR_EXTERN)
+                printf("extern ");
+            if (ast->vardecl.attributes & MOJOSHADER_AST_VARATTR_NOINTERPOLATION)
+                printf("nointerpolation ");
+            if (ast->vardecl.attributes & MOJOSHADER_AST_VARATTR_SHARED)
+                printf("shared");
+            if (ast->vardecl.attributes & MOJOSHADER_AST_VARATTR_STATIC)
+                printf("static ");
+            if (ast->vardecl.attributes & MOJOSHADER_AST_VARATTR_UNIFORM)
+                printf("uniform ");
+            if (ast->vardecl.attributes & MOJOSHADER_AST_VARATTR_VOLATILE)
+                printf("nointerpolation ");
+            if (ast->vardecl.attributes & MOJOSHADER_AST_VARATTR_CONST)
+                printf("const ");
+            if (ast->vardecl.attributes & MOJOSHADER_AST_VARATTR_ROWMAJOR)
+                printf("rowmajor ");
+            if (ast->vardecl.attributes & MOJOSHADER_AST_VARATTR_COLUMNMAJOR)
+                printf("columnmajor ");
+
+            if (ast->vardecl.datatype)
+                printf("%s", ast->vardecl.datatype);
+            else
+                print_ast(0, ast->vardecl.anonymous_datatype);
+            printf(" ");
+            print_ast(0, ast->vardecl.details);
+            if (ast->vardecl.semantic)
+                printf(" : %s", ast->vardecl.semantic);
+            if (ast->vardecl.annotations)
+            {
+                printf(" ");
+                print_ast(0, ast->vardecl.annotations);
+            } // if
+            if (ast->vardecl.initializer != NULL)
+            {
+                printf(" = ");
+                print_ast(0, ast->vardecl.initializer);
+            } // if
+            print_ast(0, ast->vardecl.lowlevel);
+
+            if (ast->vardecl.next == NULL)
+                printf("%s", nl);
+            else
+            {
+                const int attr = ast->vardecl.next->attributes;
+                printf(", ");
+                ast->vardecl.next->attributes = 0;
+                print_ast(1, ast->vardecl.next);
+                ast->vardecl.next->attributes = attr;
+            } // if
+            break;
+
+        case MOJOSHADER_AST_PACK_OFFSET:
+            printf(" : packoffset(%s%s%s)", ast->packoffset.ident1,
+                    ast->packoffset.ident2 ? "." : "",
+                    ast->packoffset.ident2 ? ast->packoffset.ident2 : "");
+            break;
+
+        case MOJOSHADER_AST_VARIABLE_LOWLEVEL:
+            print_ast(0, ast->varlowlevel.packoffset);
+            if (ast->varlowlevel.register_name)
+                printf(" : register(%s)", ast->varlowlevel.register_name);
+            break;
+
+        case MOJOSHADER_AST_ANNOTATION:
+        {
+            const MOJOSHADER_astAnnotations *a = &ast->annotations;
+            printf("<");
+            while (a)
+            {
+                printf(" %s ", a->datatype);
+                if (a->initializer != NULL)
+                {
+                    printf(" = ");
+                    print_ast(0, a->initializer);
+                } // if
+                if (a->next)
+                    printf(",");
+                a = a->next;
+            } // while
+            printf(" >");
+            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,
@@ -192,13 +747,19 @@
     return retval;
 } // assemble
 
-void MOJOSHADER_compile(const char *filename,
-                             const char *source, unsigned int sourcelen,
-                             const MOJOSHADER_preprocessorDefine *defines,
-                             unsigned int define_count,
-                             MOJOSHADER_includeOpen include_open,
-                             MOJOSHADER_includeClose include_close,
-                             MOJOSHADER_malloc m, MOJOSHADER_free f, void *d);
+static int ast(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_parseAst(MOJOSHADER_SRC_PROFILE_HLSL_PS_1_1,  // !!! FIXME
+                        fname, buf, len, defs, defcount,
+                        open_include, close_include, Malloc, Free, NULL);
+    return 1;
+} // ast
 
 static int compile(const char *fname, const char *buf, int len,
                     const char *outfile,
@@ -209,7 +770,8 @@
     //const MOJOSHADER_parseData *pd;
     //int retval = 0;
 
-    MOJOSHADER_compile(fname, buf, len, defs, defcount,
+    MOJOSHADER_compile(MOJOSHADER_SRC_PROFILE_HLSL_PS_1_1,  // !!! FIXME
+                        fname, buf, len, defs, defcount,
                              open_include, close_include,
                              Malloc, Free, NULL);
     return 1;
@@ -221,6 +783,7 @@
     ACTION_VERSION,
     ACTION_PREPROCESS,
     ACTION_ASSEMBLE,
+    ACTION_AST,
     ACTION_COMPILE,
 } Action;
 
@@ -240,6 +803,7 @@
     include_paths[0] = ".";
     include_path_count = 1;
 
+    // !!! FIXME: clean this up.
     for (i = 1; i < argc; i++)
     {
         const char *arg = argv[i];
@@ -258,6 +822,13 @@
             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))
@@ -358,6 +929,8 @@
         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));