Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
grammar.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2019 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
20
21#include <ql/errors.hpp>
22#include <ql/math/comparison.hpp>
23
24#include <sstream>
25
26namespace ore {
27namespace data {
28
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;
34 int n = nArgs;
35 while (n) {
36 QL_REQUIRE(!evalStack.empty(), "internal error (empty stack)");
37 arg.insert(arg.begin(), evalStack.top());
38 evalStack.pop();
39 --n;
40 }
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);
46 }
47 evalStack.push(node);
48 }
49 std::stack<ASTNodePtr>& evalStack;
50 const int nArgs;
51 const bool mergeLocation;
52};
53
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;
58 int n = nArgs;
59 while (n) {
60 QL_REQUIRE(!evalStack.empty(), "internal error (empty stack)");
61 arg.insert(arg.begin(), evalStack.top());
62 evalStack.pop();
63 --n;
64 }
65 QL_REQUIRE(!evalStack.empty(), "internal error (empty stack)");
66 ASTNodePtr previous = evalStack.top();
67 evalStack.pop();
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;
71 evalStack.push(node);
72 }
73 std::stack<ASTNodePtr>& evalStack;
74 const int nArgs;
75};
76
78 : ScriptGrammar::base_type(instructionseq, "OREPayoffScript"), hasError(false), errorWhat(""),
79 annotate(evalStack, first) {
80
81 // clang-format off
82
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_('_')) ];
90
91 varname %= qi::lexeme[ (qi::alpha | qi::char_('_')) >> *(qi::alnum | qi::char_('_')) ] - keyword;
92
93 varexpr = ((varname >> '[') > term > ']') [ createASTNode<VariableNode, std::string>(evalStack, 1) ]
94 | varname [ createASTNode<VariableNode, std::string>(evalStack, 0) ];
95
96 instructionseq = instruction [ createASTNode<SequenceNode>(evalStack, 1) ]
97 > *(instruction [ collapseASTNode<SequenceNode>(evalStack, 1) ]);
98
100
101 declaration = "NUMBER" > varexpr [ createASTNode<DeclarationNumberNode>(evalStack, 1) ]
102 > *(',' > varexpr [ collapseASTNode<DeclarationNumberNode>(evalStack, 1) ]);
103
104 ifthenelse = "IF" > condition > "THEN" > instructionseq >
105 ( qi::lit("END") [ createASTNode<IfThenElseNode>(evalStack, 2)]
106 | ("ELSE" > instructionseq > "END") [ createASTNode<IfThenElseNode>(evalStack, 3)]);
107
108 loop =
109 ("FOR" > varname > "IN" > '(' > term > ',' > term > ',' > term > ')'
110 > "DO" > instructionseq > "END") [ createASTNode<LoopNode, std::string>(evalStack, 4) ];
111
112 assignment = varexpr > '=' > term [ createASTNode<AssignmentNode>(evalStack, 2) ];
113
114 require = "REQUIRE" > condition [ createASTNode<RequireNode>(evalStack, 1) ];
115
116 sort = "SORT" > qi::lit('(') > (varexpr >
117 ( qi::lit(')') [ createASTNode<SortNode>(evalStack, 1) ]
118 | (qi::lit(',') > varexpr >
119 ( qi::lit(')') [ createASTNode<SortNode>(evalStack, 2) ]
120 | (qi::lit(',') > varexpr > qi::lit(')')) [ createASTNode<SortNode>(evalStack, 3) ]))));
121
122 permute = "PERMUTE" > qi::lit('(') > (varexpr >
123 ( qi::lit(',') > varexpr >
124 ( qi::lit(')') [ createASTNode<PermuteNode>(evalStack, 2) ]
125 | (qi::lit(',') > varexpr > qi::lit(')')) [ createASTNode<PermuteNode>(evalStack, 3) ])));
126
127 condition = condition2 > *(("OR" > condition2) [ createASTNode<ConditionOrNode>(evalStack, 2, true) ] );
128 condition2 = condition3 > *(("AND" > condition3) [ createASTNode<ConditionAndNode>(evalStack, 2, true) ] );
129 condition3 = ('{' > condition > '}')
130 | (term > ( ("==" > term) [ createASTNode<ConditionEqNode>(evalStack, 2) ]
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) ] ));
136
137 term = product > *( ('+' > product) [ createASTNode<OperatorPlusNode>(evalStack, 2,true) ]
138 | ('-' > product) [ createASTNode<OperatorMinusNode>(evalStack, 2, true) ] );
139 product = factor > *( ('*' > factor) [ createASTNode<OperatorMultiplyNode>(evalStack, 2, true) ]
140 | ('/' > factor) [ createASTNode<OperatorDivideNode>(evalStack, 2, true) ] );
141 factor = ('(' > term > ')')
142 | (varexpr > -( '(' > varexpr >
143 ( (qi::lit(')') [ createASTNode<VarEvaluationNode>(evalStack, 2) ]
144 | (',' > varexpr > ')') [ createASTNode<VarEvaluationNode>(evalStack, 3) ] ))))
145 | qi::double_ [ createASTNode<ConstantNumberNode, double>(evalStack, 0) ]
146 | ('-' > factor) [ createASTNode<NegateNode>(evalStack, 1) ]
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) ]
156 | (qi::lit("black") > "(" > term > ',' > term > ',' > term > ',' > term > ',' > term > ',' > term > ')')
157 [ createASTNode<FunctionBlackNode>(evalStack, 6) ]
158 | (qi::lit("dcf") > "(" > varexpr > ',' > varexpr > ',' > varexpr > ')')
159 [ createASTNode<FunctionDcfNode>(evalStack, 3) ]
160 | (qi::lit("days") > "(" > varexpr > ',' > varexpr > ',' > varexpr > ')')
161 [ createASTNode<FunctionDaysNode>(evalStack, 3) ]
162 | (qi::lit("PAY") > "(" > term > ',' > term > ',' > term > ',' > term > ')')
163 [ createASTNode<FunctionPayNode>(evalStack, 4) ]
164 | (qi::lit("LOGPAY") > "(" > term > ',' > term > ',' > term > ',' > term >
165 ( qi::lit(')') [ createASTNode<FunctionLogPayNode>(evalStack, 4) ]
166 | (qi::lit(',') > term > ',' > varexpr >
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) ]
171 | (qi::lit(',') > condition >
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) ]
178 | (qi::lit(',') > condition >
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) ]
186 | (qi::lit("HISTFIXING") > "(" > varexpr > ',' > varexpr > ')')
187 [ createASTNode<HistFixingNode>(evalStack, 2) ]
188 | (qi::lit("FWDCOMP") > "(" > varexpr > ',' > varexpr > ',' > varexpr > ',' > varexpr >
189 ( qi::lit(')') [ createASTNode<FunctionFwdCompNode>(evalStack, 4) ]
190 | (qi::lit(',') > term > ',' > term >
191 ( qi::lit(')') [ createASTNode<FunctionFwdCompNode>(evalStack, 6) ]
192 | (qi::lit(',') > term > ',' > term > ',' > term > ',' > term >
193 ( qi::lit(')') [ createASTNode<FunctionFwdCompNode>(evalStack, 10) ]
194 | (qi::lit(',') > term > ',' > term > ',' > term > ',' > term > ')') [ createASTNode<FunctionFwdCompNode>(evalStack, 14) ]))))))
195 | (qi::lit("FWDAVG") > "(" > varexpr > ',' > varexpr > ',' > varexpr > ',' > varexpr >
196 ( qi::lit(')') [ createASTNode<FunctionFwdAvgNode>(evalStack, 4) ]
197 | (qi::lit(',') > term > ',' > term >
198 ( qi::lit(')') [ createASTNode<FunctionFwdAvgNode>(evalStack, 6) ]
199 | (qi::lit(',') > term > ',' > term > ',' > term > ',' > term >
200 ( qi::lit(')') [ createASTNode<FunctionFwdAvgNode>(evalStack, 10) ]
201 | (qi::lit(',') > term > ',' > term > ',' > term > ',' > term > ')') [ createASTNode<FunctionFwdAvgNode>(evalStack, 14) ]))))))
202 | (qi::lit("ABOVEPROB") > "(" > varexpr > ',' > varexpr > ',' > varexpr > ',' > term > ")")
203 [ createASTNode<FunctionAboveProbNode>(evalStack, 4) ]
204 | (qi::lit("BELOWPROB") > "(" > varexpr > ',' > varexpr > ',' > varexpr > ',' > term > ")")
205 [ createASTNode<FunctionBelowProbNode>(evalStack, 4) ]
206 | (qi::lit("DATEINDEX") > "(" > varexpr > ',' > varname > ',' > varname > ")")
207 [ createASTNode<FunctionDateIndexNode, boost::fusion::vector<std::string, std::string>>(evalStack, 1) ];
208
209 // clang-format on
210
211 // name rules
212 varname.name("VarName");
213 varexpr.name("VarExpr");
214 instructionseq.name("InstructionSequence");
215 instruction.name("Instruction");
216 declaration.name("Declaration");
217 ifthenelse.name("IfThenElse");
218 loop.name("Loop");
219 assignment.name("Assignment");
220 require.name("Require");
221 sort.name("Sort");
222 sort.name("Permute");
223 condition.name("Condition");
224 condition2.name("Condition2");
225 condition3.name("Condition3");
226 term.name("Term");
227 product.name("Product");
228 factor.name("Factor");
229
230 // ast node annotation
231 auto set_location_info = phoenix::bind(&ASTNodeAnnotation::operator(), &annotate, qi::_1, qi::_3);
232 qi::on_success(varexpr, set_location_info);
233 qi::on_success(instructionseq, set_location_info);
234 qi::on_success(instruction, set_location_info);
235 qi::on_success(declaration, 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);
248
249 // error handling
250 auto errorHandler =
251 (phoenix::ref(hasError) = true, phoenix::ref(errorBegin) = qi::_1, phoenix::ref(errorEnd) = qi::_2,
252 phoenix::ref(errorPos) = qi::_3, phoenix::ref(errorWhat) = qi::_4);
253 qi::on_error<qi::fail>(instructionseq, errorHandler);
254}
255
257 QL_REQUIRE(!evalStack_.empty(), "eval stack is empty");
258 ASTNodePtr& n = evalStack_.top();
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);
264}
265
266} // namespace data
267} // namespace end
payoff script grammar
@ data
Definition: log.hpp:77
boost::spirit::line_pos_iterator< std::string::const_iterator > ScriptGrammarIterator
Definition: grammar.hpp:46
QuantLib::ext::shared_ptr< ASTNode > ASTNodePtr
Definition: ast.hpp:46
Serializable Credit Default Swap.
Definition: namespaces.docs:23
const ScriptGrammarIterator first_
Definition: grammar.hpp:55
void operator()(const ScriptGrammarIterator f, const ScriptGrammarIterator l) const
Definition: grammar.cpp:256
std::stack< ASTNodePtr > & evalStack_
Definition: grammar.hpp:54
qi::rule< ScriptGrammarIterator, qi::space_type > loop
Definition: grammar.hpp:69
qi::rule< ScriptGrammarIterator, qi::space_type > condition2
Definition: grammar.hpp:70
ScriptGrammarIterator errorBegin
Definition: grammar.hpp:63
ScriptGrammar(ScriptGrammarIterator first)
Definition: grammar.cpp:77
qi::rule< ScriptGrammarIterator, qi::space_type > instructionseq
Definition: grammar.hpp:69
qi::rule< ScriptGrammarIterator, qi::space_type > require
Definition: grammar.hpp:70
std::stack< ASTNodePtr > evalStack
Definition: grammar.hpp:65
qi::rule< ScriptGrammarIterator, qi::space_type > ifthenelse
Definition: grammar.hpp:69
ASTNodeAnnotation annotate
Definition: grammar.hpp:71
qi::rule< ScriptGrammarIterator, qi::space_type > instruction
Definition: grammar.hpp:69
ScriptGrammarIterator errorEnd
Definition: grammar.hpp:63
qi::rule< ScriptGrammarIterator, qi::space_type > permute
Definition: grammar.hpp:70
qi::rule< ScriptGrammarIterator, qi::space_type > declaration
Definition: grammar.hpp:69
qi::rule< ScriptGrammarIterator, qi::space_type > assignment
Definition: grammar.hpp:70
qi::rule< ScriptGrammarIterator, std::string(), qi::space_type > keyword
Definition: grammar.hpp:68
qi::rule< ScriptGrammarIterator, qi::space_type > varexpr
Definition: grammar.hpp:69
qi::rule< ScriptGrammarIterator, qi::space_type > factor
Definition: grammar.hpp:70
qi::rule< ScriptGrammarIterator, qi::space_type > sort
Definition: grammar.hpp:70
qi::rule< ScriptGrammarIterator, qi::space_type > product
Definition: grammar.hpp:70
qi::rule< ScriptGrammarIterator, qi::space_type > term
Definition: grammar.hpp:70
qi::rule< ScriptGrammarIterator, qi::space_type > condition
Definition: grammar.hpp:70
qi::rule< ScriptGrammarIterator, qi::space_type > condition3
Definition: grammar.hpp:70
ScriptGrammarIterator errorPos
Definition: grammar.hpp:63
boost::spirit::info errorWhat
Definition: grammar.hpp:64
qi::rule< ScriptGrammarIterator, std::string(), qi::space_type > varname
Definition: grammar.hpp:68