Start of experiment with a basic calculator. calculator-experiment
authorRyan C. Gordon <icculus@icculus.org>
Mon, 08 Feb 2010 02:42:12 -0500
branchcalculator-experiment
changeset 811 307e3ab506fa
parent 810 367f7133bd71
child 812 ac8e761569da
Start of experiment with a basic calculator. This is a throwaway so I can debug some of the HLSL parsing code, and get a better idea of what I want to do there. This will eventually merge back into the default branch with the right bits going into the compiler code.
CMakeLists.txt
calculator.c
calculator.lemon
mojoshader_internal.h
--- a/CMakeLists.txt	Mon Feb 08 02:38:19 2010 -0500
+++ b/CMakeLists.txt	Mon Feb 08 02:42:12 2010 -0500
@@ -76,6 +76,21 @@
     PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/mojoshader_parser_hlsl.h"
 )
 
+# Calculator test stuff...
+ADD_CUSTOM_COMMAND(
+    OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/calculator.h"
+    MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/calculator.lemon"
+    DEPENDS lemon "${CMAKE_CURRENT_SOURCE_DIR}/misc/lempar.c"
+    COMMAND "${LEMON}"
+    ARGS -q "-T${CMAKE_CURRENT_SOURCE_DIR}/misc/lempar.c" "${CMAKE_CURRENT_SOURCE_DIR}/calculator.lemon"
+)
+SET_SOURCE_FILES_PROPERTIES(
+    calculator.c
+    PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/calculator.h"
+)
+ADD_EXECUTABLE(calculator calculator.c)
+TARGET_LINK_LIBRARIES(calculator mojoshader)
+
 FIND_PROGRAM(RE2C re2c DOC "Path to re2c command line app: http://re2c.org/")
 IF(NOT RE2C)
     MESSAGE(STATUS "re2c missing. You can go on, but can't rebuild the lexer.")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/calculator.c	Mon Feb 08 02:42:12 2010 -0500
@@ -0,0 +1,412 @@
+#define __MOJOSHADER_INTERNAL__ 1
+#include "mojoshader_internal.h"
+
+#if DEBUG_COMPILER_PARSER
+#define LEMON_SUPPORT_TRACING 1
+#endif
+
+typedef struct Context
+{
+    int isfail;
+    int out_of_memory;
+    MOJOSHADER_malloc malloc;
+    MOJOSHADER_free free;
+    void *malloc_data;
+    int error_count;
+    ErrorList *errors;
+    Preprocessor *preprocessor;
+    const char *token;
+    unsigned int tokenlen;
+    Token tokenval;
+    unsigned int parse_errors;
+} Context;
+
+
+// Convenience functions for allocators...
+
+static inline void out_of_memory(Context *ctx)
+{
+    ctx->isfail = ctx->out_of_memory = 1;
+} // out_of_memory
+
+static inline void *Malloc(Context *ctx, const size_t len)
+{
+    void *retval = ctx->malloc((int) len, ctx->malloc_data);
+    if (retval == NULL)
+        out_of_memory(ctx);
+    return retval;
+} // Malloc
+
+static inline char *StrDup(Context *ctx, const char *str)
+{
+    char *retval = (char *) Malloc(ctx, strlen(str) + 1);
+    if (retval != NULL)
+        strcpy(retval, str);
+    return retval;
+} // StrDup
+
+static inline void Free(Context *ctx, void *ptr)
+{
+    if (ptr != NULL)  // check for NULL in case of dumb free() impl.
+        ctx->free(ptr, ctx->malloc_data);
+} // Free
+
+typedef enum Operator
+{
+    OP_DEREF_ARRAY,
+    OP_CALLFUNC,
+    OP_DEREF_STRUCT,
+    OP_POSTINCREMENT,
+    OP_POSTDECREMENT,
+    OP_COMMA,
+    OP_PREINCREMENT,
+    OP_PREDECREMENT,
+    OP_NEGATE,
+    OP_COMPLEMENT,
+    OP_NOT,
+    OP_MULTIPLY,
+    OP_DIVIDE,
+    OP_MODULO,
+    OP_ADD,
+    OP_SUBTRACT,
+    OP_LSHIFT,
+    OP_RSHIFT,
+    OP_LESSTHAN,
+    OP_GREATERTHAN,
+    OP_LESSTHANOREQUAL,
+    OP_GREATERTHANOREQUAL,
+    OP_EQUAL,
+    OP_NOTEQUAL,
+    OP_BINARYAND,
+    OP_BINARYXOR,
+    OP_BINARYOR,
+    OP_LOGICALAND,
+    OP_LOGICALOR,
+    OP_CONDITIONAL,
+    OP_ASSIGN,
+    OP_MULASSIGN,
+    OP_DIVASSIGN,
+    OP_MODASSIGN,
+    OP_ADDASSIGN,
+    OP_SUBASSIGN,
+    OP_LSHIFTASSIGN,
+    OP_RSHIFTASSIGN,
+    OP_ANDASSIGN,
+    OP_XORASSIGN,
+    OP_ORASSIGN,
+} Operator;
+
+typedef struct Expression
+{
+    Operator op;  // operator
+} Expression;
+
+#define NEW_EXPR(cls) \
+    cls *retval = Malloc(ctx, sizeof (cls)); \
+    if (retval == NULL) { return NULL; }
+
+typedef struct ExpressionUnary
+{
+    Operator op;  // operator
+    Expression *operand;
+} ExpressionUnary;
+
+typedef struct ExpressionBinary
+{
+    Operator op;  // operator
+    Expression *left;
+    Expression *right;
+} ExpressionBinary;
+
+typedef struct ExpressionTernary
+{
+    Operator op;  // operator
+    Expression *left;
+    Expression *center;
+    Expression *right;
+} ExpressionTernary;
+
+typedef struct ExpressionIdentifier
+{
+    Operator op;  // Always TOKEN_CALC_IDENTIFIER
+    const char *identifier;
+} ExpressionIdentifier;
+
+typedef struct ExpressionLiteralInt
+{
+    Operator op;  // Always TOKEN_CALC_INT_CONSTANT
+    int64 value;
+} ExpressionLiteralInt;
+
+typedef struct ExpressionLiteralFloat
+{
+    Operator op;  // Always TOKEN_CALC_FLOAT_CONSTANT
+    double value;
+} ExpressionLiteralFloat;
+
+typedef struct ExpressionLiteralString
+{
+    Operator op;  // Always TOKEN_CALC_STRING_LITERAL
+    const char *string;
+} ExpressionLiteralString;
+
+static const char *new_identifier(Context *);
+static Expression *new_unary_expr(Context *, const Operator, Expression *);
+static Expression *new_binary_expr(Context *, const Operator, Expression *, Expression *);
+static Expression *new_ternary_expr(Context *, const Operator, Expression *, Expression *, Expression *);
+static Expression *new_identifier_expr(Context *, const char *);
+static Expression *new_literal_int_expr(Context *);
+static Expression *new_literal_float_expr(Context *);
+static Expression *new_literal_string_expr(Context *);
+
+static void parse_complete(const Expression *expr)
+{
+    printf("parse complete!\n");
+    
+} // parse_complete
+
+
+// This is where the actual parsing happens. It's Lemon-generated!
+#define __MOJOSHADER_CALC_COMPILER__ 1
+#include "calculator.h"
+
+static const char *new_identifier(Context *ctx)
+{
+    // !!! FIXME: this needs to cache strings.
+    const unsigned int len = ctx->tokenlen;
+    char *retval = Malloc(ctx, len + 1);
+    if (retval == NULL)
+        return NULL;
+    memcpy(retval, ctx->token, len);
+    retval[len] = '\0';
+    return retval;
+} // new_identifier
+
+static Expression *new_unary_expr(Context *ctx, const Operator op,
+                                  Expression *operand)
+{
+    NEW_EXPR(ExpressionUnary);
+    retval->op = op;
+    retval->operand = operand;
+    return (Expression *) retval;
+} // new_unary_expr
+
+static Expression *new_binary_expr(Context *ctx, const Operator op,
+                                   Expression *left, Expression *right)
+{
+    NEW_EXPR(ExpressionBinary);
+    retval->op = op;
+    retval->left = left;
+    retval->right = right;
+    return (Expression *) retval;
+} // new_binary_expr
+
+static Expression *new_ternary_expr(Context *ctx, const Operator op,
+                                    Expression *left, Expression *center,
+                                    Expression *right)
+{
+    NEW_EXPR(ExpressionTernary);
+    retval->op = op;
+    retval->left = left;
+    retval->center = center;
+    retval->right = right;
+    return (Expression *) retval;
+} // new_ternary_expr
+
+static Expression *new_identifier_expr(Context *ctx, const char *identifier)
+{
+    NEW_EXPR(ExpressionIdentifier);
+    retval->op = TOKEN_CALC_IDENTIFIER;
+    retval->identifier = identifier;
+    return (Expression *) retval;
+} // new_identifier_expr
+
+static inline int64 strtoi64(const char *str, unsigned int len)
+{
+    int64 retval = 0;
+    int64 mult = 1;
+    int i = 0;
+
+    while ((len) && (*str == ' '))
+    {
+        str++;
+        len--;
+    } // while
+
+    if ((len) && (*str == '-'))
+    {
+        mult = -1;
+        str++;
+        len--;
+    } // if
+
+    while (i < len)
+    {
+        const char ch = str[i];
+        if ((ch < '0') || (ch > '9'))
+            break;
+        i++;
+    } // while
+
+    while (--i >= 0)
+    {
+        const char ch = str[i];
+        retval += ((int64) (ch - '0')) * mult;
+        mult *= 10;
+    } // while
+
+    return retval;
+} // strtoi64
+
+static Expression *new_literal_int_expr(Context *ctx)
+{
+    NEW_EXPR(ExpressionLiteralInt);
+    retval->op = TOKEN_CALC_INT_CONSTANT;
+    retval->value = strtoi64(ctx->token, ctx->tokenlen);
+    return (Expression *) retval;
+} // new_literal_int_expr
+
+static inline double strtodouble(const char *_str, unsigned int len)
+{
+    // !!! FIXME: laziness prevails.
+    char *str = (char *) alloca(len+1);
+    memcpy(str, _str, len);
+    str[len] = '\0';
+    return strtod(str, NULL);
+} // strtodouble
+
+static Expression *new_literal_float_expr(Context *ctx)
+{
+    NEW_EXPR(ExpressionLiteralFloat);
+    retval->op = TOKEN_CALC_FLOAT_CONSTANT;
+    retval->value = strtodouble(ctx->token, ctx->tokenlen);
+    return (Expression *) retval;
+} // new_literal_float_expr
+
+static Expression *new_literal_string_expr(Context *ctx)
+{
+    NEW_EXPR(ExpressionLiteralString);
+    retval->op = TOKEN_CALC_STRING_LITERAL;
+    retval->string = new_identifier(ctx);
+    return (Expression *) retval;
+} // new_string_literal_expr
+
+
+static int convert_to_lemon_token(const Context *ctx)
+{
+    switch (ctx->tokenval)
+    {
+        case ((Token) ','): return TOKEN_CALC_COMMA;
+        case ((Token) '='): return TOKEN_CALC_ASSIGN;
+        case ((Token) TOKEN_ADDASSIGN): return TOKEN_CALC_ADDASSIGN;
+        case ((Token) TOKEN_SUBASSIGN): return TOKEN_CALC_SUBASSIGN;
+        case ((Token) TOKEN_MULTASSIGN): return TOKEN_CALC_MULASSIGN;
+        case ((Token) TOKEN_DIVASSIGN): return TOKEN_CALC_DIVASSIGN;
+        case ((Token) TOKEN_MODASSIGN): return TOKEN_CALC_MODASSIGN;
+        case ((Token) TOKEN_LSHIFTASSIGN): return TOKEN_CALC_LSHIFTASSIGN;
+        case ((Token) TOKEN_RSHIFTASSIGN): return TOKEN_CALC_RSHIFTASSIGN;
+        case ((Token) TOKEN_ANDASSIGN): return TOKEN_CALC_ANDASSIGN;
+        case ((Token) TOKEN_ORASSIGN): return TOKEN_CALC_ORASSIGN;
+        case ((Token) TOKEN_XORASSIGN): return TOKEN_CALC_XORASSIGN;
+        case ((Token) '?'): return TOKEN_CALC_QUESTION;
+        case ((Token) TOKEN_OROR): return TOKEN_CALC_OROR;
+        case ((Token) TOKEN_ANDAND): return TOKEN_CALC_ANDAND;
+        case ((Token) '|'): return TOKEN_CALC_OR;
+        case ((Token) '^'): return TOKEN_CALC_XOR;
+        case ((Token) '&'): return TOKEN_CALC_AND;
+        case ((Token) TOKEN_EQL): return TOKEN_CALC_EQL;
+        case ((Token) TOKEN_NEQ): return TOKEN_CALC_NEQ;
+        case ((Token) '<'): return TOKEN_CALC_LT;
+        case ((Token) TOKEN_LEQ): return TOKEN_CALC_LEQ;
+        case ((Token) '>'): return TOKEN_CALC_GT;
+        case ((Token) TOKEN_GEQ): return TOKEN_CALC_GEQ;
+        case ((Token) TOKEN_LSHIFT): return TOKEN_CALC_LSHIFT;
+        case ((Token) TOKEN_RSHIFT): return TOKEN_CALC_RSHIFT;
+        case ((Token) '+'): return TOKEN_CALC_PLUS;
+        case ((Token) '-'): return TOKEN_CALC_MINUS;
+        case ((Token) '*'): return TOKEN_CALC_STAR;
+        case ((Token) '/'): return TOKEN_CALC_SLASH;
+        case ((Token) '%'): return TOKEN_CALC_PERCENT;
+        case ((Token) '!'): return TOKEN_CALC_EXCLAMATION;
+        case ((Token) '~'): return TOKEN_CALC_COMPLEMENT;
+        case ((Token) TOKEN_DECREMENT): return TOKEN_CALC_MINUSMINUS;
+        case ((Token) TOKEN_INCREMENT): return TOKEN_CALC_PLUSPLUS;
+        case ((Token) '.'): return TOKEN_CALC_DOT;
+        case ((Token) '['): return TOKEN_CALC_LBRACKET;
+        case ((Token) ']'): return TOKEN_CALC_RBRACKET;
+        case ((Token) '('): return TOKEN_CALC_LPAREN;
+        case ((Token) ')'): return TOKEN_CALC_RPAREN;
+        case ((Token) TOKEN_INT_LITERAL): return TOKEN_CALC_INT_CONSTANT;
+        case ((Token) TOKEN_FLOAT_LITERAL): return TOKEN_CALC_FLOAT_CONSTANT;
+        case ((Token) TOKEN_STRING_LITERAL): return TOKEN_CALC_STRING_LITERAL;
+        case ((Token) ':'): return TOKEN_CALC_COLON;
+        //case ((Token) ';'): return TOKEN_CALC_SEMICOLON;
+        //case ((Token) '{'): return TOKEN_CALC_LBRACE;
+        //case ((Token) '}'): return TOKEN_CALC_RBRACE;
+        case ((Token) TOKEN_IDENTIFIER): return TOKEN_CALC_IDENTIFIER;
+        case TOKEN_EOI: return 0;
+        case TOKEN_BAD_CHARS: printf("bad chars from lexer\n"); return 0;
+        case TOKEN_PREPROCESSING_ERROR: printf("error from lexer\n"); return 0;
+        default: assert(0 && "unexpected token from lexer\n"); return 0;
+    } // switch
+
+    return 0;
+} // convert_to_lemon_token
+
+static 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)
+{
+    Context ctx;
+    if (m == NULL) m = MOJOSHADER_internal_malloc;
+    if (f == NULL) f = MOJOSHADER_internal_free;
+
+    memset(&ctx, '\0', sizeof (Context));
+    ctx.malloc = m;
+    ctx.free = f;
+    ctx.malloc_data = d;
+    ctx.preprocessor = preprocessor_start(filename, source, sourcelen,
+                                           include_open, include_close,
+                                           defines, define_count, 0, m, f, d);
+
+    void *pParser = ParseCalculatorAlloc(m, d);
+
+    #if DEBUG_COMPILER_PARSER
+    ParseCalculatorTrace(stdout, "COMPILER: ");
+    #endif
+
+    do {
+        ctx.token = preprocessor_nexttoken(ctx.preprocessor,
+                                                &ctx.tokenlen,
+                                                &ctx.tokenval);
+        ParseCalculator(pParser, convert_to_lemon_token(&ctx), 0, &ctx);
+    } while (ctx.tokenval != TOKEN_EOI);
+    ParseCalculatorFree(pParser, f, d);
+}
+
+int main(int argc, char **argv)
+{
+    const char *ln;
+    size_t len = 0;
+    FILE *io = stdin;
+    const char *filename = "<stdin>";
+
+    while ((ln = fgetln(io, &len)) != NULL)
+    {
+        if ((len == 5) && (memcmp(ln, "quit\n", 5) == 0))
+            break;
+
+        MOJOSHADER_compile(filename, ln, (unsigned int) len,
+                           NULL, 0, NULL, NULL, NULL, NULL, NULL);
+    } // while
+
+    fclose(io);
+    return 0;
+} // main
+
+// end of calculator.c ...
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/calculator.lemon	Mon Feb 08 02:42:12 2010 -0500
@@ -0,0 +1,185 @@
+/**
+ * MojoShader; generate shader programs from bytecode of compiled
+ *  Direct3D shaders.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+// This is a Lemon Parser grammar for HLSL. It is based on an ANSI C YACC
+//  grammar by Jeff Lee: http://www.lysator.liu.se/c/ANSI-C-grammar-y.html
+
+// Lemon is here: http://www.hwaci.com/sw/lemon/  ...  the source is included
+//  with MojoShader, and built with the library, so you don't have to track
+//  down the dependency.
+
+%name ParseCalculator
+
+// Some shift-reduce conflicts are basically unavoidable, but if the final
+//  conflict count matches this value, we consider it known and acceptable.
+%expect 0
+
+%start_symbol calculator
+%token_prefix TOKEN_CALC_
+%token_type { int }
+%extra_argument { Context *ctx }
+
+%include {
+#ifndef __MOJOSHADER_CALC_COMPILER__
+#error Do not compile this file directly.
+#endif
+}
+
+%syntax_error {
+    fprintf(stderr,"Syntax error\n");
+}
+
+%parse_failure {
+    fprintf(stderr,"Giving up.  Parser is hopelessly lost...\n");
+}
+
+%stack_overflow {
+    fprintf(stderr,"Giving up.  Parser stack overflow\n");
+}
+
+// operator precedence (matches C spec)...
+
+%left COMMA.
+%right ASSIGN ADDASSIGN SUBASSIGN MULASSIGN DIVASSIGN MODASSIGN LSHIFTASSIGN
+       RSHIFTASSIGN ANDASSIGN ORASSIGN XORASSIGN.
+%right QUESTION.
+%left OROR.
+%left ANDAND.
+%left OR.
+%left XOR.
+%left AND.
+%left EQL NEQ.
+%left LT LEQ GT GEQ.
+%left LSHIFT RSHIFT.
+%left PLUS MINUS.
+%left STAR SLASH PERCENT.
+%right TYPECAST EXCLAMATION COMPLEMENT MINUSMINUS PLUSPLUS.
+%left DOT LBRACKET RBRACKET LPAREN RPAREN.
+
+// bump up the precedence of ELSE, to avoid shift/reduce conflict on the
+//  usual "dangling else ambiguity" ...
+%right ELSE.
+
+
+// The rules...
+
+%type calculator { Expression * }
+calculator(A) ::= expression(B). { A = B; }
+
+%type identifier { const char * }
+%destructor identifier { (void) ctx; }  // !!! FIXME: remove this later, it's just to shut up the compiler for now.
+identifier(A) ::= IDENTIFIER. { A = new_identifier(ctx); }
+
+// the expression stuff is based on Jeff Lee's ANSI C grammar.
+%type primary_expr { Expression * }
+primary_expr(A) ::= identifier(B). { A = new_identifier_expr(ctx, B); }
+primary_expr(A) ::= INT_CONSTANT. { A = new_literal_int_expr(ctx); }
+primary_expr(A) ::= FLOAT_CONSTANT. { A = new_literal_float_expr(ctx); }
+primary_expr(A) ::= STRING_LITERAL. { A = new_literal_string_expr(ctx); }
+primary_expr(A) ::= LPAREN expression(B) RPAREN. { A = B; }
+
+%type postfix_expr { Expression * }
+postfix_expr(A) ::= primary_expr(B). { A = B; }
+postfix_expr(A) ::= postfix_expr(B) LBRACKET expression(C) RBRACKET. { A = new_binary_expr(ctx, OP_DEREF_ARRAY, B, C); }
+postfix_expr(A) ::= postfix_expr(B) LPAREN RPAREN. { A = new_binary_expr(ctx, OP_CALLFUNC, B, NULL); }
+postfix_expr(A) ::= postfix_expr(B) LPAREN argument_expr_list(C) RPAREN. { A = new_binary_expr(ctx, OP_CALLFUNC, B, C); }
+//postfix_expr(A) ::= datatype(B) LPAREN argument_expr_list(C) RPAREN. { A = new_constructor_expr(ctx, B, C); } // HLSL constructor
+postfix_expr(A) ::= postfix_expr(B) DOT identifier(C). { A = new_binary_expr(ctx, OP_DEREF_STRUCT, B, new_identifier_expr(ctx, C)); }
+postfix_expr(A) ::= postfix_expr(B) PLUSPLUS. { A = new_unary_expr(ctx, OP_POSTINCREMENT, B); }
+postfix_expr(A) ::= postfix_expr(B) MINUSMINUS. { A = new_unary_expr(ctx, OP_POSTDECREMENT, B); }
+
+%type argument_expr_list { Expression * }
+argument_expr_list(A) ::= assignment_expr(B). { A = B; }
+argument_expr_list(A) ::= argument_expr_list(B) COMMA assignment_expr(C). { A = new_binary_expr(ctx, OP_COMMA, B, C); }
+
+%type unary_expr { Expression * }
+unary_expr(A) ::= postfix_expr(B).  { A = B; }
+unary_expr(A) ::= PLUSPLUS unary_expr(B). { A = new_unary_expr(ctx, OP_PREINCREMENT, B); }
+unary_expr(A) ::= MINUSMINUS unary_expr(B). { A = new_unary_expr(ctx, 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, OP_NEGATE, B); }
+unary_expr(A) ::= COMPLEMENT cast_expr(B). { A = new_unary_expr(ctx, OP_COMPLEMENT, B); }
+unary_expr(A) ::= EXCLAMATION cast_expr(B). { A = new_unary_expr(ctx, OP_NOT, B); }
+
+%type cast_expr { Expression * }
+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 * }
+multiplicative_expr(A) ::= cast_expr(B). { A = B; }
+multiplicative_expr(A) ::= multiplicative_expr(B) STAR cast_expr(C). { A = new_binary_expr(ctx, OP_MULTIPLY, B, C); }
+multiplicative_expr(A) ::= multiplicative_expr(B) SLASH cast_expr(C). { A = new_binary_expr(ctx, OP_DIVIDE, B, C); }
+multiplicative_expr(A) ::= multiplicative_expr(B) PERCENT cast_expr(C). { A = new_binary_expr(ctx, OP_MODULO, B, C); }
+
+%type additive_expr { Expression * }
+additive_expr(A) ::= multiplicative_expr(B). { A = B; }
+additive_expr(A) ::= additive_expr(B) PLUS multiplicative_expr(C). { A = new_binary_expr(ctx, OP_ADD, B, C); }
+additive_expr(A) ::= additive_expr(B) MINUS multiplicative_expr(C). { A = new_binary_expr(ctx, OP_SUBTRACT, B, C); }
+
+%type shift_expr { Expression * }
+shift_expr(A) ::= additive_expr(B). { A = B; }
+shift_expr(A) ::= shift_expr(B) LSHIFT additive_expr(C). { A = new_binary_expr(ctx, OP_LSHIFT, B, C); }
+shift_expr(A) ::= shift_expr(B) RSHIFT additive_expr(C). { A = new_binary_expr(ctx, OP_RSHIFT, B, C); }
+
+%type relational_expr { Expression * }
+relational_expr(A) ::= shift_expr(B). { A = B; }
+relational_expr(A) ::= relational_expr(B) LT shift_expr(C). { A = new_binary_expr(ctx, OP_LESSTHAN, B, C); }
+relational_expr(A) ::= relational_expr(B) GT shift_expr(C). { A = new_binary_expr(ctx, OP_GREATERTHAN, B, C); }
+relational_expr(A) ::= relational_expr(B) LEQ shift_expr(C). { A = new_binary_expr(ctx, OP_LESSTHANOREQUAL, B, C); }
+relational_expr(A) ::= relational_expr(B) GEQ shift_expr(C). { A = new_binary_expr(ctx, OP_GREATERTHANOREQUAL, B, C); }
+
+%type equality_expr { Expression * }
+equality_expr(A) ::= relational_expr(B). { A = B; }
+equality_expr(A) ::= equality_expr(B) EQL relational_expr(C). { A = new_binary_expr(ctx, OP_EQUAL, B, C); }
+equality_expr(A) ::= equality_expr(B) NEQ relational_expr(C). { A = new_binary_expr(ctx, OP_NOTEQUAL, B, C); }
+
+%type and_expr { Expression * }
+and_expr(A) ::= equality_expr(B). { A = B; }
+and_expr(A) ::= and_expr(B) AND equality_expr(C). { A = new_binary_expr(ctx, OP_BINARYAND, B, C); }
+
+%type exclusive_or_expr { Expression * }
+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, OP_BINARYXOR, B, C); }
+
+%type inclusive_or_expr { Expression * }
+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, OP_BINARYOR, B, C); }
+
+%type logical_and_expr { Expression * }
+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, OP_LOGICALAND, B, C); }
+
+%type logical_or_expr { Expression * }
+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, OP_LOGICALOR, B, C); }
+
+%type conditional_expr { Expression * }
+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, OP_CONDITIONAL, B, C, D); }
+
+%type assignment_expr { Expression * }
+assignment_expr(A) ::= conditional_expr(B). { A = B; }
+assignment_expr(A) ::= unary_expr(B) ASSIGN assignment_expr(C). { A = new_binary_expr(ctx, OP_ASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) MULASSIGN assignment_expr(C). { A = new_binary_expr(ctx, OP_MULASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) DIVASSIGN assignment_expr(C). { A = new_binary_expr(ctx, OP_DIVASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) MODASSIGN assignment_expr(C). { A = new_binary_expr(ctx, OP_MODASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) ADDASSIGN assignment_expr(C). { A = new_binary_expr(ctx, OP_ADDASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) SUBASSIGN assignment_expr(C). { A = new_binary_expr(ctx, OP_SUBASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) LSHIFTASSIGN assignment_expr(C). { A = new_binary_expr(ctx, OP_LSHIFTASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) RSHIFTASSIGN assignment_expr(C). { A = new_binary_expr(ctx, OP_RSHIFTASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) ANDASSIGN assignment_expr(C). { A = new_binary_expr(ctx, OP_ANDASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) XORASSIGN assignment_expr(C). { A = new_binary_expr(ctx, OP_XORASSIGN, B, C); }
+assignment_expr(A) ::= unary_expr(B) ORASSIGN assignment_expr(C). { A = new_binary_expr(ctx, OP_ORASSIGN, B, C); }
+
+%type expression { Expression * }
+expression(A) ::= assignment_expr(B). { A = B; }
+expression(A) ::= expression(B) COMMA assignment_expr(C). { A = new_binary_expr(ctx, OP_COMMA, B, C); }
+
+// end of calculator.lemon ...
+
--- a/mojoshader_internal.h	Mon Feb 08 02:38:19 2010 -0500
+++ b/mojoshader_internal.h	Mon Feb 08 02:42:12 2010 -0500
@@ -88,7 +88,9 @@
 typedef unsigned __int8 uint8;
 typedef unsigned __int16 uint16;
 typedef unsigned __int32 uint32;
+typedef unsigned __int64 uint64;
 typedef __int32 int32;
+typedef __int64 int64;
 // Warning Level 4 considered harmful.  :)
 #pragma warning(disable: 4100)  // "unreferenced formal parameter"
 #pragma warning(disable: 4389)  // "signed/unsigned mismatch"
@@ -98,6 +100,8 @@
 typedef uint16_t uint16;
 typedef uint32_t uint32;
 typedef int32_t int32;
+typedef int64_t int64;
+typedef uint64_t uint64;
 #endif
 
 #ifdef sun