]> granicus.if.org Git - icinga2/blob - lib/config/config_parser.yy
Merge branch 'feature/constants-4946' into next
[icinga2] / lib / config / config_parser.yy
1 %{
2 /******************************************************************************
3  * Icinga 2                                                                   *
4  * Copyright (C) 2012-2013 Icinga Development Team (http://www.icinga.org/)   *
5  *                                                                            *
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.                     *
10  *                                                                            *
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.                               *
15  *                                                                            *
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  ******************************************************************************/
20
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"
35 #include <sstream>
36 #include <stack>
37 #include <boost/foreach.hpp>
38
39 #define YYLTYPE icinga::DebugInfo
40
41 using namespace icinga;
42
43 %}
44
45 %pure-parser
46
47 %locations
48 %defines
49 %error-verbose
50
51 %parse-param { ConfigCompiler *context }
52 %lex-param { void *scanner }
53
54 %union {
55         char *text;
56         double num;
57         icinga::Value *variant;
58         icinga::ExpressionOperator op;
59         icinga::TypeSpecifier type;
60         std::vector<String> *slist;
61         Expression *expr;
62         ExpressionList *exprl;
63         Array *array;
64         Value *aexpr;
65 }
66
67 %token <text> T_STRING
68 %token <text> T_STRING_ANGLE
69 %token <num> T_NUMBER
70 %token T_NULL
71 %token <text> T_IDENTIFIER
72 %token <op> T_EQUAL "= (T_EQUAL)"
73 %token <op> T_PLUS_EQUAL "+= (T_PLUS_EQUAL)"
74 %token <op> T_MINUS_EQUAL "-= (T_MINUS_EQUAL)"
75 %token <op> T_MULTIPLY_EQUAL "*= (T_MULTIPLY_EQUAL)"
76 %token <op> T_DIVIDE_EQUAL "/= (T_DIVIDE_EQUAL)"
77 %token T_VAR "var (T_VAR)"
78 %token T_CONST "const (T_CONST)"
79 %token T_SHIFT_LEFT "<< (T_SHIFT_LEFT)"
80 %token T_SHIFT_RIGHT ">> (T_SHIFT_RIGHT)"
81 %token <type> T_TYPE_DICTIONARY "dictionary (T_TYPE_DICTIONARY)"
82 %token <type> T_TYPE_ARRAY "array (T_TYPE_ARRAY)"
83 %token <type> T_TYPE_NUMBER "number (T_TYPE_NUMBER)"
84 %token <type> T_TYPE_STRING "string (T_TYPE_STRING)"
85 %token <type> T_TYPE_SCALAR "scalar (T_TYPE_SCALAR)"
86 %token <type> T_TYPE_ANY "any (T_TYPE_ANY)"
87 %token <type> T_TYPE_NAME "name (T_TYPE_NAME)"
88 %token T_VALIDATOR "%validator (T_VALIDATOR)"
89 %token T_REQUIRE "%require (T_REQUIRE)"
90 %token T_ATTRIBUTE "%attribute (T_ATTRIBUTE)"
91 %token T_TYPE "type (T_TYPE)"
92 %token T_OBJECT "object (T_OBJECT)"
93 %token T_TEMPLATE "template (T_TEMPLATE)"
94 %token T_INCLUDE "include (T_INCLUDE)"
95 %token T_INCLUDE_RECURSIVE "include_recursive (T_INCLUDE_RECURSIVE)"
96 %token T_LIBRARY "library (T_LIBRARY)"
97 %token T_INHERITS "inherits (T_INHERITS)"
98 %token T_PARTIAL "partial (T_PARTIAL)"
99 %type <text> identifier
100 %type <array> array
101 %type <array> array_items
102 %type <array> array_items_inner
103 %type <variant> simplevalue
104 %type <variant> value
105 %type <expr> expression
106 %type <exprl> expressions
107 %type <exprl> expressions_inner
108 %type <exprl> expressionlist
109 %type <variant> typerulelist
110 %type <op> operator
111 %type <type> type
112 %type <num> partial_specifier
113 %type <slist> object_inherits_list
114 %type <slist> object_inherits_specifier
115 %type <aexpr> aterm
116 %type <aexpr> aexpression
117 %type <num> variable_decl
118 %left '+' '-'
119 %left '*' '/'
120 %left '&'
121 %left '|'
122 %{
123
124 int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner);
125
126 void yyerror(YYLTYPE *locp, ConfigCompiler *, const char *err)
127 {
128         std::ostringstream message;
129         message << *locp << ": " << err;
130         ConfigCompilerContext::GetInstance()->AddMessage(true, message.str());
131 }
132
133 int yyparse(ConfigCompiler *context);
134
135 static std::stack<Array::Ptr> m_Arrays;
136 static bool m_Abstract;
137
138 static std::stack<TypeRuleList::Ptr> m_RuleLists;
139 static ConfigType::Ptr m_Type;
140
141 void ConfigCompiler::Compile(void)
142 {
143         try {
144                 yyparse(this);
145         } catch (const std::exception& ex) {
146                 ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex));
147         }
148 }
149
150 #define scanner (context->GetScanner())
151
152 %}
153
154 %%
155 statements: /* empty */
156         | statements statement
157         ;
158
159 statement: object | type | include | include_recursive | library | variable
160         ;
161
162 include: T_INCLUDE value
163         {
164                 context->HandleInclude(*$2, false, yylloc);
165                 delete $2;
166         }
167         | T_INCLUDE T_STRING_ANGLE
168         {
169                 context->HandleInclude($2, true, yylloc);
170                 free($2);
171         }
172         ;
173
174 include_recursive: T_INCLUDE_RECURSIVE value
175         {
176                 context->HandleIncludeRecursive(*$2, "*.conf", yylloc);
177                 delete $2;
178         }
179         | T_INCLUDE_RECURSIVE value value
180         {
181                 context->HandleIncludeRecursive(*$2, *$3, yylloc);
182                 delete $2;
183                 delete $3;
184         }
185         ;
186
187 library: T_LIBRARY T_STRING
188         {
189                 context->HandleLibrary($2);
190                 free($2);
191         }
192         ;
193
194 variable: variable_decl identifier T_EQUAL value
195         {
196                 Value *value = $4;
197                 if (value->IsObjectType<ExpressionList>()) {
198                         Dictionary::Ptr dict = make_shared<Dictionary>();
199                         ExpressionList::Ptr exprl = *value;
200                         exprl->Execute(dict);
201                         delete value;
202                         value = new Value(dict);
203                 }
204
205                 ScriptVariable::Ptr sv = ScriptVariable::Set($2, *value);
206
207                 if (!$1)
208                         sv->SetConstant(true);
209
210                 free($2);
211                 delete value;
212         }
213         ;
214
215 variable_decl: T_VAR
216         {
217                 $$ = true;
218         }
219         | T_CONST
220         {
221                 $$ = false;
222         }
223         ;
224
225 identifier: T_IDENTIFIER
226         | T_STRING
227         {
228                 $$ = $1;
229         }
230         ;
231
232 type: partial_specifier T_TYPE identifier
233         {
234                 String name = String($3);
235                 free($3);
236
237                 m_Type = ConfigType::GetByName(name);
238
239                 if (!m_Type) {
240                         if ($1)
241                                 BOOST_THROW_EXCEPTION(std::invalid_argument("Partial type definition for unknown type '" + name + "'"));
242
243                         m_Type = make_shared<ConfigType>(name, yylloc);
244                         m_Type->Register();
245                 }
246         }
247         type_inherits_specifier typerulelist
248         {
249                 TypeRuleList::Ptr ruleList = *$6;
250                 m_Type->GetRuleList()->AddRules(ruleList);
251                 m_Type->GetRuleList()->AddRequires(ruleList);
252
253                 String validator = ruleList->GetValidator();
254                 if (!validator.IsEmpty())
255                         m_Type->GetRuleList()->SetValidator(validator);
256
257                 delete $6;
258         }
259         ;
260
261 partial_specifier: /* Empty */
262         {
263                 $$ = 0;
264         }
265         | T_PARTIAL
266         {
267                 $$ = 1;
268         }
269         ;
270
271 typerulelist: '{'
272         {
273                 m_RuleLists.push(make_shared<TypeRuleList>());
274         }
275         typerules
276         '}'
277         {
278                 $$ = new Value(m_RuleLists.top());
279                 m_RuleLists.pop();
280         }
281         ;
282
283 typerules: typerules_inner
284         | typerules_inner ','
285
286 typerules_inner: /* empty */
287         | typerule
288         | typerules_inner ',' typerule
289         ;
290
291 typerule: T_REQUIRE T_STRING
292         {
293                 m_RuleLists.top()->AddRequire($2);
294                 free($2);
295         }
296         | T_VALIDATOR T_STRING
297         {
298                 m_RuleLists.top()->SetValidator($2);
299                 free($2);
300         }
301         | T_ATTRIBUTE type T_STRING
302         {
303                 TypeRule rule($2, String(), $3, TypeRuleList::Ptr(), yylloc);
304                 free($3);
305
306                 m_RuleLists.top()->AddRule(rule);
307         }
308         | T_ATTRIBUTE T_TYPE_NAME '(' identifier ')' T_STRING
309         {
310                 TypeRule rule($2, $4, $6, TypeRuleList::Ptr(), yylloc);
311                 free($4);
312                 free($6);
313
314                 m_RuleLists.top()->AddRule(rule);
315         }
316         | T_ATTRIBUTE type T_STRING typerulelist
317         {
318                 TypeRule rule($2, String(), $3, *$4, yylloc);
319                 free($3);
320                 delete $4;
321                 m_RuleLists.top()->AddRule(rule);
322         }
323         ;
324
325 type_inherits_specifier: /* empty */
326         | T_INHERITS identifier
327         {
328                 m_Type->SetParent($2);
329                 free($2);
330         }
331         ;
332
333 type: T_TYPE_DICTIONARY
334         | T_TYPE_ARRAY
335         | T_TYPE_NUMBER
336         | T_TYPE_STRING
337         | T_TYPE_SCALAR
338         | T_TYPE_ANY
339         | T_TYPE_NAME
340         {
341                 $$ = $1;
342         }
343         ;
344
345 object:
346         {
347                 m_Abstract = false;
348         }
349 object_declaration identifier T_STRING object_inherits_specifier expressionlist
350         {
351                 ConfigItemBuilder::Ptr item = make_shared<ConfigItemBuilder>(yylloc);
352
353                 item->SetType($3);
354
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 ':'";
358                         free($3);
359                         BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str()));
360                 }
361
362                 free($3);
363
364                 item->SetName($4);
365                 free($4);
366
367                 if ($5) {
368                         BOOST_FOREACH(const String& parent, *$5) {
369                                 item->AddParent(parent);
370                         }
371
372                         delete $5;
373                 }
374
375                 if ($6) {
376                         ExpressionList::Ptr exprl = ExpressionList::Ptr($6);
377                         item->AddExpressionList(exprl);
378                 }
379
380                 item->SetAbstract(m_Abstract);
381
382                 item->Compile()->Register();
383                 item.reset();
384         }
385         ;
386
387 object_declaration: T_OBJECT
388         | T_TEMPLATE
389         {
390                 m_Abstract = true;
391         }
392
393 object_inherits_list:
394         {
395                 $$ = NULL;
396         }
397         | T_STRING
398         {
399                 $$ = new std::vector<String>();
400                 $$->push_back($1);
401                 free($1);
402         }
403         | object_inherits_list ',' T_STRING
404         {
405                 if ($1)
406                         $$ = $1;
407                 else
408                         $$ = new std::vector<String>();
409
410                 $$->push_back($3);
411                 free($3);
412         }
413         ;
414
415 object_inherits_specifier:
416         {
417                 $$ = NULL;
418         }
419         | T_INHERITS object_inherits_list
420         {
421                 $$ = $2;
422         }
423         ;
424
425 expressionlist: '{' expressions '}'
426         {
427                 if ($2)
428                         $$ = $2;
429                 else
430                         $$ = new ExpressionList();
431         }
432         ;
433
434 expressions: expressions_inner
435         {
436                 $$ = $1;
437         }
438         | expressions_inner ','
439         {
440                 $$ = $1;
441         }
442
443 expressions_inner: /* empty */
444         {
445                 $$ = NULL;
446         }
447         | expression
448         {
449                 $$ = new ExpressionList();
450                 $$->AddExpression(*$1);
451                 delete $1;
452         }
453         | expressions_inner ',' expression
454         {
455                 if ($1)
456                         $$ = $1;
457                 else
458                         $$ = new ExpressionList();
459
460                 $$->AddExpression(*$3);
461                 delete $3;
462         }
463         ;
464
465 expression: identifier operator value
466         {
467                 $$ = new Expression($1, $2, *$3, yylloc);
468                 free($1);
469                 delete $3;
470         }
471         | identifier '[' T_STRING ']' operator value
472         {
473                 Expression subexpr($3, $5, *$6, yylloc);
474                 free($3);
475                 delete $6;
476
477                 ExpressionList::Ptr subexprl = make_shared<ExpressionList>();
478                 subexprl->AddExpression(subexpr);
479
480                 $$ = new Expression($1, OperatorPlus, subexprl, yylloc);
481                 free($1);
482         }
483         ;
484
485 operator: T_EQUAL
486         | T_PLUS_EQUAL
487         | T_MINUS_EQUAL
488         | T_MULTIPLY_EQUAL
489         | T_DIVIDE_EQUAL
490         {
491                 $$ = $1;
492         }
493         ;
494
495 array: '[' array_items ']'
496         {
497                 $$ = $2;
498         }
499         ;
500
501 array_items: array_items_inner
502         {
503                 $$ = $1;
504         }
505         | array_items_inner ','
506         {
507                 $$ = $1;
508         }
509
510 array_items_inner: /* empty */
511         {
512                 $$ = NULL;
513         }
514         | value
515         {
516                 $$ = new Array();
517
518                 if ($1->IsObjectType<ExpressionList>()) {
519                         ExpressionList::Ptr exprl = *$1;
520                         Dictionary::Ptr dict = make_shared<Dictionary>();
521                         exprl->Execute(dict);
522                         delete $1;
523                         $1 = new Value(dict);
524                 }
525
526                 $$->Add(*$1);
527                 delete $1;
528         }
529         | array_items_inner ',' value
530         {
531                 if ($1)
532                         $$ = $1;
533                 else
534                         $$ = new Array();
535
536                 if ($3->IsObjectType<ExpressionList>()) {
537                         ExpressionList::Ptr exprl = *$3;
538                         Dictionary::Ptr dict = make_shared<Dictionary>();
539                         exprl->Execute(dict);
540                         delete $3;
541                         $3 = new Value(dict);
542                 }
543
544                 $$->Add(*$3);
545                 delete $3;
546         }
547         ;
548
549 simplevalue: T_STRING
550         {
551                 $$ = new Value($1);
552                 free($1);
553         }
554         | T_NUMBER
555         {
556                 $$ = new Value($1);
557         }
558         | T_NULL
559         {
560                 $$ = new Value();
561         }
562         | array
563         {
564                 if ($1 == NULL)
565                         $1 = new Array();
566
567                 Array::Ptr array = Array::Ptr($1);
568                 $$ = new Value(array);
569         }
570         ;
571
572 aterm: '(' aexpression ')'
573         {
574                 $$ = $2;
575         }
576
577 aexpression: T_STRING
578         {
579                 $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, $1)));
580                 free($1);
581         }
582         | T_NUMBER
583         {
584                 $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, $1)));
585         }
586         | T_IDENTIFIER
587         {
588                 $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATVariable, $1)));
589                 free($1);
590         }
591         | '~' aexpression
592         {
593                 $$ = new Value(make_shared<AExpression>(AENegate, static_cast<AExpression::Ptr>(*$2)));
594                 delete $2;
595         }
596         | aexpression '+' aexpression
597         {
598                 $$ = new Value(make_shared<AExpression>(AEAdd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
599                 delete $1;
600                 delete $3;
601         }
602         | aexpression '-' aexpression
603         {
604                 $$ = new Value(make_shared<AExpression>(AESubtract, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
605                 delete $1;
606                 delete $3;
607         }
608         | aexpression '*' aexpression
609         {
610                 $$ = new Value(make_shared<AExpression>(AEMultiply, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
611                 delete $1;
612                 delete $3;
613         }
614         | aexpression '/' aexpression
615         {
616                 $$ = new Value(make_shared<AExpression>(AEDivide, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
617                 delete $1;
618                 delete $3;
619         }
620         | aexpression '&' aexpression
621         {
622                 $$ = new Value(make_shared<AExpression>(AEBinaryAnd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
623                 delete $1;
624                 delete $3;
625         }
626         | aexpression '|' aexpression
627         {
628                 $$ = new Value(make_shared<AExpression>(AEBinaryOr, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
629                 delete $1;
630                 delete $3;
631         }
632         | aexpression T_SHIFT_LEFT aexpression
633         {
634                 $$ = new Value(make_shared<AExpression>(AEShiftLeft, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
635                 delete $1;
636                 delete $3;
637         }
638         | aexpression T_SHIFT_RIGHT aexpression
639         {
640                 $$ = new Value(make_shared<AExpression>(AEShiftRight, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
641                 delete $1;
642                 delete $3;
643         }
644         | '(' aexpression ')'
645         {
646                 $$ = $2;
647         }
648         ;
649
650 value: simplevalue
651         | expressionlist
652         {
653                 ExpressionList::Ptr exprl = ExpressionList::Ptr($1);
654                 $$ = new Value(exprl);
655         }
656         | aterm
657         {
658                 AExpression::Ptr aexpr = *$1;
659                 $$ = new Value(aexpr->Evaluate(Object::Ptr()));
660                 delete $1;
661         }
662         ;
663 %%