Path: blob/a-new-beginning/SharedDependencies/Sources/nihstro/parser_assembly.cpp
2 views
// Copyright 2014 Tony Wasserka1// All rights reserved.2//3// Redistribution and use in source and binary forms, with or without4// modification, are permitted provided that the following conditions are met:5//6// * Redistributions of source code must retain the above copyright7// notice, this list of conditions and the following disclaimer.8// * Redistributions in binary form must reproduce the above copyright9// notice, this list of conditions and the following disclaimer in the10// documentation and/or other materials provided with the distribution.11// * Neither the name of the owner nor the names of its contributors may12// be used to endorse or promote products derived from this software13// without specific prior written permission.14//15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS16// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT17// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR18// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT19// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,20// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT21// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,22// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY23// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT24// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE25// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.262728// Enable this for detailed XML overview of parser results29// #define BOOST_SPIRIT_DEBUG3031#include <boost/fusion/include/adapt_struct.hpp>32#include <boost/phoenix/core/reference.hpp>33#include <boost/spirit/include/qi.hpp>3435#include "nihstro/parser_assembly.h"36#include "nihstro/parser_assembly_private.h"3738#include "nihstro/shader_binary.h"39#include "nihstro/shader_bytecode.h"4041namespace spirit = boost::spirit;42namespace qi = boost::spirit::qi;43namespace ascii = boost::spirit::qi::ascii;44namespace phoenix = boost::phoenix;4546using spirit::_1;47using spirit::_2;48using spirit::_3;49using spirit::_4;5051using namespace nihstro;5253// Adapt parser data structures for use with boost::spirit5455BOOST_FUSION_ADAPT_STRUCT(56SetEmitInstruction::Flags,57(boost::optional<bool>, primitive_flag)58(boost::optional<bool>, invert_flag)59)6061BOOST_FUSION_ADAPT_STRUCT(62SetEmitInstruction,63(OpCode, opcode)64(unsigned, vertex_id)65(SetEmitInstruction::Flags, flags)66)6768phoenix::function<ErrorHandler> error_handler;6970template<typename Iterator, bool require_end_of_line>71TrivialOpParser<Iterator, require_end_of_line>::TrivialOpParser(const ParserContext& context)72: TrivialOpParser::base_type(trivial_instruction),73common(context),74opcodes_trivial(common.opcodes_trivial),75opcodes_compare(common.opcodes_compare),76opcodes_float(common.opcodes_float),77opcodes_flowcontrol(common.opcodes_flowcontrol),78end_of_statement(common.end_of_statement),79diagnostics(common.diagnostics) {8081// Setup rules82if (require_end_of_line) {83opcode = qi::no_case[qi::lexeme[opcodes_trivial >> &ascii::space]];84trivial_instruction = opcode > end_of_statement;85} else {86opcode = qi::no_case[qi::lexeme[opcodes_trivial | opcodes_compare | opcodes_float[0]87| opcodes_float[1] | opcodes_float[2] | opcodes_float[3]88| opcodes_flowcontrol[0] | opcodes_flowcontrol[1] >> &ascii::space]];89trivial_instruction = opcode;90}9192// Error handling93BOOST_SPIRIT_DEBUG_NODE(opcode);94BOOST_SPIRIT_DEBUG_NODE(trivial_instruction);9596qi::on_error<qi::fail>(trivial_instruction, error_handler(phoenix::ref(diagnostics), _1, _2, _3, _4));97}9899template<typename Iterator>100SetEmitParser<Iterator>::SetEmitParser(const ParserContext& context)101: SetEmitParser::base_type(setemit_instruction),102common(context),103opcodes_setemit(common.opcodes_setemit),104end_of_statement(common.end_of_statement),105diagnostics(common.diagnostics) {106107// Setup rules108109auto comma_rule = qi::lit(',');110111opcode = qi::lexeme[qi::no_case[opcodes_setemit] >> &ascii::space];112113vertex_id = qi::uint_;114prim_flag = qi::lit("prim") >> &(!ascii::alnum) >> qi::attr(true);115inv_flag = qi::lit("inv") >> &(!ascii::alnum) >> qi::attr(true);116flags = ((comma_rule >> prim_flag) ^ (comma_rule >> inv_flag));117118setemit_instruction = ((opcode >> vertex_id) >> (flags | qi::attr(SetEmitInstruction::Flags{}))) > end_of_statement;119120// Error handling121BOOST_SPIRIT_DEBUG_NODE(opcode);122BOOST_SPIRIT_DEBUG_NODE(vertex_id);123BOOST_SPIRIT_DEBUG_NODE(prim_flag);124BOOST_SPIRIT_DEBUG_NODE(inv_flag);125BOOST_SPIRIT_DEBUG_NODE(flags);126BOOST_SPIRIT_DEBUG_NODE(setemit_instruction);127128qi::on_error<qi::fail>(setemit_instruction, error_handler(phoenix::ref(diagnostics), _1, _2, _3, _4));129}130131template<typename Iterator>132LabelParser<Iterator>::LabelParser(const ParserContext& context)133: LabelParser::base_type(label), common(context),134end_of_statement(common.end_of_statement),135identifier(common.identifier),136diagnostics(common.diagnostics) {137138label = identifier >> qi::lit(':') > end_of_statement;139140BOOST_SPIRIT_DEBUG_NODE(label);141142qi::on_error<qi::fail>(label, error_handler(phoenix::ref(diagnostics), _1, _2, _3, _4));143}144template struct LabelParser<ParserIterator>;145146147struct Parser::ParserImpl {148using Iterator = SourceTreeIterator;149150ParserImpl(const ParserContext& context) : label(context), plain_instruction(context),151simple_instruction(context), instruction(context),152compare(context), flow_control(context),153setemit(context), declaration(context) {154}155156unsigned Skip(Iterator& begin, Iterator end) {157unsigned lines_skipped = 0;158do {159parse(begin, end, skipper);160lines_skipped++;161} while (boost::spirit::qi::parse(begin, end, boost::spirit::qi::eol));162163return --lines_skipped;164}165166void SkipSingleLine(Iterator& begin, Iterator end) {167qi::parse(begin, end, *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi));168}169170bool ParseLabel(Iterator& begin, Iterator end, StatementLabel* content) {171assert(content != nullptr);172173return phrase_parse(begin, end, label, skipper, *content);174}175176bool ParseOpCode(Iterator& begin, Iterator end, OpCode* content) {177assert(content != nullptr);178179return phrase_parse(begin, end, plain_instruction, skipper, *content);180}181182bool ParseSimpleInstruction(Iterator& begin, Iterator end, OpCode* content) {183assert(content != nullptr);184185return phrase_parse(begin, end, simple_instruction, skipper, *content);186}187188bool ParseFloatOp(Iterator& begin, Iterator end, FloatOpInstruction* content) {189assert(content != nullptr);190191return phrase_parse(begin, end, instruction, skipper, *content);192}193194bool ParseCompare(Iterator& begin, Iterator end, CompareInstruction* content) {195assert(content != nullptr);196197return phrase_parse(begin, end, compare, skipper, *content);198}199200bool ParseFlowControl(Iterator& begin, Iterator end, FlowControlInstruction* content) {201assert(content != nullptr);202203return phrase_parse(begin, end, flow_control, skipper, *content);204}205206bool ParseSetEmit(Iterator& begin, Iterator end, SetEmitInstruction* content) {207assert(content != nullptr);208209return phrase_parse(begin, end, setemit, skipper, *content);210}211212bool ParseDeclaration(Iterator& begin, Iterator end, StatementDeclaration* content) {213assert(content != nullptr);214215return phrase_parse(begin, end, declaration, skipper, *content);216}217218private:219AssemblySkipper<Iterator> skipper;220221LabelParser<Iterator> label;222TrivialOpParser<Iterator, false> plain_instruction;223TrivialOpParser<Iterator, true> simple_instruction;224FloatOpParser<Iterator> instruction;225CompareParser<Iterator> compare;226FlowControlParser<Iterator> flow_control;227SetEmitParser<Iterator> setemit;228DeclarationParser<Iterator> declaration;229};230231232233Parser::Parser(const ParserContext& context) : impl(new ParserImpl(context)) {234};235236Parser::~Parser() {237}238239unsigned Parser::Skip(Iterator& begin, Iterator end) {240return impl->Skip(begin, end);241}242243void Parser::SkipSingleLine(Iterator& begin, Iterator end) {244impl->SkipSingleLine(begin, end);245}246247bool Parser::ParseLabel(Iterator& begin, Iterator end, StatementLabel* label) {248return impl->ParseLabel(begin, end, label);249}250251bool Parser::ParseOpCode(Iterator& begin, Iterator end, OpCode* opcode) {252return impl->ParseOpCode(begin, end, opcode);253}254255bool Parser::ParseSimpleInstruction(Iterator& begin, Iterator end, OpCode* opcode) {256return impl->ParseSimpleInstruction(begin, end, opcode);257}258259bool Parser::ParseFloatOp(Iterator& begin, Iterator end, FloatOpInstruction* instruction) {260return impl->ParseFloatOp(begin, end, instruction);261}262263bool Parser::ParseCompare(Iterator& begin, Iterator end, CompareInstruction* content) {264return impl->ParseCompare(begin, end, content);265}266267bool Parser::ParseFlowControl(Iterator& begin, Iterator end, FlowControlInstruction* content) {268return impl->ParseFlowControl(begin, end, content);269}270271bool Parser::ParseSetEmit(Iterator& begin, Iterator end, SetEmitInstruction* content) {272return impl->ParseSetEmit(begin, end, content);273}274275bool Parser::ParseDeclaration(Iterator& begin, Iterator end, StatementDeclaration* declaration) {276return impl->ParseDeclaration(begin, end, declaration);277}278279280