mojoshader_parser_hlsl.lemon
author Ryan C. Gordon <icculus@icculus.org>
Tue, 09 Feb 2010 02:55:38 -0500
branchcalculator-experiment
changeset 827 2f955ce29b7b
parent 796 ab5e4797e0cb
child 836 d975fa785f1e
permissions -rw-r--r--
Moved the calculator experiment work back into the compiler. At least we know the expression parser works! :) Lots of other bits of new infrastructure in there, too.

/**
 * 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.

// HLSL syntax is described, informally, here:
//  http://msdn.microsoft.com/en-us/library/bb509615(VS.85).aspx

%name ParseHLSL

// Some shift-reduce conflicts are basically unavoidable, but if the final
//  conflict count matches this value, we consider it known and acceptable.
%expect 2

%start_symbol shader
%token_prefix TOKEN_HLSL_
%token_type { TokenData }
%extra_argument { Context *ctx }

%include {
#ifndef __MOJOSHADER_HLSL_COMPILER__
#error Do not compile this file directly.
#endif
}

%syntax_error {
    fprintf(stderr,"Syntax error\n");
}

%parse_failure {
    // !!! FIXME: make this a proper fail() function.
    ctx->isfail = 1;
    fprintf(stderr,"Giving up.  Parser is hopelessly lost...\n");
}

%stack_overflow {
    // !!! FIXME: make this a proper fail() function.
    ctx->isfail = 1;
    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 shader { int }                // !!! FIXME: remove this later.
%destructor shader { (void) ctx; }  // !!! FIXME: remove this later.
shader ::= compilation_units.

compilation_units ::= compilation_unit.
compilation_units ::= compilation_units compilation_unit.

compilation_unit ::= function_declaration.
compilation_unit ::= function_definition.
compilation_unit ::= global_variable.
compilation_unit ::= typedef_statement.
compilation_unit ::= struct_statement.

function_declaration ::= function_signature SEMICOLON.

function_definition ::= function_signature statement_block.

function_signature ::= function_storageclass function_details semantic.
function_signature ::= function_storageclass function_details.
function_signature ::= function_details semantic.
function_signature ::= function_details.

function_details ::= datatype IDENTIFIER LPAREN function_arguments RPAREN.
function_details ::= VOID IDENTIFIER LPAREN function_arguments RPAREN.

// !!! FIXME: there is a "target" storage class that is the name of the
// !!! FIXME:  platform that this function is meant for...but I don't know
// !!! FIXME:  what tokens are valid here.

// !!! FIXME: Also, the docs say "one of" inline or target, but I bet you can
// !!! FIXME:  specify both.
//function_storageclass ::= target.
function_storageclass ::= INLINE.

function_arguments ::= VOID.
function_arguments ::= function_argument_list.
function_arguments ::= .

function_argument_list ::= function_argument.
function_argument_list ::= function_argument_list COMMA function_argument.

function_argument ::= input_modifier datatype IDENTIFIER semantic interpolation_mod initializer.
function_argument ::= input_modifier datatype IDENTIFIER semantic interpolation_mod.
function_argument ::= input_modifier datatype IDENTIFIER semantic initializer.
function_argument ::= input_modifier datatype IDENTIFIER semantic.
function_argument ::= input_modifier datatype IDENTIFIER interpolation_mod initializer.
function_argument ::= input_modifier datatype IDENTIFIER interpolation_mod.
function_argument ::= input_modifier datatype IDENTIFIER initializer.
function_argument ::= input_modifier datatype IDENTIFIER.
function_argument ::= datatype IDENTIFIER semantic interpolation_mod initializer.
function_argument ::= datatype IDENTIFIER semantic interpolation_mod.
function_argument ::= datatype IDENTIFIER semantic initializer.
function_argument ::= datatype IDENTIFIER semantic.
function_argument ::= datatype IDENTIFIER interpolation_mod initializer.
function_argument ::= datatype IDENTIFIER interpolation_mod.
function_argument ::= datatype IDENTIFIER initializer.
function_argument ::= datatype IDENTIFIER.

input_modifier ::= IN.
input_modifier ::= INOUT.
input_modifier ::= OUT.
input_modifier ::= IN OUT.
input_modifier ::= OUT IN.
input_modifier ::= UNIFORM.

semantic ::= COLON SEMANTIC.

// DX10 only?
interpolation_mod ::= LINEAR.
interpolation_mod ::= CENTROID.
interpolation_mod ::= NOINTERPOLATION.
interpolation_mod ::= NOPERSPECTIVE.
interpolation_mod ::= SAMPLE.

global_variable ::= variable_declaration.

variable_declaration ::= variable_attribute_list datatype variable_declaration_details_list SEMICOLON.
variable_declaration ::= datatype variable_declaration_details_list SEMICOLON.
variable_declaration ::= struct_declaration scalar_or_array SEMICOLON.

variable_declaration_details_list ::= variable_declaration_details.
variable_declaration_details_list ::= variable_declaration_details_list COMMA variable_declaration_details.

variable_declaration_details ::= scalar_or_array semantic annotations initializer variable_lowlevel.
variable_declaration_details ::= scalar_or_array semantic annotations initializer.
variable_declaration_details ::= scalar_or_array semantic annotations variable_lowlevel.
variable_declaration_details ::= scalar_or_array semantic annotations.
variable_declaration_details ::= scalar_or_array semantic initializer variable_lowlevel.
variable_declaration_details ::= scalar_or_array semantic initializer.
variable_declaration_details ::= scalar_or_array semantic variable_lowlevel.
variable_declaration_details ::= scalar_or_array semantic.
variable_declaration_details ::= scalar_or_array annotations initializer variable_lowlevel.
variable_declaration_details ::= scalar_or_array annotations initializer.
variable_declaration_details ::= scalar_or_array annotations variable_lowlevel.
variable_declaration_details ::= scalar_or_array annotations.
variable_declaration_details ::= scalar_or_array initializer variable_lowlevel.
variable_declaration_details ::= scalar_or_array initializer.
variable_declaration_details ::= scalar_or_array variable_lowlevel.
variable_declaration_details ::= scalar_or_array.

// !!! FIXME: we don't handle full sampler declarations at the moment.

struct_declaration ::= STRUCT IDENTIFIER(A) LBRACE struct_member_list RBRACE.
{
    add_usertype(ctx, A.string);
}

struct_member_list ::= struct_member.
struct_member_list ::= struct_member_list struct_member.

struct_member ::= interpolation_mod struct_member_details.
struct_member ::= struct_member_details.

struct_member_details ::= datatype struct_member_item_list SEMICOLON.

struct_member_item_list ::= scalar_or_array.
struct_member_item_list ::= scalar_or_array semantic.
struct_member_item_list ::= struct_member_item_list COMMA IDENTIFIER.

typedef_statement ::= TYPEDEF CONST datatype scalar_or_array.
typedef_statement ::= TYPEDEF datatype scalar_or_array.

variable_lowlevel ::= packoffset register.
variable_lowlevel ::= packoffset.
variable_lowlevel ::= register.

scalar_or_array ::= IDENTIFIER LBRACKET RBRACKET.
scalar_or_array ::= IDENTIFIER LBRACKET expression RBRACKET.
scalar_or_array ::= IDENTIFIER.

packoffset ::= PACKOFFSET LPAREN IDENTIFIER IDENTIFIER RPAREN.
packoffset ::= PACKOFFSET LPAREN IDENTIFIER RPAREN.

register ::= COLON REGISTER LPAREN IDENTIFIER RPAREN.

annotations ::= LT annotation_list GT.

annotation_list ::= annotation.
annotation_list ::= annotation_list annotation.

annotation ::= datatype_scalar initializer SEMICOLON.

variable_attribute_list ::= variable_attribute.
variable_attribute_list ::= variable_attribute_list variable_attribute.

variable_attribute ::= EXTERN.
variable_attribute ::= NOINTERPOLATION.
variable_attribute ::= SHARED.
variable_attribute ::= STATIC.
variable_attribute ::= UNIFORM.
variable_attribute ::= VOLATILE.
variable_attribute ::= CONST.
variable_attribute ::= ROWMAJOR.
variable_attribute ::= COLUMNMAJOR.

initializer_block_list ::= expression.
initializer_block_list ::= LBRACE initializer_block_list RBRACE.
initializer_block_list ::= initializer_block_list COMMA initializer_block_list.
initializer_block ::= LBRACE initializer_block_list RBRACE.

initializer ::= ASSIGN initializer_block.
initializer ::= ASSIGN expression.

intrinsic_datatype ::= datatype_vector.
intrinsic_datatype ::= datatype_matrix.
intrinsic_datatype ::= datatype_scalar.
intrinsic_datatype ::= datatype_sampler.

datatype ::= intrinsic_datatype.
datatype ::= USERTYPE.

datatype_sampler ::= SAMPLER.
datatype_sampler ::= SAMPLER1D.
datatype_sampler ::= SAMPLER2D.
datatype_sampler ::= SAMPLER3D.
datatype_sampler ::= SAMPLERCUBE.
datatype_sampler ::= SAMPLER_STATE.
datatype_sampler ::= SAMPLERSTATE.
datatype_sampler ::= SAMPLERCOMPARISONSTATE.

datatype_scalar ::= BOOL.
datatype_scalar ::= INT.
datatype_scalar ::= UINT.
datatype_scalar ::= HALF.
datatype_scalar ::= FLOAT.
datatype_scalar ::= DOUBLE.
datatype_scalar ::= STRING.  // this is for the effects framework, not HLSL.
datatype_scalar ::= SNORM FLOAT.
datatype_scalar ::= UNORM FLOAT.
datatype_scalar ::= BUFFER LT datatype_scalar GT.

// !!! FIXME: MSDN suggests that the matrix ones are just typedefs inserted
// !!! FIXME:  before parsing begins, like:
// !!! FIXME: typedef matrix <bool,4,3> bool4x3;
// !!! FIXME:  ...maybe we can rip these out of the grammar and just create
// !!! FIXME:  them at startup?
datatype_vector ::= VECTOR LT datatype_scalar COMMA INT_CONSTANT GT.
datatype_vector ::= BOOL1.
datatype_vector ::= BOOL2.
datatype_vector ::= BOOL3.
datatype_vector ::= BOOL4.
datatype_vector ::= INT1.
datatype_vector ::= INT2.
datatype_vector ::= INT3.
datatype_vector ::= INT4.
datatype_vector ::= UINT1.
datatype_vector ::= UINT2.
datatype_vector ::= UINT3.
datatype_vector ::= UINT4.
datatype_vector ::= HALF1.
datatype_vector ::= HALF2.
datatype_vector ::= HALF3.
datatype_vector ::= HALF4.
datatype_vector ::= FLOAT1.
datatype_vector ::= FLOAT2.
datatype_vector ::= FLOAT3.
datatype_vector ::= FLOAT4.
datatype_vector ::= DOUBLE1.
datatype_vector ::= DOUBLE2.
datatype_vector ::= DOUBLE3.
datatype_vector ::= DOUBLE4.

datatype_matrix ::= MATRIX LT datatype_scalar COMMA INT_CONSTANT COMMA INT_CONSTANT GT.
datatype_matrix ::= BOOL1X1.
datatype_matrix ::= BOOL1X2.
datatype_matrix ::= BOOL1X3.
datatype_matrix ::= BOOL1X4.
datatype_matrix ::= BOOL2X1.
datatype_matrix ::= BOOL2X2.
datatype_matrix ::= BOOL2X3.
datatype_matrix ::= BOOL2X4.
datatype_matrix ::= BOOL3X1.
datatype_matrix ::= BOOL3X2.
datatype_matrix ::= BOOL3X3.
datatype_matrix ::= BOOL3X4.
datatype_matrix ::= BOOL4X1.
datatype_matrix ::= BOOL4X2.
datatype_matrix ::= BOOL4X3.
datatype_matrix ::= BOOL4X4.
datatype_matrix ::= INT1X1.
datatype_matrix ::= INT1X2.
datatype_matrix ::= INT1X3.
datatype_matrix ::= INT1X4.
datatype_matrix ::= INT2X1.
datatype_matrix ::= INT2X2.
datatype_matrix ::= INT2X3.
datatype_matrix ::= INT2X4.
datatype_matrix ::= INT3X1.
datatype_matrix ::= INT3X2.
datatype_matrix ::= INT3X3.
datatype_matrix ::= INT3X4.
datatype_matrix ::= INT4X1.
datatype_matrix ::= INT4X2.
datatype_matrix ::= INT4X3.
datatype_matrix ::= INT4X4.
datatype_matrix ::= UINT1X1.
datatype_matrix ::= UINT1X2.
datatype_matrix ::= UINT1X3.
datatype_matrix ::= UINT1X4.
datatype_matrix ::= UINT2X1.
datatype_matrix ::= UINT2X2.
datatype_matrix ::= UINT2X3.
datatype_matrix ::= UINT2X4.
datatype_matrix ::= UINT3X1.
datatype_matrix ::= UINT3X2.
datatype_matrix ::= UINT3X3.
datatype_matrix ::= UINT3X4.
datatype_matrix ::= UINT4X1.
datatype_matrix ::= UINT4X2.
datatype_matrix ::= UINT4X3.
datatype_matrix ::= UINT4X4.
datatype_matrix ::= HALF1X1.
datatype_matrix ::= HALF1X2.
datatype_matrix ::= HALF1X3.
datatype_matrix ::= HALF1X4.
datatype_matrix ::= HALF2X1.
datatype_matrix ::= HALF2X2.
datatype_matrix ::= HALF2X3.
datatype_matrix ::= HALF2X4.
datatype_matrix ::= HALF3X1.
datatype_matrix ::= HALF3X2.
datatype_matrix ::= HALF3X3.
datatype_matrix ::= HALF3X4.
datatype_matrix ::= HALF4X1.
datatype_matrix ::= HALF4X2.
datatype_matrix ::= HALF4X3.
datatype_matrix ::= HALF4X4.
datatype_matrix ::= FLOAT1X1.
datatype_matrix ::= FLOAT1X2.
datatype_matrix ::= FLOAT1X3.
datatype_matrix ::= FLOAT1X4.
datatype_matrix ::= FLOAT2X1.
datatype_matrix ::= FLOAT2X2.
datatype_matrix ::= FLOAT2X3.
datatype_matrix ::= FLOAT2X4.
datatype_matrix ::= FLOAT3X1.
datatype_matrix ::= FLOAT3X2.
datatype_matrix ::= FLOAT3X3.
datatype_matrix ::= FLOAT3X4.
datatype_matrix ::= FLOAT4X1.
datatype_matrix ::= FLOAT4X2.
datatype_matrix ::= FLOAT4X3.
datatype_matrix ::= FLOAT4X4.
datatype_matrix ::= DOUBLE1X1.
datatype_matrix ::= DOUBLE1X2.
datatype_matrix ::= DOUBLE1X3.
datatype_matrix ::= DOUBLE1X4.
datatype_matrix ::= DOUBLE2X1.
datatype_matrix ::= DOUBLE2X2.
datatype_matrix ::= DOUBLE2X3.
datatype_matrix ::= DOUBLE2X4.
datatype_matrix ::= DOUBLE3X1.
datatype_matrix ::= DOUBLE3X2.
datatype_matrix ::= DOUBLE3X3.
datatype_matrix ::= DOUBLE3X4.
datatype_matrix ::= DOUBLE4X1.
datatype_matrix ::= DOUBLE4X2.
datatype_matrix ::= DOUBLE4X3.
datatype_matrix ::= DOUBLE4X4.

statement_block ::= LBRACE RBRACE.
statement_block ::= LBRACE statement_list RBRACE.

statement_list ::= statement.
statement_list ::= statement_list statement.

// These are for Shader Model 4 and Xbox 360 only, apparently.
statement_attribute_details ::= ISOLATE.
statement_attribute_details ::= MAXINSTRUCTIONCOUNT LPAREN INT_CONSTANT RPAREN.
statement_attribute_details ::= NOEXPRESSIONOPTIMIZATIONS.
statement_attribute_details ::= REMOVEUNUSEDINPUTS.
statement_attribute_details ::= UNUSED.
statement_attribute_details ::= XPS.

statement_attribute ::= LBRACKET statement_attribute_details RBRACKET.

statement ::= return_statement.
statement ::= BREAK SEMICOLON.
statement ::= CONTINUE SEMICOLON.
statement ::= DISCARD SEMICOLON.
statement ::= statement_attribute statement_block.
statement ::= statement_block.
statement ::= for_statement.
statement ::= do_statement.
statement ::= while_statement.
statement ::= if_statement.
statement ::= switch_statement.
statement ::= variable_declaration.
statement ::= typedef_statement.
statement ::= expression_statement.
statement ::= struct_statement.

struct_statement ::= struct_declaration SEMICOLON.

expression_statement ::= SEMICOLON.
expression_statement ::= expression SEMICOLON.

return_statement ::= RETURN SEMICOLON.
return_statement ::= RETURN expression SEMICOLON.

while_statement ::= loop_attribute while_details.
while_statement ::= while_details.

while_details ::= WHILE LPAREN expression RPAREN statement.

for_statement ::= loop_attribute for_details.
for_statement ::= for_details.

for_details ::= FOR LPAREN expression SEMICOLON expression SEMICOLON expression RPAREN statement.
for_details ::= FOR LPAREN SEMICOLON SEMICOLON RPAREN statement.
for_details ::= FOR LPAREN SEMICOLON SEMICOLON expression RPAREN statement.
for_details ::= FOR LPAREN SEMICOLON expression SEMICOLON RPAREN statement.
for_details ::= FOR LPAREN SEMICOLON expression SEMICOLON expression RPAREN statement.
for_details ::= FOR LPAREN expression SEMICOLON SEMICOLON RPAREN statement.
for_details ::= FOR LPAREN expression SEMICOLON SEMICOLON expression RPAREN statement.
for_details ::= FOR LPAREN expression SEMICOLON expression SEMICOLON RPAREN statement.
for_details ::= FOR LPAREN variable_declaration expression SEMICOLON expression RPAREN statement.
for_details ::= FOR LPAREN variable_declaration SEMICOLON RPAREN statement.
for_details ::= FOR LPAREN variable_declaration SEMICOLON expression RPAREN statement.
for_details ::= FOR LPAREN variable_declaration expression SEMICOLON RPAREN statement.

loop_attribute ::= UNROLL LPAREN INT_CONSTANT RPAREN.
loop_attribute ::= UNROLL.
loop_attribute ::= LOOP.

do_statement ::= DO statement WHILE LPAREN expression RPAREN SEMICOLON.

if_statement ::= if_attribute IF LPAREN expression RPAREN statement.
if_statement ::= IF LPAREN expression RPAREN statement.
if_statement ::= if_attribute IF LPAREN expression RPAREN statement ELSE statement.
if_statement ::= IF LPAREN expression RPAREN statement ELSE statement.

if_attribute ::= BRANCH.
if_attribute ::= FLATTEN.

switch_statement ::= switch_attribute switch_details.
switch_statement ::= switch_details.

switch_details ::= SWITCH LPAREN expression RPAREN LBRACE switch_case_list RBRACE.

switch_attribute ::= FLATTEN.
switch_attribute ::= BRANCH.
switch_attribute ::= FORCECASE.
switch_attribute ::= CALL.

switch_case_list ::= switch_case.
switch_case_list ::= switch_case_list switch_case.

// You can do math here, apparently, as long as it produces an int constant.
//  ...so "case 3+2:" works.
switch_case ::= CASE expression COLON statement_list.
switch_case ::= CASE expression COLON.
switch_case ::= DEFAULT COLON statement_list.
switch_case ::= DEFAULT COLON.

// 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.string); }
primary_expr(A) ::= INT_CONSTANT(B). { A = new_literal_int_expr(ctx, B.i64); }
primary_expr(A) ::= FLOAT_CONSTANT(B). { A = new_literal_float_expr(ctx, B.dbl); }
primary_expr(A) ::= STRING_LITERAL(B). { A = new_literal_string_expr(ctx, B.string); }
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.string)); }
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 mojoshader_parser_hlsl.lemon ...