2 /******************************************************************************
4 * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
6 * This program is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU General Public License *
8 * as published by the Free Software Foundation; either version 2 *
9 * of the License, or (at your option) any later version. *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software Foundation *
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ******************************************************************************/
21 #include "i2-config.h"
22 #include "config/expression.h"
23 #include "config/expressionlist.h"
24 #include "config/configitembuilder.h"
25 #include "config/configcompiler.h"
26 #include "config/configcompilercontext.h"
27 #include "config/typerule.h"
28 #include "config/typerulelist.h"
29 #include "config/aexpression.h"
30 #include "base/value.h"
31 #include "base/utility.h"
32 #include "base/array.h"
33 #include "base/scriptvariable.h"
34 #include "base/exception.h"
37 #include <boost/foreach.hpp>
39 #define YYLTYPE icinga::DebugInfo
41 using namespace icinga;
51 %parse-param { ConfigCompiler *context }
52 %lex-param { void *scanner }
57 icinga::Value *variant;
58 icinga::ExpressionOperator op;
59 icinga::TypeSpecifier type;
60 std::vector<String> *slist;
62 ExpressionList *exprl;
67 %token <text> T_STRING
68 %token <text> T_STRING_ANGLE
71 %token <text> T_IDENTIFIER
72 %token <op> T_EQUAL "== (T_EQUAL)"
73 %token <op> T_NOT_EQUAL "!= (T_NOT_EQUAL)"
74 %token <op> T_SET "= (T_SET)"
75 %token <op> T_PLUS_EQUAL "+= (T_PLUS_EQUAL)"
76 %token <op> T_MINUS_EQUAL "-= (T_MINUS_EQUAL)"
77 %token <op> T_MULTIPLY_EQUAL "*= (T_MULTIPLY_EQUAL)"
78 %token <op> T_DIVIDE_EQUAL "/= (T_DIVIDE_EQUAL)"
79 %token T_VAR "var (T_VAR)"
80 %token T_CONST "const (T_CONST)"
81 %token T_SHIFT_LEFT "<< (T_SHIFT_LEFT)"
82 %token T_SHIFT_RIGHT ">> (T_SHIFT_RIGHT)"
83 %token <type> T_TYPE_DICTIONARY "dictionary (T_TYPE_DICTIONARY)"
84 %token <type> T_TYPE_ARRAY "array (T_TYPE_ARRAY)"
85 %token <type> T_TYPE_NUMBER "number (T_TYPE_NUMBER)"
86 %token <type> T_TYPE_STRING "string (T_TYPE_STRING)"
87 %token <type> T_TYPE_SCALAR "scalar (T_TYPE_SCALAR)"
88 %token <type> T_TYPE_ANY "any (T_TYPE_ANY)"
89 %token <type> T_TYPE_NAME "name (T_TYPE_NAME)"
90 %token T_VALIDATOR "%validator (T_VALIDATOR)"
91 %token T_REQUIRE "%require (T_REQUIRE)"
92 %token T_ATTRIBUTE "%attribute (T_ATTRIBUTE)"
93 %token T_TYPE "type (T_TYPE)"
94 %token T_OBJECT "object (T_OBJECT)"
95 %token T_TEMPLATE "template (T_TEMPLATE)"
96 %token T_INCLUDE "include (T_INCLUDE)"
97 %token T_INCLUDE_RECURSIVE "include_recursive (T_INCLUDE_RECURSIVE)"
98 %token T_LIBRARY "library (T_LIBRARY)"
99 %token T_INHERITS "inherits (T_INHERITS)"
100 %token T_PARTIAL "partial (T_PARTIAL)"
101 %type <text> identifier
103 %type <array> array_items
104 %type <array> array_items_inner
105 %type <variant> simplevalue
106 %type <variant> value
107 %type <expr> expression
108 %type <exprl> expressions
109 %type <exprl> expressions_inner
110 %type <exprl> expressionlist
111 %type <variant> typerulelist
114 %type <num> partial_specifier
115 %type <slist> object_inherits_list
116 %type <slist> object_inherits_specifier
118 %type <aexpr> aexpression
119 %type <num> variable_decl
126 int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner);
128 void yyerror(YYLTYPE *locp, ConfigCompiler *, const char *err)
130 std::ostringstream message;
131 message << *locp << ": " << err;
132 ConfigCompilerContext::GetInstance()->AddMessage(true, message.str());
135 int yyparse(ConfigCompiler *context);
137 static std::stack<Array::Ptr> m_Arrays;
138 static bool m_Abstract;
140 static std::stack<TypeRuleList::Ptr> m_RuleLists;
141 static ConfigType::Ptr m_Type;
143 void ConfigCompiler::Compile(void)
147 } catch (const std::exception& ex) {
148 ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex));
152 #define scanner (context->GetScanner())
157 statements: /* empty */
158 | statements statement
161 statement: object | type | include | include_recursive | library | variable
164 include: T_INCLUDE value
166 context->HandleInclude(*$2, false, yylloc);
169 | T_INCLUDE T_STRING_ANGLE
171 context->HandleInclude($2, true, yylloc);
176 include_recursive: T_INCLUDE_RECURSIVE value
178 context->HandleIncludeRecursive(*$2, "*.conf", yylloc);
181 | T_INCLUDE_RECURSIVE value value
183 context->HandleIncludeRecursive(*$2, *$3, yylloc);
189 library: T_LIBRARY T_STRING
191 context->HandleLibrary($2);
196 variable: variable_decl identifier T_SET value
199 if (value->IsObjectType<ExpressionList>()) {
200 Dictionary::Ptr dict = make_shared<Dictionary>();
201 ExpressionList::Ptr exprl = *value;
202 exprl->Execute(dict);
204 value = new Value(dict);
207 ScriptVariable::Ptr sv = ScriptVariable::Set($2, *value);
208 sv->SetConstant(true);
225 identifier: T_IDENTIFIER
232 type: partial_specifier T_TYPE identifier
234 String name = String($3);
237 m_Type = ConfigType::GetByName(name);
241 BOOST_THROW_EXCEPTION(std::invalid_argument("Partial type definition for unknown type '" + name + "'"));
243 m_Type = make_shared<ConfigType>(name, yylloc);
247 type_inherits_specifier typerulelist
249 TypeRuleList::Ptr ruleList = *$6;
250 m_Type->GetRuleList()->AddRules(ruleList);
251 m_Type->GetRuleList()->AddRequires(ruleList);
253 String validator = ruleList->GetValidator();
254 if (!validator.IsEmpty())
255 m_Type->GetRuleList()->SetValidator(validator);
261 partial_specifier: /* Empty */
273 m_RuleLists.push(make_shared<TypeRuleList>());
278 $$ = new Value(m_RuleLists.top());
283 typerules: typerules_inner
284 | typerules_inner ','
286 typerules_inner: /* empty */
288 | typerules_inner ',' typerule
291 typerule: T_REQUIRE T_STRING
293 m_RuleLists.top()->AddRequire($2);
296 | T_VALIDATOR T_STRING
298 m_RuleLists.top()->SetValidator($2);
301 | T_ATTRIBUTE type T_STRING
303 TypeRule rule($2, String(), $3, TypeRuleList::Ptr(), yylloc);
306 m_RuleLists.top()->AddRule(rule);
308 | T_ATTRIBUTE T_TYPE_NAME '(' identifier ')' T_STRING
310 TypeRule rule($2, $4, $6, TypeRuleList::Ptr(), yylloc);
314 m_RuleLists.top()->AddRule(rule);
316 | T_ATTRIBUTE type T_STRING typerulelist
318 TypeRule rule($2, String(), $3, *$4, yylloc);
321 m_RuleLists.top()->AddRule(rule);
325 type_inherits_specifier: /* empty */
326 | T_INHERITS identifier
328 m_Type->SetParent($2);
333 type: T_TYPE_DICTIONARY
349 object_declaration identifier T_STRING object_inherits_specifier expressionlist
351 ConfigItemBuilder::Ptr item = make_shared<ConfigItemBuilder>(yylloc);
355 if (strchr($4, '!') != NULL) {
356 std::ostringstream msgbuf;
357 msgbuf << "Name for object '" << $4 << "' of type '" << $3 << "' is invalid: Object names may not contain '!'";
359 BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str()));
368 BOOST_FOREACH(const String& parent, *$5) {
369 item->AddParent(parent);
376 ExpressionList::Ptr exprl = ExpressionList::Ptr($6);
377 item->AddExpressionList(exprl);
380 item->SetAbstract(m_Abstract);
382 item->Compile()->Register();
387 object_declaration: T_OBJECT
393 object_inherits_list:
399 $$ = new std::vector<String>();
403 | object_inherits_list ',' T_STRING
408 $$ = new std::vector<String>();
415 object_inherits_specifier:
419 | T_INHERITS object_inherits_list
425 expressionlist: '{' expressions '}'
430 $$ = new ExpressionList();
434 expressions: expressions_inner
438 | expressions_inner ','
443 expressions_inner: /* empty */
449 $$ = new ExpressionList();
450 $$->AddExpression(*$1);
453 | expressions_inner ',' expression
458 $$ = new ExpressionList();
460 $$->AddExpression(*$3);
465 expression: identifier operator value
467 $$ = new Expression($1, $2, *$3, yylloc);
471 | identifier '[' T_STRING ']' operator value
473 Expression subexpr($3, $5, *$6, yylloc);
477 ExpressionList::Ptr subexprl = make_shared<ExpressionList>();
478 subexprl->AddExpression(subexpr);
480 $$ = new Expression($1, OperatorPlus, subexprl, yylloc);
495 array: '[' array_items ']'
501 array_items: array_items_inner
505 | array_items_inner ','
510 array_items_inner: /* empty */
518 if ($1->IsObjectType<ExpressionList>()) {
519 ExpressionList::Ptr exprl = *$1;
520 Dictionary::Ptr dict = make_shared<Dictionary>();
521 exprl->Execute(dict);
523 $1 = new Value(dict);
529 | array_items_inner ',' value
536 if ($3->IsObjectType<ExpressionList>()) {
537 ExpressionList::Ptr exprl = *$3;
538 Dictionary::Ptr dict = make_shared<Dictionary>();
539 exprl->Execute(dict);
541 $3 = new Value(dict);
549 simplevalue: T_STRING
567 Array::Ptr array = Array::Ptr($1);
568 $$ = new Value(array);
572 aterm: '(' aexpression ')'
577 aexpression: T_STRING
579 $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, $1)));
584 $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, $1)));
588 $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATVariable, $1)));
593 $$ = new Value(make_shared<AExpression>(AENegate, static_cast<AExpression::Ptr>(*$2)));
596 | aexpression T_EQUAL aexpression
598 $$ = new Value(make_shared<AExpression>(AEEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
602 | aexpression T_NOT_EQUAL aexpression
604 $$ = new Value(make_shared<AExpression>(AENotEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
608 | aexpression '+' aexpression
610 $$ = new Value(make_shared<AExpression>(AEAdd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
614 | aexpression '-' aexpression
616 $$ = new Value(make_shared<AExpression>(AESubtract, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
620 | aexpression '*' aexpression
622 $$ = new Value(make_shared<AExpression>(AEMultiply, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
626 | aexpression '/' aexpression
628 $$ = new Value(make_shared<AExpression>(AEDivide, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
632 | aexpression '&' aexpression
634 $$ = new Value(make_shared<AExpression>(AEBinaryAnd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
638 | aexpression '|' aexpression
640 $$ = new Value(make_shared<AExpression>(AEBinaryOr, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
644 | aexpression T_SHIFT_LEFT aexpression
646 $$ = new Value(make_shared<AExpression>(AEShiftLeft, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
650 | aexpression T_SHIFT_RIGHT aexpression
652 $$ = new Value(make_shared<AExpression>(AEShiftRight, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
656 | '(' aexpression ')'
665 ExpressionList::Ptr exprl = ExpressionList::Ptr($1);
666 $$ = new Value(exprl);
670 AExpression::Ptr aexpr = *$1;
671 $$ = new Value(aexpr->Evaluate(Dictionary::Ptr()));