21#include <ql/errors.hpp>
22#include <ql/math/comparison.hpp>
29template <
typename NodeType,
typename... AddArgs>
struct createASTNode {
30 createASTNode(std::stack<ASTNodePtr>& evalStack,
const int nArgs,
const bool mergeLocation =
false)
31 : evalStack(evalStack), nArgs(nArgs), mergeLocation(mergeLocation) {}
32 void operator()(AddArgs... addArgs)
const {
33 std::vector<ASTNodePtr> arg;
36 QL_REQUIRE(!evalStack.empty(),
"internal error (empty stack)");
37 arg.insert(arg.begin(), evalStack.top());
41 auto node = QuantLib::ext::make_shared<NodeType>(addArgs..., arg);
42 if (mergeLocation && !arg.empty()) {
43 auto const& loc1 = arg.front()->locationInfo;
44 auto const& loc2 = arg.back()->locationInfo;
45 node->locationInfo = LocationInfo(loc1.lineStart, loc1.columnStart, loc2.lineEnd, loc2.columnEnd);
49 std::stack<ASTNodePtr>& evalStack;
51 const bool mergeLocation;
54template <
typename NodeType,
typename... AddArgs>
struct collapseASTNode {
55 collapseASTNode(std::stack<ASTNodePtr>& evalStack,
const int nArgs) : evalStack(evalStack), nArgs(nArgs) {}
56 void operator()(AddArgs... addArgs)
const {
57 std::vector<ASTNodePtr> arg;
60 QL_REQUIRE(!evalStack.empty(),
"internal error (empty stack)");
61 arg.insert(arg.begin(), evalStack.top());
65 QL_REQUIRE(!evalStack.empty(),
"internal error (empty stack)");
68 arg.insert(arg.begin(), previous->args.begin(), previous->args.end());
69 auto node = QuantLib::ext::make_shared<NodeType>(addArgs..., arg);
70 node->locationInfo = previous->locationInfo;
73 std::stack<ASTNodePtr>& evalStack;
78 :
ScriptGrammar::base_type(instructionseq,
"OREPayoffScript"), hasError(false), errorWhat(
""),
79 annotate(evalStack, first) {
83 keyword %= qi::lexeme[ ( qi::lit(
"IF") | qi::lit(
"THEN") | qi::lit(
"ELSE") | qi::lit(
"END") | qi::lit(
"FOR") | qi::lit(
"IN") | qi::lit(
"DO")
84 | qi::lit(
"NUMBER") | qi::lit(
"REQUIRE") | qi::lit(
"OR") | qi::lit(
"AND") | qi::lit(
"abs") | qi::lit(
"exp") | qi::lit(
"ln")
85 | qi::lit(
"sqrt") | qi::lit(
"normalCdf") | qi::lit(
"normalPdf") | qi::lit(
"max") | qi::lit(
"min") | qi::lit(
"pow") | qi::lit(
"black")
86 | qi::lit(
"dcf") | qi::lit(
"days") | qi::lit(
"PAY") | qi::lit(
"NPVMEM") | qi::lit(
"DISCOUNT") | qi::lit(
"SIZE") | qi::lit(
"SORT")
87 | qi::lit(
"PERMUTE") | qi::lit(
"LOGPAY") | qi::lit(
"HISTFIXING") | qi::lit(
"FWDCOMP") | qi::lit(
"FWDAVG") | qi::lit(
"ABOVEPROB")
88 | qi::lit(
"BELOWPROB") | qi::lit(
"NPV") | qi::lit(
"DATEINDEX")
89 ) >> !(qi::alnum | qi::char_(
'_')) ];
91 varname %= qi::lexeme[ (qi::alpha | qi::char_(
'_')) >> *(qi::alnum | qi::char_(
'_')) ] -
keyword;
102 > *(
',' >
varexpr [ collapseASTNode<DeclarationNumberNode>(
evalStack, 1) ]);
105 ( qi::lit(
"END") [ createASTNode<IfThenElseNode>(
evalStack, 2)]
117 ( qi::lit(
')') [ createASTNode<SortNode>(
evalStack, 1) ]
119 ( qi::lit(
')') [ createASTNode<SortNode>(
evalStack, 2) ]
120 | (qi::lit(
',') >
varexpr > qi::lit(
')')) [ createASTNode<SortNode>(
evalStack, 3) ]))));
124 ( qi::lit(
')') [ createASTNode<PermuteNode>(
evalStack, 2) ]
125 | (qi::lit(
',') >
varexpr > qi::lit(
')')) [ createASTNode<PermuteNode>(
evalStack, 3) ])));
131 | (
"!=" >
term) [ createASTNode<ConditionNeqNode>(
evalStack, 2) ]
132 | (
">=" >
term) [ createASTNode<ConditionGeqNode>(
evalStack, 2) ]
133 | (
">" >
term) [ createASTNode<ConditionGtNode>(
evalStack, 2) ]
134 | (
"<=" >
term) [ createASTNode<ConditionLeqNode>(
evalStack, 2) ]
135 | (
"<" >
term) [ createASTNode<ConditionLtNode>(
evalStack, 2) ] ));
138 | (
'-' >
product) [ createASTNode<OperatorMinusNode>(
evalStack, 2,
true) ] );
140 | (
'/' >
factor) [ createASTNode<OperatorDivideNode>(
evalStack, 2,
true) ] );
143 ( (qi::lit(
')') [ createASTNode<VarEvaluationNode>(
evalStack, 2) ]
144 | (
',' >
varexpr >
')') [ createASTNode<VarEvaluationNode>(
evalStack, 3) ] ))))
145 | qi::double_ [ createASTNode<ConstantNumberNode, double>(
evalStack, 0) ]
147 | (qi::lit(
"abs") >
"(" >
term >
')') [ createASTNode<FunctionAbsNode>(
evalStack, 1) ]
148 | (qi::lit(
"exp") >
"(" >
term >
')') [ createASTNode<FunctionExpNode>(
evalStack, 1) ]
149 | (qi::lit(
"ln") >
"(" >
term >
')') [ createASTNode<FunctionLogNode>(
evalStack, 1) ]
150 | (qi::lit(
"sqrt") >
"(" >
term >
')') [ createASTNode<FunctionSqrtNode>(
evalStack, 1) ]
151 | (qi::lit(
"normalCdf") >
"(" >
term >
')') [ createASTNode<FunctionNormalCdfNode>(
evalStack, 1) ]
152 | (qi::lit(
"normalPdf") >
"(" >
term >
')') [ createASTNode<FunctionNormalPdfNode>(
evalStack, 1) ]
153 | (qi::lit(
"max") >
"(" >
term >
',' >
term >
')') [ createASTNode<FunctionMaxNode>(
evalStack, 2) ]
154 | (qi::lit(
"min") >
"(" >
term >
',' >
term >
')') [ createASTNode<FunctionMinNode>(
evalStack, 2) ]
155 | (qi::lit(
"pow") >
"(" >
term >
',' >
term >
')') [ createASTNode<FunctionPowNode>(
evalStack, 2) ]
157 [ createASTNode<FunctionBlackNode>(
evalStack, 6) ]
159 [ createASTNode<FunctionDcfNode>(
evalStack, 3) ]
161 [ createASTNode<FunctionDaysNode>(
evalStack, 3) ]
162 | (qi::lit(
"PAY") >
"(" >
term >
',' >
term >
',' >
term >
',' >
term >
')')
163 [ createASTNode<FunctionPayNode>(
evalStack, 4) ]
165 ( qi::lit(
')') [ createASTNode<FunctionLogPayNode>(
evalStack, 4) ]
167 ( qi::lit(
')') [ createASTNode<FunctionLogPayNode>(
evalStack, 6) ]
168 | (qi::lit(
',') >
term >
")") [ createASTNode<FunctionLogPayNode>(
evalStack, 7) ]))))
169 | (qi::lit(
"NPVMEM") >
"(" >
term >
',' >
term >
',' >
term >
170 ( qi::lit(
')') [ createASTNode<FunctionNpvMemNode>(
evalStack, 3) ]
172 ( qi::lit(
')') [ createASTNode<FunctionNpvMemNode>(
evalStack, 4) ]
173 | (qi::lit(
',') >
term >
174 ( qi::lit(
')') [ createASTNode<FunctionNpvMemNode>(
evalStack, 5) ]
175 | (qi::lit(
',') >
term >
')') [ createASTNode<FunctionNpvMemNode>(
evalStack, 6) ]))))))
176 | (qi::lit(
"NPV") >
"(" >
term >
',' >
term >
177 ( qi::lit(
')') [ createASTNode<FunctionNpvNode>(
evalStack, 2) ]
179 ( qi::lit(
')') [ createASTNode<FunctionNpvNode>(
evalStack, 3) ]
180 | (qi::lit(
',') >
term >
181 ( qi::lit(
')') [ createASTNode<FunctionNpvNode>(
evalStack, 4) ]
182 | (qi::lit(
',') >
term >
')') [ createASTNode<FunctionNpvNode>(
evalStack, 5) ]))))))
183 | (qi::lit(
"DISCOUNT") >
"(" >
term >
',' >
term >
',' >
term >
')')
184 [ createASTNode<FunctionDiscountNode>(
evalStack, 3) ]
185 | (qi::lit(
"SIZE") >
"(" >
varname >
')') [ createASTNode<SizeOpNode, std::string>(
evalStack, 0) ]
187 [ createASTNode<HistFixingNode>(
evalStack, 2) ]
189 ( qi::lit(
')') [ createASTNode<FunctionFwdCompNode>(
evalStack, 4) ]
190 | (qi::lit(
',') >
term >
',' >
term >
191 ( qi::lit(
')') [ createASTNode<FunctionFwdCompNode>(
evalStack, 6) ]
193 ( qi::lit(
')') [ createASTNode<FunctionFwdCompNode>(
evalStack, 10) ]
194 | (qi::lit(
',') >
term >
',' >
term >
',' >
term >
',' >
term >
')') [ createASTNode<FunctionFwdCompNode>(
evalStack, 14) ]))))))
196 ( qi::lit(
')') [ createASTNode<FunctionFwdAvgNode>(
evalStack, 4) ]
197 | (qi::lit(
',') >
term >
',' >
term >
198 ( qi::lit(
')') [ createASTNode<FunctionFwdAvgNode>(
evalStack, 6) ]
200 ( qi::lit(
')') [ createASTNode<FunctionFwdAvgNode>(
evalStack, 10) ]
201 | (qi::lit(
',') >
term >
',' >
term >
',' >
term >
',' >
term >
')') [ createASTNode<FunctionFwdAvgNode>(
evalStack, 14) ]))))))
203 [ createASTNode<FunctionAboveProbNode>(
evalStack, 4) ]
205 [ createASTNode<FunctionBelowProbNode>(
evalStack, 4) ]
222 sort.name(
"Permute");
231 auto set_location_info = phoenix::bind(&ASTNodeAnnotation::operator(), &
annotate, qi::_1, qi::_3);
232 qi::on_success(
varexpr, set_location_info);
236 qi::on_success(
ifthenelse, set_location_info);
237 qi::on_success(
loop, set_location_info);
238 qi::on_success(
assignment, set_location_info);
239 qi::on_success(
require, set_location_info);
240 qi::on_success(
sort, set_location_info);
241 qi::on_success(
permute, set_location_info);
242 qi::on_success(
condition, set_location_info);
243 qi::on_success(
condition2, set_location_info);
244 qi::on_success(
condition3, set_location_info);
245 qi::on_success(
term, set_location_info);
246 qi::on_success(
product, set_location_info);
247 qi::on_success(
factor, set_location_info);
257 QL_REQUIRE(!
evalStack_.empty(),
"eval stack is empty");
259 n->locationInfo.initialised =
true;
260 n->locationInfo.lineStart = boost::spirit::get_line(f);
261 n->locationInfo.columnStart = boost::spirit::get_column(
first_, f);
262 n->locationInfo.lineEnd = boost::spirit::get_line(l);
263 n->locationInfo.columnEnd = boost::spirit::get_column(
first_, l);
boost::spirit::line_pos_iterator< std::string::const_iterator > ScriptGrammarIterator
QuantLib::ext::shared_ptr< ASTNode > ASTNodePtr
Serializable Credit Default Swap.
const ScriptGrammarIterator first_
void operator()(const ScriptGrammarIterator f, const ScriptGrammarIterator l) const
std::stack< ASTNodePtr > & evalStack_
qi::rule< ScriptGrammarIterator, qi::space_type > loop
qi::rule< ScriptGrammarIterator, qi::space_type > condition2
ScriptGrammarIterator errorBegin
ScriptGrammar(ScriptGrammarIterator first)
qi::rule< ScriptGrammarIterator, qi::space_type > instructionseq
qi::rule< ScriptGrammarIterator, qi::space_type > require
std::stack< ASTNodePtr > evalStack
qi::rule< ScriptGrammarIterator, qi::space_type > ifthenelse
ASTNodeAnnotation annotate
qi::rule< ScriptGrammarIterator, qi::space_type > instruction
ScriptGrammarIterator errorEnd
qi::rule< ScriptGrammarIterator, qi::space_type > permute
qi::rule< ScriptGrammarIterator, qi::space_type > declaration
qi::rule< ScriptGrammarIterator, qi::space_type > assignment
qi::rule< ScriptGrammarIterator, std::string(), qi::space_type > keyword
qi::rule< ScriptGrammarIterator, qi::space_type > varexpr
qi::rule< ScriptGrammarIterator, qi::space_type > factor
qi::rule< ScriptGrammarIterator, qi::space_type > sort
qi::rule< ScriptGrammarIterator, qi::space_type > product
qi::rule< ScriptGrammarIterator, qi::space_type > term
qi::rule< ScriptGrammarIterator, qi::space_type > condition
qi::rule< ScriptGrammarIterator, qi::space_type > condition3
ScriptGrammarIterator errorPos
boost::spirit::info errorWhat
qi::rule< ScriptGrammarIterator, std::string(), qi::space_type > varname