主頁 > 軟體工程 > boostSpiritx3語法中匹配的錯誤規則

boostSpiritx3語法中匹配的錯誤規則

2021-10-22 08:34:31 軟體工程

我是一個使用 Spirit 的新手。

我正在嘗試使用精神 x3 從一個簡單的“excel”公式構建一個 AST 樹。語法支持典型的運算子( 、-、*、/)、函式(myfunc(myparam1, myparam2))和單元格參考(例如A1、AA234)。

因此,要決議的示例運算式可能是 A1 sin(A2 3)。

問題是下面的 xlreference 規則永遠不會匹配,因為 xlfunction 規則優先并且規則不會回溯。我已經嘗試過expect,但我缺乏一些很好的例子來讓它繼續下去。

我想這會引出另一個與除錯 x3 的最佳方法有關的問題。我已經看到了 BOOST_SPIRIT_X3_DEBUG 定義,但我找不到任何證明它的用法的例子。我還在 expression_class 上寫了一個 on_error 方法,但這并沒有提供很好的跟蹤。我曾嘗試使用位置標記和 with 陳述句,但這也沒有提供足夠的資訊。

任何幫助,將不勝感激!

x3::rule<class xlreference, ast::xlreference> const   xlreference{"xlreference"};
auto const xlreference_def =  alpha  > x3::uint_ > !x3::expect[char('(')];
BOOST_SPIRIT_DEFINE(xlreference);

struct identifier_class;
typedef x3::rule<identifier_class, std::string> identifier_type;
identifier_type const identifier = "identifier";
auto const identifier_def = x3::char_("a-zA-Z") > *(x3::char_("a-zA-Z") | x3::char_('_')) > !x3::expect[char('0-9')];
BOOST_SPIRIT_DEFINE(identifier);


auto const expression_def = // constadditive_expr_def 
    term [print_action()]
    >> *(   (char_(' ') > term)
        |   (char_('-') > term)
        )
    ;

x3::rule<xlfunction_class, ast::xlfunction> const xlfunction("xlfunction");
auto const xlfunction_def = identifier > '(' > *(expression > *(',' > expression)) > ')';
BOOST_SPIRIT_DEFINE(xlfunction);

    

auto const term_def = //constmultiplicative_expr_def 
    factor 
    >> *(   (char_('*') > factor) 
        |   (char_('/') > factor) 
        )
    ;



auto const factor_def = // constunary_expr_def 
    xlfunction [print_action()]
    |   '(' > expression > ')' 
    |   (char_('-') > factor) 
    |   (char_(' ') > factor) 
    | x3::double_  [print_action()] | xlreference [print_action()]
    ;

錯誤處理程式:

    struct expression_class //: x3::annotate_on_success
{
    //  Our error handler
    template <typename Iterator, typename Exception, typename Context>
    x3::error_handler_result
    on_error(Iterator& q, Iterator const& last, Exception const& x, Context const& context)
    {
        std::cout
            << "Error! Expecting: "
            << x.which()
            << " here: \""
            << std::string(x.where(), last)
            << "\""
            << std::endl
            ;
        return x3::error_handler_result::fail;
    }
};

位置標簽:

    with<position_cache_tag>(std::ref(positions))
[
    client::calculator_grammar::expression
];
client::ast::program ast;
bool r = phrase_parse(iter, (iterator_type const ) str.end(), parser, x3::space, ast);
if (!r) {
    std::cout << "failed:" << str << "\n";
}

uj5u.com熱心網友回復:

好的,一步一步地進行審查。一路組成 AST 型別(因為你不想展示)。

  1. 這是無效代碼:char('0-9')那是寬字符文字嗎?啟用編譯器警告!您可能的意思是x3::char_("0-9")(兩個重要的區別!)。

  2. !x3::expect[]是矛盾的。您永遠無法通過該條件,因為!斷言前瞻不匹配,而expect[]需要匹配。因此,最好的情況是!失敗,因為expect[]-ation 是匹配的。最壞的情況是expect[]拋出例外,因為你要求它。

  3. operator >已經是一個期待點。由于與以前相同的原因> !p是矛盾的。做了>> !p

  4. 替換char_("0-9")x3::digit

  5. 替換char_("a-zA-Z")x3::alpha

  6. 一些(許多)規則需要是詞素。那是因為您在船長背景關系(phrase_parsewith x3::space)中呼叫了語法你的識別符號會默默地吃空白,因為你沒有讓它們成為詞素。請參閱提升精神船長問題

  7. 否定前瞻斷言不公開屬性,因此! char_('(')可以(應該?)! lit('(')

  8. 語意動作的存在(默認情況下)會抑制屬性傳播 - 因此print_action()會導致屬性傳播停止

  9. operator>定義的期望點 ( ) 不能回溯。這就是他們期望值的原因

  10. 使用與 kleene-star 組合的 List 運算子:p >> *(',' >> p)->p % ','

  11. 那個額外的 kleene-star 是假的。您的意思是將引數串列設為可選嗎?那是-(expression % ',')

  12. 鏈接運算子規則使得獲取 ast 變得有點麻煩

  13. 簡化

    factor >> *((x3::char_('*') > factor) //
               | (x3::char_('/') > factor));
    

    只是 factor >> *(x3::char_("*/") >> factor);

  14. factor_def邏輯上匹配什么expression

第一次審查通過產生:

auto const xlreference_def =
    x3::lexeme[ x3::alpha >> x3::uint_] >> !x3::char_('(');

auto const identifier_def =
    x3::raw[x3::lexeme[x3::alpha >> *(x3::alpha | '_') >> !x3::digit]];

auto const xlfunction_def = identifier >> '(' >> -(expression % ',') >> ')';

auto const term_def = factor >> *(x3::char_("*/") >> factor);

auto const factor_def = xlfunction //
    | '(' >> expression >> ')'     //
    | x3::double_                  //
    | xlreference;

auto const expression_def = term >> *(x3::char_("- ") >> term);

更多觀察:

  1. (iterator_type const)str.end()?? 永遠不要使用 C 風格的強制轉換。事實上,只要使用str.cend()或事實上str.end(),如果str是適當的const反正。

  2. phrase_parse - 考慮不要讓船長成為來電者的決定,因為它在邏輯上是你語法的一部分

  3. 多種excel運算式沒有決議:A:A、$A4、B$4、所有單元格區域;我認為通常也支持 R1C1

魔法仙塵的時間

因此,憑借豐富的經驗,我要去 Crystall Ball? 一些 AST?:

namespace client::ast {
    using identifier = std::string;
    //using identifier = boost::iterator_range<std::string::const_iterator>;
    
    struct string_literal  : std::string {
        using std::string::string;
        using std::string::operator=;

        friend std::ostream& operator<<(std::ostream& os, string_literal const& sl) {
            return os << std::quoted(sl) ;
        }
    };

    struct xlreference {
        std::string colname;
        size_t      rownum;
    };

    struct xlfunction; // fwd
    struct binary_op;  // fwd

    using expression = boost::variant<        //
        double,                               //
        string_literal,                       //
        identifier,                           //
        xlreference,                          //
        boost::recursive_wrapper<xlfunction>, //
        boost::recursive_wrapper<binary_op>   //
        >;

    struct xlfunction{
        identifier              name;
        std::vector<expression> args;

        friend std::ostream& operator<<(std::ostream& os, xlfunction const& xlf)
        {
            os << xlf.name << "(";
            char const* sep = "";
            for (auto& arg : xlf.args)
                os << std::exchange(sep, ", ") << arg;
            return os;
        }
    };

    struct binary_op {
        struct chained_t {
            char       op;
            expression e;
        };
        expression             lhs;
        std::vector<chained_t> chained;

        friend std::ostream& operator<<(std::ostream& os, binary_op const& bop)
        {
            os << "(" << bop.lhs;
            for (auto& rhs : bop.chained)
            os << rhs.op << rhs.e;
            return os << ")";
        }
    };

    using program = expression;
    using boost::fusion::operator<<;
} // namespace client::ast

我們迅速適應:

BOOST_FUSION_ADAPT_STRUCT(client::ast::xlfunction, name, args)
BOOST_FUSION_ADAPT_STRUCT(client::ast::xlreference, colname, rownum)
BOOST_FUSION_ADAPT_STRUCT(client::ast::binary_op, lhs, chained)
BOOST_FUSION_ADAPT_STRUCT(client::ast::binary_op::chained_t, op, e)

接下來,讓我們宣告合適的規則:

x3::rule<struct identifier_class, ast::identifier>  const identifier{"identifier"};
x3::rule<struct xlreference,      ast::xlreference> const xlreference{"xlreference"};
x3::rule<struct xlfunction_class, ast::xlfunction>  const xlfunction{"xlfunction"};
x3::rule<struct factor_class,     ast::expression>  const factor{"factor"};
x3::rule<struct expression_class, ast::binary_op>   const expression{"expression"};
x3::rule<struct term_class,       ast::binary_op>   const term{"term"};

其中需要定義:

auto const xlreference_def =
    x3::lexeme[ x3::alpha >> x3::uint_] /*>> !x3::char_('(')*/;

請注意,前瞻斷言 ( !) 實際上并未更改決議結果,因為任何單元格參考無論如何都不是有效識別符號,因此 () 將保持未決議狀態。

auto const identifier_def =
    x3::raw[x3::lexeme[x3::alpha >> *(x3::alpha | '_') /*>> !x3::digit*/]];

同樣在這里。剩余的輸入將在x3::eoi 稍后進行檢查

我輸入了一個字串文字,因為任何 Excel 克隆都會有一個:

auto const string_literal =
    x3::rule<struct _, ast::string_literal>{"string_literal"} //
= x3::lexeme['"' > *('\\' >> x3::char_ | ~x3::char_('"')) > '"'];

Note that this demonstrates that non-recursive, locally-defined rules don't need separate definitions.

Then come the expression rules

auto const factor_def =        //
    xlfunction                 //
    | '(' >> expression >> ')' //
    | x3::double_              //
    | string_literal           //
    | xlreference              //
    | identifier               //
    ;

I'd usually call this "simple expression" instead of factor.

auto const term_def       = factor >> *(x3::char_("*/") >>  factor);
auto const expression_def = term >> *(x3::char_("- ") >> term);
auto const xlfunction_def = identifier >> '(' >> -(expression % ',') >> ')';

Straight-forward mappings to the AST.

BOOST_SPIRIT_DEFINE(xlreference)
BOOST_SPIRIT_DEFINE(identifier)
BOOST_SPIRIT_DEFINE(xlfunction)
BOOST_SPIRIT_DEFINE(term)
BOOST_SPIRIT_DEFINE(factor)
BOOST_SPIRIT_DEFINE(expression)

'Nuff said. Now comes a bit of cargo cult - remnants of code both unshown and unused, which I'll mostly just accept and ignore here:

int main() {
    std::vector<int> positions; // TODO

    auto parser = x3::with<struct position_cache_tag /*TODO*/>        //
        (std::ref(positions))                                         //
            [                                                         //
                x3::skip(x3::space)[                                  //
                    client::calculator_grammar::expression >> x3::eoi //
    ]                                                                 //
    ];

DO NOTE though that x3::eoi makes it so the rule doesn't match if end of input (modulo skipper) isn't reached.

Now, let's add some test cases!

struct {
    std::string              category;
    std::vector<std::string> cases;
} test_table[] = {
    {
        "xlreference",
        {"A1", "A1111", "AbCdZ9876543", "i9", "i0"},
    },
    {
        "identifier",
        {"i", "id", "id_entifier"},
    },
    {
        "number",
        {"123", "inf", "-inf", "NaN", ".99e34", "1e-8", "1.e-8", " 9"},
    },
    {
        "binaries",
        {                                                       //
         "3 4", "3*4",                                          //
         "3 4 5", "3*4*5", "3 4*5", "3*4 5", "3*4 5",           //
         "3 (4 5)", "3*(4*5)", "3 (4*5)", "3*(4 5)", "3*(4 5)", //
         "(3 4) 5", "(3*4)*5", "(3 4)*5", "(3*4) 5", "(3*4) 5"},
    },
    {
        "xlfunction",
        {
            "pi()",
            "sin(4)",
            R"--(IIF(A1, "Red", "Green"))--",
        },
    },
    {
        "invalid",
        {
            "A9()", // an xlreference may not be followed by ()
            "",     // you didn't specify
        },
    },
    {
        "other",
        {
            "A-9",    // 1-letter identifier and binary operation
            "1    9", // unary plus accepted in number rule
        },
    },
    {
        "question",
        {
            "myfunc(myparam1, myparam2)",
            "A1",
            "AA234",
            "A1   sin(A2 3)",
        },
    },
};

And run them:

for (auto& [cat, cases] : test_table) {
    for (std::string const& str : cases) {
        auto iter = begin(str), last(end(str));
        std::cout << std::setw(12) << cat << ": ";

        client::ast::program ast;
        if (parse(iter, last, parser, ast)) {
            std::cout << "parsed: " << ast;
        } else {
            std::cout << "failed: " << std::quoted(str);
        }

        if (iter == last) {
            std::cout << "\n";
        } else {
            std::cout << " unparsed: "
                      << std::quoted(std::string_view(iter, last)) << "\n";
        }
    }
}

Live Demo

Live On Coliru

//#define BOOST_SPIRIT_X3_DEBUG
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/position_tagged.hpp>
#include <boost/spirit/home/x3/support/utility/annotate_on_success.hpp>
#include <iostream>
#include <iomanip>
#include <map>
namespace x3 = boost::spirit::x3;

namespace client::ast {
    using identifier = std::string;
    //using identifier = boost::iterator_range<std::string::const_iterator>;
    
    struct string_literal  : std::string {
        using std::string::string;
        using std::string::operator=;

        friend std::ostream& operator<<(std::ostream& os, string_literal const& sl) {
            return os << std::quoted(sl) ;
        }
    };

    struct xlreference {
        std::string colname;
        size_t      rownum;
    };

    struct xlfunction; // fwd
    struct binary_op;  // fwd

    using expression = boost::variant<        //
        double,                               //
        string_literal,                       //
        identifier,                           //
        xlreference,                          //
        boost::recursive_wrapper<xlfunction>, //
        boost::recursive_wrapper<binary_op>   //
        >;

    struct xlfunction{
        identifier              name;
        std::vector<expression> args;

        friend std::ostream& operator<<(std::ostream& os, xlfunction const& xlf)
        {
            os << xlf.name << "(";
            char const* sep = "";
            for (auto& arg : xlf.args)
                os << std::exchange(sep, ", ") << arg;
            return os;
        }
    };

    struct binary_op {
        struct chained_t {
            char       op;
            expression e;
        };
        expression             lhs;
        std::vector<chained_t> chained;

        friend std::ostream& operator<<(std::ostream& os, binary_op const& bop)
        {
            os << "(" << bop.lhs;
            for (auto& rhs : bop.chained)
            os << rhs.op << rhs.e;
            return os << ")";
        }
    };

    using program = expression;
    using boost::fusion::operator<<;
} // namespace client::ast

BOOST_FUSION_ADAPT_STRUCT(client::ast::xlfunction, name, args)
BOOST_FUSION_ADAPT_STRUCT(client::ast::xlreference, colname, rownum)
BOOST_FUSION_ADAPT_STRUCT(client::ast::binary_op, lhs, chained)
BOOST_FUSION_ADAPT_STRUCT(client::ast::binary_op::chained_t, op, e)

namespace client::calculator_grammar {
    struct expression_class //: x3::annotate_on_success
    {
        //  Our error handler
        template <typename Iterator, typename Exception, typename Context>
        x3::error_handler_result on_error(Iterator& q, Iterator const& last,
                                          Exception const& x,
                                          Context const&   context)
        {
            std::cout                                          //
                << "Error! Expecting: " << x.which()           //
                << " here: \"" << std::string(x.where(), last) //
                << "\"" << std::endl;

            return x3::error_handler_result::fail;
        }
    };

    x3::rule<struct identifier_class, ast::identifier>  const identifier{"identifier"};
    x3::rule<struct xlreference,      ast::xlreference> const xlreference{"xlreference"};
    x3::rule<struct xlfunction_class, ast::xlfunction>  const xlfunction{"xlfunction"};
    x3::rule<struct factor_class,     ast::expression>  const factor{"factor"};
    x3::rule<struct expression_class, ast::binary_op>   const expression{"expression"};
    x3::rule<struct term_class,       ast::binary_op>   const term{"term"};

    auto const xlreference_def =
        x3::lexeme[ x3::alpha >> x3::uint_] /*>> !x3::char_('(')*/;

    auto const identifier_def =
        x3::raw[x3::lexeme[x3::alpha >> *(x3::alpha | '_') /*>> !x3::digit*/]];

    auto const string_literal =
        x3::rule<struct _, ast::string_literal>{"string_literal"} //
    = x3::lexeme['"' > *('\\' >> x3::char_ | ~x3::char_('"')) > '"'];

    auto const factor_def =        //
        xlfunction                 //
        | '(' >> expression >> ')' //
        | x3::double_              //
        | string_literal           //
        | xlreference              //
        | identifier               //
        ;

    auto const term_def       = factor >> *(x3::char_("*/") >>  factor);
    auto const expression_def = term >> *(x3::char_("- ") >> term);
    auto const xlfunction_def = identifier >> '(' >> -(expression % ',') >> ')';

    BOOST_SPIRIT_DEFINE(xlreference)
    BOOST_SPIRIT_DEFINE(identifier)
    BOOST_SPIRIT_DEFINE(xlfunction)
    BOOST_SPIRIT_DEFINE(term)
    BOOST_SPIRIT_DEFINE(factor)
    BOOST_SPIRIT_DEFINE(expression)

} // namespace client::calculator_grammar

int main() {
    std::vector<int> positions; // TODO

    auto parser = x3::with<struct position_cache_tag /*TODO*/>        //
        (std::ref(positions))                                         //
            [                                                         //
                x3::skip(x3::space)[                                  //
                    client::calculator_grammar::expression >> x3::eoi //
    ]                                                                 //
    ];

    struct {
        std::string              category;
        std::vector<std::string> cases;
    } test_table[] = {
        {
            "xlreference",
            {"A1", "A1111", "AbCdZ9876543", "i9", "i0"},
        },
        {
            "identifier",
            {"i", "id", "id_entifier"},
        },
        {
            "number",
            {"123", "inf", "-inf", "NaN", ".99e34", "1e-8", "1.e-8", " 9"},
        },
        {
            "binaries",
            {                                                       //
             "3 4", "3*4",                                          //
             "3 4 5", "3*4*5", "3 4*5", "3*4 5", "3*4 5",           //
             "3 (4 5)", "3*(4*5)", "3 (4*5)", "3*(4 5)", "3*(4 5)", //
             "(3 4) 5", "(3*4)*5", "(3 4)*5", "(3*4) 5", "(3*4) 5"},
        },
        {
            "xlfunction",
            {
                "pi()",
                "sin(4)",
                R"--(IIF(A1, "Red", "Green"))--",
            },
        },
        {
            "invalid",
            {
                "A9()", // an xlreference may not be followed by ()
                "",     // you didn't specify
            },
        },
        {
            "other",
            {
                "A-9",    // 1-letter identifier and binary operation
                "1    9", // unary plus accepted in number rule
            },
        },
        {
            "question",
            {
                "myfunc(myparam1, myparam2)",
                "A1",
                "AA234",
                "A1   sin(A2 3)",
            },
        },
    };

    for (auto& [cat, cases] : test_table) {
        for (std::string const& str : cases) {
            auto iter = begin(str), last(end(str));
            std::cout << std::setw(12) << cat << ": ";

            client::ast::program ast;
            if (parse(iter, last, parser, ast)) {
                std::cout << "parsed: " << ast;
            } else {
                std::cout << "failed: " << std::quoted(str);
            }

            if (iter == last) {
                std::cout << "\n";
            } else {
                std::cout << " unparsed: "
                          << std::quoted(std::string_view(iter, last)) << "\n";
            }
        }
    }
}

Prints

 xlreference: parsed: (((A 1)))
 xlreference: parsed: (((A 1111)))
 xlreference: parsed: (((AbCdZ 9876543)))
 xlreference: parsed: (((i 9)))
 xlreference: parsed: (((i 0)))
  identifier: parsed: ((i))
  identifier: parsed: ((id))
  identifier: parsed: ((id_entifier))
      number: parsed: ((123))
      number: parsed: ((inf))
      number: parsed: ((-inf))
      number: parsed: ((nan))
      number: parsed: ((9.9e 33))
      number: parsed: ((1e-08))
      number: parsed: ((1e-08))
      number: parsed: ((9))
    binaries: parsed: ((3) (4))
    binaries: parsed: ((3*4))
    binaries: parsed: ((3) (4) (5))
    binaries: parsed: ((3*4*5))
    binaries: parsed: ((3) (4*5))
    binaries: parsed: ((3*4) (5))
    binaries: parsed: ((3*4) (5))
    binaries: parsed: ((3) (((4) (5))))
    binaries: parsed: ((3*((4*5))))
    binaries: parsed: ((3) (((4*5))))
    binaries: parsed: ((3*((4) (5))))
    binaries: parsed: ((3*((4) (5))))
    binaries: parsed: ((((3) (4))) (5))
    binaries: parsed: ((((3*4))*5))
    binaries: parsed: ((((3) (4))*5))
    binaries: parsed: ((((3*4))) (5))
    binaries: parsed: ((((3*4))) (5))
  xlfunction: parsed: ((pi())
  xlfunction: parsed: ((sin(((4))))
  xlfunction: parsed: ((IIF((((A 1))), (("Red")), (("Green"))))
     invalid: failed: "A9()" unparsed: "A9()"
     invalid: failed: ""
       other: parsed: ((A)-(9))
       other: parsed: ((1) (9))
    question: parsed: ((myfunc((((myparam 1))), (((myparam 2)))))
    question: parsed: (((A 1)))
    question: parsed: (((AA 234)))
    question: parsed: (((A 1)) (sin((((A 2)) (3))))

The only two failed lines are as expected

DEBUG?

Simply uncomment

#define BOOST_SPIRIT_X3_DEBUG

And be slammed with additional noise:

    question: <expression>
  <try>A1   sin(A2 3)</try>
  <term>
    <try>A1   sin(A2 3)</try>
    <factor>
      <try>A1   sin(A2 3)</try>
      <xlfunction>
        <try>A1   sin(A2 3)</try>
        <identifier>
          <try>A1   sin(A2 3)</try>
          <success>1   sin(A2 3)</success>
          <attributes>[A]</attributes>
        </identifier>
        <fail/>
      </xlfunction>
      <string_literal>
        <try>A1   sin(A2 3)</try>
        <fail/>
      </string_literal>
      <xlreference>
        <try>A1   sin(A2 3)</try>
        <success>   sin(A2 3)</success>
        <attributes>[[A], 1]</attributes>
      </xlreference>
      <success>   sin(A2 3)</success>
      <attributes>[[A], 1]</attributes>
    </factor>
    <success>   sin(A2 3)</success>
    <attributes>[[[A], 1], []]</attributes>
  </term>
  <term>
    <try> sin(A2 3)</try>
    <factor>
      <try> sin(A2 3)</try>
      <xlfunction>
        <try> sin(A2 3)</try>
        <identifier>
          <try> sin(A2 3)</try>
          <success>(A2 3)</success>
          <attributes>[s, i, n]</attributes>
        </identifier>
        <expression>
          <try>A2 3)</try>
          <term>
            <try>A2 3)</try>
            <factor>
              <try>A2 3)</try>
              <xlfunction>
                <try>A2 3)</try>
                <identifier>
                  <try>A2 3)</try>
                  <success>2 3)</success>
                  <attributes>[A]</attributes>
                </identifier>
                <fail/>
              </xlfunction>
              <string_literal>
                <try>A2 3)</try>
                <fail/>
              </string_literal>
              <xlreference>
                <try>A2 3)</try>
                <success> 3)</success>
                <attributes>[[A], 2]</attributes>
              </xlreference>
              <success> 3)</success>
              <attributes>[[A], 2]</attributes>
            </factor>
            <success> 3)</success>
            <attributes>[[[A], 2], []]</attributes>
          </term>
          <term>
            <try>3)</try>
            <factor>
              <try>3)</try>
              <xlfunction>
                <try>3)</try>
                <identifier>
                  <try>3)</try>
                  <fail/>
                </identifier>
                <fail/>
              </xlfunction>
              <success>)</success>
              <attributes>3</attributes>
            </factor>
            <success>)</success>
            <attributes>[3, []]</attributes>
          </term>
          <success>)</success>
          <attributes>[[[[A], 2], []], [[ , [3, []]]]]</attributes>
        </expression>
        <success></success>
        <attributes>[[s, i, n], [[[[[A], 2], []], [[ , [3, []]]]]]]</attributes>
      </xlfunction>
      <success></success>
      <attributes>[[s, i, n], [[[[[A], 2], []], [[ , [3, []]]]]]]</attributes>
    </factor>
    <success></success>
    <attributes>[[[s, i, n], [[[[[A], 2], []], [[ , [3, []]]]]]], []]</attributes>
  </term>
  <success></success>
  <attributes>[[[[A], 1], []], [[ , [[[s, i, n], [[[[[A], 2], []], [[ , [3, []]]]]]], []]]]]</attributes>
</expression>
parsed: (((A 1)) (sin((((A 2)) (3))))

轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/330410.html

標籤:C 促进 振奋精神 升压精神-x3

上一篇:UWPTabView以編程方式更改選項卡

下一篇:簡化嵌套的for回圈

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • Git本地庫既關聯GitHub又關聯Gitee

    創建代碼倉庫 使用gitee舉例(github和gitee差不多) 1.在gitee右上角點擊+,選擇新建倉庫 ? 2.選擇填寫倉庫資訊,然后進行創建 ? 3.服務端已經準備好了,本地開始作準備 (1)Git 全域設定 git config --global user.name "成鈺" git c ......

    uj5u.com 2020-09-10 05:04:14 more
  • CODING DevOps 代碼質量實戰系列第二課,相約周三

    隨著 ToB(企業服務)的興起和 ToC(消費互聯網)產品進入成熟期,線上故障帶來的損失越來越大,代碼質量越來越重要,而「質量內建」正是 DevOps 核心理念之一。**《DevOps 代碼質量實戰(PHP 版)》**為 CODING DevOps 代碼質量實戰系列的第二課,同時也是本系列的 PHP ......

    uj5u.com 2020-09-10 05:07:43 more
  • 推薦Scrum書籍

    推薦Scrum書籍 直接上干貨,推薦書籍清單如下(推薦有順序的哦) Scrum指南 Scrum精髓 Scrum敏捷軟體開發 Scrum捷徑 硝煙中的Scrum和XP : 我們如何實施Scrum 敏捷軟體開發:Scrum實戰指南 Scrum要素 大規模Scrum:大規模敏捷組織的設計 用戶故事地圖 用 ......

    uj5u.com 2020-09-10 05:07:45 more
  • CODING DevOps 代碼質量實戰系列最后一課,周四發車

    隨著 ToB(企業服務)的興起和 ToC(消費互聯網)產品進入成熟期,線上故障帶來的損失越來越大,代碼質量越來越重要,而「質量內建」正是 DevOps 核心理念之一。 **《DevOps 代碼質量實戰(Java 版)》**為 CODING DevOps 代碼質量實戰系列的最后一課,同時也是本系列的 ......

    uj5u.com 2020-09-10 05:07:52 more
  • 敏捷軟體工程實踐書籍

    Scrum轉型想要做好,第一步先了解并真正落實Scrum,那么我推薦的Scrum書籍是要看懂并實踐的。第二步是團隊的工程實踐要做扎實。 下面推薦工程實踐書單: 重構:改善既有代碼的設計 決議極限編程 : 擁抱變化 代碼整潔代碼 程式員的職業素養 修改代碼的藝術 撰寫可讀代碼的藝術 測驗驅動開發 : ......

    uj5u.com 2020-09-10 05:07:55 more
  • Jenkins+svn+nginx實作windows環境自動部署vue前端專案

    前面文章介紹了Jenkins+svn+tomcat實作自動化部署,現在終于有空抽時間出來寫下Jenkins+svn+nginx實作自動部署vue前端專案。 jenkins的安裝和配置已經在前面文章進行介紹,下面介紹實作vue前端專案需要進行的哪些額外的步驟。 注意:在安裝jenkins和nginx的 ......

    uj5u.com 2020-09-10 05:08:49 more
  • CODING DevOps 微服務專案實戰系列第一課,明天等你

    CODING DevOps 微服務專案實戰系列第一課**《DevOps 微服務專案實戰:DevOps 初體驗》**將由 CODING DevOps 開發工程師 王寬老師 向大家介紹 DevOps 的基本理念,并探討為什么現代開發活動需要 DevOps,同時將以 eShopOnContainers 項 ......

    uj5u.com 2020-09-10 05:09:14 more
  • CODING DevOps 微服務專案實戰系列第二課來啦!

    近年來,工程專案的結構越來越復雜,需要接入合適的持續集成流水線形式,才能滿足更多變的需求,那么如何優雅地使用 CI 能力提升生產效率呢?CODING DevOps 微服務專案實戰系列第二課 《DevOps 微服務專案實戰:CI 進階用法》 將由 CODING DevOps 全堆疊工程師 何晨哲老師 向 ......

    uj5u.com 2020-09-10 05:09:33 more
  • CODING DevOps 微服務專案實戰系列最后一課,周四開講!

    隨著軟體工程越來越復雜化,如何在 Kubernetes 集群進行灰度發布成為了生產部署的”必修課“,而如何實作安全可控、自動化的灰度發布也成為了持續部署重點關注的問題。CODING DevOps 微服務專案實戰系列最后一課:**《DevOps 微服務專案實戰:基于 Nginx-ingress 的自動 ......

    uj5u.com 2020-09-10 05:10:00 more
  • CODING 儀表盤功能正式推出,實作作業資料可視化!

    CODING 儀表盤功能現已正式推出!該功能旨在用一張張統計卡片的形式,統計并展示使用 CODING 中所產生的資料。這意味著無需額外的設定,就可以收集歸納寶貴的作業資料并予之量化分析。這些海量的資料皆會以圖表或串列的方式躍然紙上,方便團隊成員隨時查看各專案的進度、狀態和指標,云端協作迎來真正意義上 ......

    uj5u.com 2020-09-10 05:11:01 more
最新发布
  • windows系統git使用ssh方式和gitee/github進行同步

    使用git來clone專案有兩種方式:HTTPS和SSH:
    HTTPS:不管是誰,拿到url隨便clone,但是在push的時候需要驗證用戶名和密碼;
    SSH:clone的專案你必須是擁有者或者管理員,而且需要在clone前添加SSH Key。SSH 在push的時候,是不需要輸入用戶名的,如果配置... ......

    uj5u.com 2023-04-19 08:41:12 more
  • windows系統git使用ssh方式和gitee/github進行同步

    使用git來clone專案有兩種方式:HTTPS和SSH:
    HTTPS:不管是誰,拿到url隨便clone,但是在push的時候需要驗證用戶名和密碼;
    SSH:clone的專案你必須是擁有者或者管理員,而且需要在clone前添加SSH Key。SSH 在push的時候,是不需要輸入用戶名的,如果配置... ......

    uj5u.com 2023-04-19 08:35:34 more
  • 2023年農牧行業6大CRM系統、5大場景盤點

    在物聯網、大資料、云計算、人工智能、自動化技術等現代資訊技術蓬勃發展與逐步成熟的背景下,數字化正成為農牧行業供給側結構性變革與高質量發展的核心驅動因素。因此,改造和提升傳統農牧業、開拓創新現代智慧農牧業,加快推進農牧業的現代化、資訊化、數字化建設已成為農牧業發展的重要方向。 當下,企業數字化轉型已經 ......

    uj5u.com 2023-04-18 08:05:44 more
  • 2023年農牧行業6大CRM系統、5大場景盤點

    在物聯網、大資料、云計算、人工智能、自動化技術等現代資訊技術蓬勃發展與逐步成熟的背景下,數字化正成為農牧行業供給側結構性變革與高質量發展的核心驅動因素。因此,改造和提升傳統農牧業、開拓創新現代智慧農牧業,加快推進農牧業的現代化、資訊化、數字化建設已成為農牧業發展的重要方向。 當下,企業數字化轉型已經 ......

    uj5u.com 2023-04-18 08:00:18 more
  • 計算機組成原理—存盤器

    計算機組成原理—硬體結構 二、存盤器 1.概述 存盤器是計算機系統中的記憶設備,用來存放程式和資料 1.1存盤器的層次結構 快取-主存層次主要解決CPU和主存速度不匹配的問題,速度接近快取 主存-輔存層次主要解決存盤系統的容量問題,容量接近與價位接近于主存 2.主存盤器 2.1概述 主存與CPU的聯 ......

    uj5u.com 2023-04-17 08:20:31 more
  • 談一談我對協同開發的一些認識

    如今各互聯網公司普通都使用敏捷開發,采用小步快跑的形式來進行專案開發。如果是小專案或者小需求,那一個開發可能就搞定了。但對于電商等復雜的系統,其功能多,結構復雜,一個人肯定是搞不定的,所以都是很多人來共同開發維護。以我曾經待過的商城團隊為例,光是后端開發就有七十多人。 為了更好地開發這類大型系統,往 ......

    uj5u.com 2023-04-17 08:18:55 more
  • 專案管理PRINCE2核心知識點整理

    PRINCE2,即 PRoject IN Controlled Environment(受控環境中的專案)是一種結構化的專案管理方法論,由英國政府內閣商務部(OGC)推出,是英國專案管理標準。
    PRINCE2 作為一種開放的方法論,是一套結構化的專案管理流程,描述了如何以一種邏輯性的、有組織的方法,... ......

    uj5u.com 2023-04-17 08:18:51 more
  • 談一談我對協同開發的一些認識

    如今各互聯網公司普通都使用敏捷開發,采用小步快跑的形式來進行專案開發。如果是小專案或者小需求,那一個開發可能就搞定了。但對于電商等復雜的系統,其功能多,結構復雜,一個人肯定是搞不定的,所以都是很多人來共同開發維護。以我曾經待過的商城團隊為例,光是后端開發就有七十多人。 為了更好地開發這類大型系統,往 ......

    uj5u.com 2023-04-17 08:18:00 more
  • 專案管理PRINCE2核心知識點整理

    PRINCE2,即 PRoject IN Controlled Environment(受控環境中的專案)是一種結構化的專案管理方法論,由英國政府內閣商務部(OGC)推出,是英國專案管理標準。
    PRINCE2 作為一種開放的方法論,是一套結構化的專案管理流程,描述了如何以一種邏輯性的、有組織的方法,... ......

    uj5u.com 2023-04-17 08:17:55 more
  • 計算機組成原理—存盤器

    計算機組成原理—硬體結構 二、存盤器 1.概述 存盤器是計算機系統中的記憶設備,用來存放程式和資料 1.1存盤器的層次結構 快取-主存層次主要解決CPU和主存速度不匹配的問題,速度接近快取 主存-輔存層次主要解決存盤系統的容量問題,容量接近與價位接近于主存 2.主存盤器 2.1概述 主存與CPU的聯 ......

    uj5u.com 2023-04-17 08:12:06 more