1 // Copyright 2014 Tony Wasserka
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 //       notice, this list of conditions and the following disclaimer.
9 //     * Redistributions in binary form must reproduce the above copyright
10 //       notice, this list of conditions and the following disclaimer in the
11 //       documentation and/or other materials provided with the distribution.
12 //     * Neither the name of the owner nor the names of its contributors may
13 //       be used to endorse or promote products derived from this software
14 //       without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 
29 // Enable this for detailed XML overview of parser results
30 // #define BOOST_SPIRIT_DEBUG
31 
32 #include <boost/fusion/include/adapt_struct.hpp>
33 #include <boost/spirit/include/qi.hpp>
34 
35 #include "nihstro/parser_assembly.h"
36 #include "nihstro/parser_assembly_private.h"
37 
38 #include "nihstro/shader_binary.h"
39 #include "nihstro/shader_bytecode.h"
40 
41 namespace spirit = boost::spirit;
42 namespace qi = boost::spirit::qi;
43 namespace ascii = boost::spirit::qi::ascii;
44 namespace phoenix = boost::phoenix;
45 
46 using spirit::_1;
47 using spirit::_2;
48 using spirit::_3;
49 using spirit::_4;
50 
51 using namespace nihstro;
52 
53 // Adapt parser data structures for use with boost::spirit
54 
55 /*BOOST_FUSION_ADAPT_STRUCT(
56     IntegerWithSign,
57     (int, sign)
58     (unsigned, value)
59 )
60 */
61 BOOST_FUSION_ADAPT_STRUCT(
62     CompareInstruction,
63     (OpCode, opcode)
64     (std::vector<Expression>, arguments)
65     (std::vector<Instruction::Common::CompareOpType::Op>, ops)
66 )
67 
68 template<>
CompareParser(const ParserContext & context)69 CompareParser<ParserIterator>::CompareParser(const ParserContext& context)
70                 : CompareParser::base_type(instruction),
71                   common(context),
72                   opcodes_compare(common.opcodes_compare),
73                   expression(common.expression),
74                   end_of_statement(common.end_of_statement),
75                   diagnostics(common.diagnostics) {
76 
77         // TODO: Will this properly match >= ?
78         compare_ops.add
79                        ( "==", CompareOp::Equal )
80                        ( "!=", CompareOp::NotEqual )
81                        ( "<", CompareOp::LessThan )
82                        ( "<=", CompareOp::LessEqual )
83                        ( ">", CompareOp::GreaterThan )
84                        ( ">=", CompareOp::GreaterEqual );
85 
86         // Setup rules
87 
88         auto comma_rule = qi::lit(',');
89 
90         opcode = qi::no_case[qi::lexeme[opcodes_compare >> &ascii::space]];
91         compare_op = qi::lexeme[compare_ops];
92 
93         // cmp src1, src2, op1, op2
94         // TODO: Also allow "cmp src1 op1 src2, src1 op2 src2"
95         two_ops = compare_op > comma_rule > compare_op;
96         two_expressions = expression > comma_rule > expression;
97         instr[0] = opcode > two_expressions > comma_rule > two_ops;
98 
99         instruction = instr[0] > end_of_statement;
100 
101         // Error handling
102         BOOST_SPIRIT_DEBUG_NODE(instr[0]);
103         BOOST_SPIRIT_DEBUG_NODE(instruction);
104 
105         qi::on_error<qi::fail>(instruction, error_handler(phoenix::ref(diagnostics), _1, _2, _3, _4));
106 }
107