1%{ 2#define YYDEBUG 1 3 4/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ 5 6#include "config/i2-config.hpp" 7#include "config/configcompiler.hpp" 8#include "config/expression.hpp" 9#include "config/applyrule.hpp" 10#include "config/objectrule.hpp" 11#include "base/value.hpp" 12#include "base/utility.hpp" 13#include "base/exception.hpp" 14#include "base/configtype.hpp" 15#include "base/exception.hpp" 16#include <sstream> 17#include <stack> 18 19#define YYLTYPE icinga::CompilerDebugInfo 20#define YYERROR_VERBOSE 21 22#define YYLLOC_DEFAULT(Current, Rhs, N) \ 23do { \ 24 if (N) { \ 25 (Current).Path = YYRHSLOC(Rhs, 1).Path; \ 26 (Current).FirstLine = YYRHSLOC(Rhs, 1).FirstLine; \ 27 (Current).FirstColumn = YYRHSLOC(Rhs, 1).FirstColumn; \ 28 (Current).LastLine = YYRHSLOC(Rhs, N).LastLine; \ 29 (Current).LastColumn = YYRHSLOC(Rhs, N).LastColumn; \ 30 } else { \ 31 (Current).Path = YYRHSLOC(Rhs, 0).Path; \ 32 (Current).FirstLine = (Current).LastLine = \ 33 YYRHSLOC(Rhs, 0).LastLine; \ 34 (Current).FirstColumn = (Current).LastColumn = \ 35 YYRHSLOC(Rhs, 0).LastColumn; \ 36 } \ 37} while (0) 38 39#define YY_LOCATION_PRINT(file, loc) \ 40do { \ 41 std::ostringstream msgbuf; \ 42 msgbuf << loc; \ 43 std::string str = msgbuf.str(); \ 44 fputs(str.c_str(), file); \ 45} while (0) 46 47#define YYINITDEPTH 10000 48 49using namespace icinga; 50 51template<typename T> 52static void MakeRBinaryOp(Expression** result, Expression *left, Expression *right, const DebugInfo& diLeft, const DebugInfo& diRight) 53{ 54 *result = new T(std::unique_ptr<Expression>(left), std::unique_ptr<Expression>(right), DebugInfoRange(diLeft, diRight)); 55} 56 57%} 58 59%pure-parser 60 61%locations 62%defines 63%error-verbose 64%glr-parser 65 66%parse-param { std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> > *llist } 67%parse-param { ConfigCompiler *context } 68%lex-param { void *scanner } 69 70%union { 71 String *text; 72 double num; 73 bool boolean; 74 icinga::Expression *expr; 75 icinga::DictExpression *dexpr; 76 CombinedSetOp csop; 77 std::vector<String> *slist; 78 std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> > *llist; 79 std::vector<std::unique_ptr<Expression> > *elist; 80 std::vector<std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression> > > *ebranchlist; 81 std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression> > *ebranch; 82 std::pair<String, std::unique_ptr<Expression> > *cvitem; 83 std::map<String, std::unique_ptr<Expression> > *cvlist; 84 icinga::ScopeSpecifier scope; 85} 86 87%token T_NEWLINE "new-line" 88%token <text> T_STRING 89%token <text> T_STRING_ANGLE 90%token <num> T_NUMBER 91%token <boolean> T_BOOLEAN 92%token T_NULL 93%token <text> T_IDENTIFIER 94 95%token <csop> T_SET "= (T_SET)" 96%token <csop> T_SET_ADD "+= (T_SET_ADD)" 97%token <csop> T_SET_SUBTRACT "-= (T_SET_SUBTRACT)" 98%token <csop> T_SET_MULTIPLY "*= (T_SET_MULTIPLY)" 99%token <csop> T_SET_DIVIDE "/= (T_SET_DIVIDE)" 100%token <csop> T_SET_MODULO "%= (T_SET_MODULO)" 101%token <csop> T_SET_XOR "^= (T_SET_XOR)" 102%token <csop> T_SET_BINARY_AND "&= (T_SET_BINARY_AND)" 103%token <csop> T_SET_BINARY_OR "|= (T_SET_BINARY_OR)" 104 105%token T_SHIFT_LEFT "<< (T_SHIFT_LEFT)" 106%token T_SHIFT_RIGHT ">> (T_SHIFT_RIGHT)" 107%token T_EQUAL "== (T_EQUAL)" 108%token T_NOT_EQUAL "!= (T_NOT_EQUAL)" 109%token T_IN "in (T_IN)" 110%token T_NOT_IN "!in (T_NOT_IN)" 111%token T_LOGICAL_AND "&& (T_LOGICAL_AND)" 112%token T_LOGICAL_OR "|| (T_LOGICAL_OR)" 113%token T_LESS_THAN_OR_EQUAL "<= (T_LESS_THAN_OR_EQUAL)" 114%token T_GREATER_THAN_OR_EQUAL ">= (T_GREATER_THAN_OR_EQUAL)" 115%token T_PLUS "+ (T_PLUS)" 116%token T_MINUS "- (T_MINUS)" 117%token T_MULTIPLY "* (T_MULTIPLY)" 118%token T_DIVIDE_OP "/ (T_DIVIDE_OP)" 119%token T_MODULO "% (T_MODULO)" 120%token T_XOR "^ (T_XOR)" 121%token T_BINARY_AND "& (T_BINARY_AND)" 122%token T_BINARY_OR "| (T_BINARY_OR)" 123%token T_LESS_THAN "< (T_LESS_THAN)" 124%token T_GREATER_THAN "> (T_GREATER_THAN)" 125 126%token T_VAR "var (T_VAR)" 127%token T_GLOBALS "globals (T_GLOBALS)" 128%token T_LOCALS "locals (T_LOCALS)" 129%token T_CONST "const (T_CONST)" 130%token T_DEFAULT "default (T_DEFAULT)" 131%token T_IGNORE_ON_ERROR "ignore_on_error (T_IGNORE_ON_ERROR)" 132%token T_CURRENT_FILENAME "current_filename (T_CURRENT_FILENAME)" 133%token T_CURRENT_LINE "current_line (T_CURRENT_LINE)" 134%token T_DEBUGGER "debugger (T_DEBUGGER)" 135%token T_NAMESPACE "namespace (T_NAMESPACE)" 136%token T_USE "use (T_USE)" 137%token T_USING "using (T_USING)" 138%token T_OBJECT "object (T_OBJECT)" 139%token T_TEMPLATE "template (T_TEMPLATE)" 140%token T_INCLUDE "include (T_INCLUDE)" 141%token T_INCLUDE_RECURSIVE "include_recursive (T_INCLUDE_RECURSIVE)" 142%token T_INCLUDE_ZONES "include_zones (T_INCLUDE_ZONES)" 143%token T_LIBRARY "library (T_LIBRARY)" 144%token T_APPLY "apply (T_APPLY)" 145%token T_TO "to (T_TO)" 146%token T_WHERE "where (T_WHERE)" 147%token T_IMPORT "import (T_IMPORT)" 148%token T_ASSIGN "assign (T_ASSIGN)" 149%token T_IGNORE "ignore (T_IGNORE)" 150%token T_FUNCTION "function (T_FUNCTION)" 151%token T_RETURN "return (T_RETURN)" 152%token T_BREAK "break (T_BREAK)" 153%token T_CONTINUE "continue (T_CONTINUE)" 154%token T_FOR "for (T_FOR)" 155%token T_IF "if (T_IF)" 156%token T_ELSE "else (T_ELSE)" 157%token T_WHILE "while (T_WHILE)" 158%token T_THROW "throw (T_THROW)" 159%token T_TRY "try (T_TRY)" 160%token T_EXCEPT "except (T_EXCEPT)" 161%token T_FOLLOWS "=> (T_FOLLOWS)" 162%token T_NULLARY_LAMBDA_BEGIN "{{ (T_NULLARY_LAMBDA_BEGIN)" 163%token T_NULLARY_LAMBDA_END "}} (T_NULLARY_LAMBDA_END)" 164 165%type <text> identifier 166%type <elist> rterm_items 167%type <elist> rterm_items_inner 168%type <slist> identifier_items 169%type <slist> identifier_items_inner 170%type <csop> combined_set_op 171%type <llist> statements 172%type <llist> lterm_items 173%type <llist> lterm_items_inner 174%type <expr> rterm 175%type <expr> rterm_array 176%type <dexpr> rterm_dict 177%type <dexpr> rterm_scope_require_side_effect 178%type <dexpr> rterm_scope 179%type <ebranchlist> else_if_branches 180%type <ebranch> else_if_branch 181%type <expr> rterm_side_effect 182%type <expr> rterm_no_side_effect 183%type <expr> rterm_no_side_effect_no_dict 184%type <expr> lterm 185%type <expr> object 186%type <expr> apply 187%type <expr> optional_rterm 188%type <text> target_type_specifier 189%type <boolean> default_specifier 190%type <boolean> ignore_specifier 191%type <cvlist> use_specifier 192%type <cvlist> use_specifier_items 193%type <cvitem> use_specifier_item 194%type <num> object_declaration 195 196%right T_FOLLOWS 197%right T_INCLUDE T_INCLUDE_RECURSIVE T_INCLUDE_ZONES T_OBJECT T_TEMPLATE T_APPLY T_IMPORT T_ASSIGN T_IGNORE T_WHERE 198%right T_FUNCTION T_FOR 199%left T_SET T_SET_ADD T_SET_SUBTRACT T_SET_MULTIPLY T_SET_DIVIDE T_SET_MODULO T_SET_XOR T_SET_BINARY_AND T_SET_BINARY_OR 200%right '?' ':' 201%left T_LOGICAL_OR 202%left T_LOGICAL_AND 203%left T_RETURN T_BREAK T_CONTINUE 204%left T_IDENTIFIER 205%left T_BINARY_OR 206%left T_XOR 207%left T_BINARY_AND 208%nonassoc T_EQUAL T_NOT_EQUAL 209%left T_IN T_NOT_IN 210%nonassoc T_LESS_THAN T_LESS_THAN_OR_EQUAL T_GREATER_THAN T_GREATER_THAN_OR_EQUAL 211%left T_SHIFT_LEFT T_SHIFT_RIGHT 212%left T_PLUS T_MINUS 213%left T_MULTIPLY T_DIVIDE_OP T_MODULO 214%left UNARY_MINUS UNARY_PLUS 215%right REF_OP DEREF_OP 216%right '!' '~' 217%left '.' '(' '[' 218%left T_VAR T_THIS T_GLOBALS T_LOCALS 219%right ';' ',' 220%right T_NEWLINE 221%{ 222 223int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner); 224 225extern int yydebug; 226 227void yyerror(const YYLTYPE *locp, std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> > *, ConfigCompiler *context, const char *err) 228{ 229 bool incomplete = context && context->m_Eof && (context->m_OpenBraces > 0); 230 BOOST_THROW_EXCEPTION(ScriptError(err, *locp, incomplete)); 231} 232 233int yyparse(std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> > *llist, ConfigCompiler *context); 234 235static void BeginFlowControlBlock(ConfigCompiler *compiler, int allowedTypes, bool inherit) 236{ 237 if (inherit) 238 allowedTypes |= compiler->m_FlowControlInfo.top(); 239 240 compiler->m_FlowControlInfo.push(allowedTypes); 241} 242 243static void EndFlowControlBlock(ConfigCompiler *compiler) 244{ 245 compiler->m_FlowControlInfo.pop(); 246} 247 248static void UseFlowControl(ConfigCompiler *compiler, FlowControlType type, const CompilerDebugInfo& location) 249{ 250 int fci = compiler->m_FlowControlInfo.top(); 251 252 if ((type & fci) != type) 253 BOOST_THROW_EXCEPTION(ScriptError("Invalid flow control statement.", location)); 254} 255 256std::unique_ptr<Expression> ConfigCompiler::Compile() 257{ 258 std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> > llist; 259 260 //yydebug = 1; 261 262 m_IgnoreNewlines.push(false); 263 BeginFlowControlBlock(this, 0, false); 264 265 if (yyparse(&llist, this) != 0) 266 return NULL; 267 268 EndFlowControlBlock(this); 269 m_IgnoreNewlines.pop(); 270 271 std::vector<std::unique_ptr<Expression> > dlist; 272 decltype(llist.size()) num = 0; 273 for (auto& litem : llist) { 274 if (!litem.second.SideEffect && num != llist.size() - 1) { 275 yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used."); 276 } 277 dlist.emplace_back(std::move(litem.first)); 278 num++; 279 } 280 281 std::unique_ptr<DictExpression> expr{new DictExpression(std::move(dlist))}; 282 expr->MakeInline(); 283 return std::move(expr); 284} 285 286#define scanner (context->GetScanner()) 287 288%} 289 290%% 291script: statements 292 { 293 llist->swap(*$1); 294 delete $1; 295 } 296 ; 297 298statements: optional_newlines lterm_items 299 { 300 $$ = $2; 301 } 302 ; 303 304lterm_items: /* empty */ 305 { 306 $$ = new std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> >(); 307 } 308 | lterm_items_inner 309 | lterm_items_inner sep 310 ; 311 312lterm_items_inner: lterm %dprec 2 313 { 314 $$ = new std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> >(); 315 $$->emplace_back(std::unique_ptr<Expression>($1), EItemInfo{true, @1}); 316 } 317 | rterm_no_side_effect 318 { 319 $$ = new std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> >(); 320 $$->emplace_back(std::unique_ptr<Expression>($1), EItemInfo{false, @1}); 321 } 322 | lterm_items_inner sep lterm %dprec 1 323 { 324 if ($1) 325 $$ = $1; 326 else 327 $$ = new std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> >(); 328 329 if ($3) { 330 $$->emplace_back(std::unique_ptr<Expression>($3), EItemInfo{true, @3}); 331 } 332 } 333 | lterm_items_inner sep rterm_no_side_effect %dprec 1 334 { 335 if ($1) 336 $$ = $1; 337 else 338 $$ = new std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> >(); 339 340 if ($3) { 341 $$->emplace_back(std::unique_ptr<Expression>($3), EItemInfo{false, @3}); 342 } 343 } 344 ; 345 346identifier: T_IDENTIFIER 347 | T_STRING 348 ; 349 350object: 351 { 352 context->m_ObjectAssign.push(true); 353 context->m_SeenAssign.push(false); 354 context->m_SeenIgnore.push(false); 355 context->m_Assign.push(0); 356 context->m_Ignore.push(0); 357 } 358 object_declaration rterm optional_rterm use_specifier default_specifier ignore_specifier 359 { 360 BeginFlowControlBlock(context, FlowControlReturn, false); 361 } 362 rterm_scope_require_side_effect 363 { 364 EndFlowControlBlock(context); 365 366 context->m_ObjectAssign.pop(); 367 368 bool abstract = $2; 369 bool defaultTmpl = $6; 370 371 if (!abstract && defaultTmpl) 372 BOOST_THROW_EXCEPTION(ScriptError("'default' keyword is invalid for object definitions", @6)); 373 374 bool seen_assign = context->m_SeenAssign.top(); 375 context->m_SeenAssign.pop(); 376 377 bool seen_ignore = context->m_SeenIgnore.top(); 378 context->m_SeenIgnore.pop(); 379 380 std::unique_ptr<Expression> ignore{std::move(context->m_Ignore.top())}; 381 context->m_Ignore.pop(); 382 383 std::unique_ptr<Expression> assign{std::move(context->m_Assign.top())}; 384 context->m_Assign.pop(); 385 386 std::unique_ptr<Expression> filter; 387 388 if (seen_assign) { 389 if (ignore) { 390 std::unique_ptr<Expression> rex{new LogicalNegateExpression(std::move(ignore), DebugInfoRange(@2, @5))}; 391 392 filter.reset(new LogicalAndExpression(std::move(assign), std::move(rex), DebugInfoRange(@2, @5))); 393 } else 394 filter.swap(assign); 395 } else if (seen_ignore) { 396 BOOST_THROW_EXCEPTION(ScriptError("object rule 'ignore where' cannot be used without 'assign where'", DebugInfoRange(@2, @4))); 397 } 398 399 $$ = new ObjectExpression(abstract, std::unique_ptr<Expression>($3), std::unique_ptr<Expression>($4), 400 std::move(filter), context->GetZone(), context->GetPackage(), std::move(*$5), $6, $7, 401 std::unique_ptr<Expression>($9), DebugInfoRange(@2, @7)); 402 delete $5; 403 } 404 ; 405 406object_declaration: T_OBJECT 407 { 408 $$ = false; 409 } 410 | T_TEMPLATE 411 { 412 $$ = true; 413 } 414 ; 415 416identifier_items: /* empty */ 417 { 418 $$ = new std::vector<String>(); 419 } 420 | identifier_items_inner 421 | identifier_items_inner ',' 422 ; 423 424identifier_items_inner: identifier 425 { 426 $$ = new std::vector<String>(); 427 $$->emplace_back(std::move(*$1)); 428 delete $1; 429 } 430 | identifier_items_inner ',' identifier 431 { 432 if ($1) 433 $$ = $1; 434 else 435 $$ = new std::vector<String>(); 436 437 $$->emplace_back(std::move(*$3)); 438 delete $3; 439 } 440 ; 441 442combined_set_op: T_SET 443 | T_SET_ADD 444 | T_SET_SUBTRACT 445 | T_SET_MULTIPLY 446 | T_SET_DIVIDE 447 | T_SET_MODULO 448 | T_SET_XOR 449 | T_SET_BINARY_AND 450 | T_SET_BINARY_OR 451 ; 452 453optional_var: /* empty */ 454 | T_VAR 455 ; 456 457lterm: T_LIBRARY rterm 458 { 459 $$ = new LibraryExpression(std::unique_ptr<Expression>($2), @$); 460 } 461 | rterm combined_set_op rterm 462 { 463 $$ = new SetExpression(std::unique_ptr<Expression>($1), $2, std::unique_ptr<Expression>($3), @$); 464 } 465 | T_INCLUDE rterm 466 { 467 $$ = new IncludeExpression(Utility::DirName(context->GetPath()), std::unique_ptr<Expression>($2), NULL, NULL, IncludeRegular, false, context->GetZone(), context->GetPackage(), @$); 468 } 469 | T_INCLUDE T_STRING_ANGLE 470 { 471 $$ = new IncludeExpression(Utility::DirName(context->GetPath()), MakeLiteral(std::move(*$2)), NULL, NULL, IncludeRegular, true, context->GetZone(), context->GetPackage(), @$); 472 delete $2; 473 } 474 | T_INCLUDE_RECURSIVE rterm 475 { 476 $$ = new IncludeExpression(Utility::DirName(context->GetPath()), std::unique_ptr<Expression>($2), MakeLiteral("*.conf"), NULL, IncludeRecursive, false, context->GetZone(), context->GetPackage(), @$); 477 } 478 | T_INCLUDE_RECURSIVE rterm ',' rterm 479 { 480 $$ = new IncludeExpression(Utility::DirName(context->GetPath()), std::unique_ptr<Expression>($2), std::unique_ptr<Expression>($4), NULL, IncludeRecursive, false, context->GetZone(), context->GetPackage(), @$); 481 } 482 | T_INCLUDE_ZONES rterm ',' rterm 483 { 484 $$ = new IncludeExpression(Utility::DirName(context->GetPath()), std::unique_ptr<Expression>($4), MakeLiteral("*.conf"), std::unique_ptr<Expression>($2), IncludeZones, false, context->GetZone(), context->GetPackage(), @$); 485 } 486 | T_INCLUDE_ZONES rterm ',' rterm ',' rterm 487 { 488 $$ = new IncludeExpression(Utility::DirName(context->GetPath()), std::unique_ptr<Expression>($4), std::unique_ptr<Expression>($6), std::unique_ptr<Expression>($2), IncludeZones, false, context->GetZone(), context->GetPackage(), @$); 489 } 490 | T_IMPORT rterm 491 { 492 $$ = new ImportExpression(std::unique_ptr<Expression>($2), @$); 493 } 494 | T_ASSIGN T_WHERE 495 { 496 BeginFlowControlBlock(context, FlowControlReturn, false); 497 } 498 rterm_scope %dprec 2 499 { 500 EndFlowControlBlock(context); 501 502 if ((context->m_Apply.empty() || !context->m_Apply.top()) && (context->m_ObjectAssign.empty() || !context->m_ObjectAssign.top())) 503 BOOST_THROW_EXCEPTION(ScriptError("'assign' keyword not valid in this context.", @$)); 504 505 context->m_SeenAssign.top() = true; 506 507 if (context->m_Assign.top()) 508 context->m_Assign.top() = new LogicalOrExpression(std::unique_ptr<Expression>(context->m_Assign.top()), std::unique_ptr<Expression>($4), @$); 509 else 510 context->m_Assign.top() = $4; 511 512 $$ = MakeLiteralRaw(); 513 } 514 | T_ASSIGN T_WHERE rterm %dprec 1 515 { 516 ASSERT(!dynamic_cast<DictExpression *>($3)); 517 518 if ((context->m_Apply.empty() || !context->m_Apply.top()) && (context->m_ObjectAssign.empty() || !context->m_ObjectAssign.top())) 519 BOOST_THROW_EXCEPTION(ScriptError("'assign' keyword not valid in this context.", @$)); 520 521 context->m_SeenAssign.top() = true; 522 523 if (context->m_Assign.top()) 524 context->m_Assign.top() = new LogicalOrExpression(std::unique_ptr<Expression>(context->m_Assign.top()), std::unique_ptr<Expression>($3), @$); 525 else 526 context->m_Assign.top() = $3; 527 528 $$ = MakeLiteralRaw(); 529 } 530 | T_IGNORE T_WHERE 531 { 532 BeginFlowControlBlock(context, FlowControlReturn, false); 533 } 534 rterm_scope %dprec 2 535 { 536 EndFlowControlBlock(context); 537 538 if ((context->m_Apply.empty() || !context->m_Apply.top()) && (context->m_ObjectAssign.empty() || !context->m_ObjectAssign.top())) 539 BOOST_THROW_EXCEPTION(ScriptError("'ignore' keyword not valid in this context.", @$)); 540 541 context->m_SeenIgnore.top() = true; 542 543 if (context->m_Ignore.top()) 544 context->m_Ignore.top() = new LogicalOrExpression(std::unique_ptr<Expression>(context->m_Ignore.top()), std::unique_ptr<Expression>($4), @$); 545 else 546 context->m_Ignore.top() = $4; 547 548 $$ = MakeLiteralRaw(); 549 } 550 | T_IGNORE T_WHERE rterm %dprec 1 551 { 552 ASSERT(!dynamic_cast<DictExpression *>($3)); 553 554 if ((context->m_Apply.empty() || !context->m_Apply.top()) && (context->m_ObjectAssign.empty() || !context->m_ObjectAssign.top())) 555 BOOST_THROW_EXCEPTION(ScriptError("'ignore' keyword not valid in this context.", @$)); 556 557 context->m_SeenIgnore.top() = true; 558 559 if (context->m_Ignore.top()) 560 context->m_Ignore.top() = new LogicalOrExpression(std::unique_ptr<Expression>(context->m_Ignore.top()), std::unique_ptr<Expression>($3), @$); 561 else 562 context->m_Ignore.top() = $3; 563 564 $$ = MakeLiteralRaw(); 565 } 566 | T_RETURN optional_rterm 567 { 568 UseFlowControl(context, FlowControlReturn, @$); 569 $$ = new ReturnExpression(std::unique_ptr<Expression>($2), @$); 570 } 571 | T_BREAK 572 { 573 UseFlowControl(context, FlowControlBreak, @$); 574 $$ = new BreakExpression(@$); 575 } 576 | T_CONTINUE 577 { 578 UseFlowControl(context, FlowControlContinue, @$); 579 $$ = new ContinueExpression(@$); 580 } 581 | T_DEBUGGER 582 { 583 $$ = new BreakpointExpression(@$); 584 } 585 | T_NAMESPACE rterm 586 { 587 BeginFlowControlBlock(context, FlowControlReturn, false); 588 } 589 rterm_scope_require_side_effect 590 { 591 EndFlowControlBlock(context); 592 593 std::unique_ptr<Expression> expr{$2}; 594 BindToScope(expr, ScopeGlobal); 595 $$ = new SetExpression(std::move(expr), OpSetLiteral, std::unique_ptr<Expression>(new NamespaceExpression(std::unique_ptr<Expression>($4), @$)), @$); 596 } 597 | T_USING rterm 598 { 599 Expression::Ptr expr{$2}; 600 context->AddImport(std::move(expr)); 601 $$ = MakeLiteralRaw(); 602 } 603 | apply 604 | object 605 | T_FOR '(' optional_var identifier T_FOLLOWS optional_var identifier T_IN rterm ')' 606 { 607 BeginFlowControlBlock(context, FlowControlContinue | FlowControlBreak, true); 608 } 609 rterm_scope_require_side_effect 610 { 611 EndFlowControlBlock(context); 612 613 $$ = new ForExpression(std::move(*$4), std::move(*$7), std::unique_ptr<Expression>($9), std::unique_ptr<Expression>($12), @$); 614 delete $4; 615 delete $7; 616 } 617 | T_FOR '(' optional_var identifier T_IN rterm ')' 618 { 619 BeginFlowControlBlock(context, FlowControlContinue | FlowControlBreak, true); 620 } 621 rterm_scope_require_side_effect 622 { 623 EndFlowControlBlock(context); 624 625 $$ = new ForExpression(std::move(*$4), "", std::unique_ptr<Expression>($6), std::unique_ptr<Expression>($9), @$); 626 delete $4; 627 } 628 | T_FUNCTION identifier '(' identifier_items ')' use_specifier 629 { 630 BeginFlowControlBlock(context, FlowControlReturn, false); 631 } 632 rterm_scope 633 { 634 EndFlowControlBlock(context); 635 636 std::unique_ptr<FunctionExpression> fexpr{new FunctionExpression(*$2, std::move(*$4), std::move(*$6), std::unique_ptr<Expression>($8), @$)}; 637 delete $4; 638 delete $6; 639 640 $$ = new SetExpression(MakeIndexer(ScopeThis, std::move(*$2)), OpSetLiteral, std::move(fexpr), @$); 641 delete $2; 642 } 643 | T_CONST T_IDENTIFIER T_SET rterm 644 { 645 $$ = new SetConstExpression(std::move(*$2), std::unique_ptr<Expression>($4), @$); 646 delete $2; 647 } 648 | T_VAR rterm 649 { 650 std::unique_ptr<Expression> expr{$2}; 651 BindToScope(expr, ScopeLocal); 652 $$ = new SetExpression(std::move(expr), OpSetLiteral, MakeLiteral(), @$); 653 } 654 | T_VAR rterm combined_set_op rterm 655 { 656 std::unique_ptr<Expression> expr{$2}; 657 BindToScope(expr, ScopeLocal); 658 $$ = new SetExpression(std::move(expr), $3, std::unique_ptr<Expression>($4), @$); 659 } 660 | T_WHILE '(' rterm ')' 661 { 662 BeginFlowControlBlock(context, FlowControlContinue | FlowControlBreak, true); 663 } 664 rterm_scope 665 { 666 EndFlowControlBlock(context); 667 668 $$ = new WhileExpression(std::unique_ptr<Expression>($3), std::unique_ptr<Expression>($6), @$); 669 } 670 | T_THROW rterm 671 { 672 $$ = new ThrowExpression(std::unique_ptr<Expression>($2), false, @$); 673 } 674 | T_TRY rterm_scope T_EXCEPT rterm_scope 675 { 676 $$ = new TryExceptExpression(std::unique_ptr<Expression>($2), std::unique_ptr<Expression>($4), @$); 677 } 678 | rterm_side_effect 679 ; 680 681rterm_items: /* empty */ 682 { 683 $$ = new std::vector<std::unique_ptr<Expression> >(); 684 } 685 | rterm_items_inner 686 | rterm_items_inner ',' optional_newlines 687 | rterm_items_inner newlines 688 ; 689 690rterm_items_inner: rterm 691 { 692 $$ = new std::vector<std::unique_ptr<Expression> >(); 693 $$->emplace_back($1); 694 } 695 | rterm_items_inner ',' optional_newlines rterm 696 { 697 $$ = $1; 698 $$->emplace_back($4); 699 } 700 ; 701 702rterm_array: '[' 703 { 704 context->m_OpenBraces++; 705 } 706 optional_newlines rterm_items ']' 707 { 708 context->m_OpenBraces--; 709 $$ = new ArrayExpression(std::move(*$4), @$); 710 delete $4; 711 } 712 ; 713 714rterm_dict: '{' 715 { 716 BeginFlowControlBlock(context, 0, false); 717 context->m_IgnoreNewlines.push(false); 718 context->m_OpenBraces++; 719 } 720 statements '}' 721 { 722 EndFlowControlBlock(context); 723 context->m_OpenBraces--; 724 context->m_IgnoreNewlines.pop(); 725 std::vector<std::unique_ptr<Expression> > dlist; 726 for (auto& litem : *$3) { 727 if (!litem.second.SideEffect) 728 yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used."); 729 dlist.emplace_back(std::move(litem.first)); 730 } 731 delete $3; 732 $$ = new DictExpression(std::move(dlist), @$); 733 } 734 ; 735 736rterm_scope_require_side_effect: '{' 737 { 738 context->m_IgnoreNewlines.push(false); 739 context->m_OpenBraces++; 740 } 741 statements '}' 742 { 743 context->m_OpenBraces--; 744 context->m_IgnoreNewlines.pop(); 745 std::vector<std::unique_ptr<Expression> > dlist; 746 for (auto& litem : *$3) { 747 if (!litem.second.SideEffect) 748 yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used."); 749 dlist.emplace_back(std::move(litem.first)); 750 } 751 delete $3; 752 $$ = new DictExpression(std::move(dlist), @$); 753 $$->MakeInline(); 754 } 755 ; 756 757rterm_scope: '{' 758 { 759 context->m_IgnoreNewlines.push(false); 760 context->m_OpenBraces++; 761 } 762 statements '}' 763 { 764 context->m_OpenBraces--; 765 context->m_IgnoreNewlines.pop(); 766 std::vector<std::unique_ptr<Expression> > dlist; 767 decltype($3->size()) num = 0; 768 for (auto& litem : *$3) { 769 if (!litem.second.SideEffect && num != $3->size() - 1) 770 yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used."); 771 dlist.emplace_back(std::move(litem.first)); 772 num++; 773 } 774 delete $3; 775 $$ = new DictExpression(std::move(dlist), @$); 776 $$->MakeInline(); 777 } 778 ; 779 780else_if_branch: T_ELSE T_IF '(' rterm ')' rterm_scope 781 { 782 $$ = new std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression> >(std::unique_ptr<Expression>($4), std::unique_ptr<Expression>($6)); 783 } 784 ; 785 786else_if_branches: /* empty */ 787 { 788 $$ = new std::vector<std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression> > >(); 789 } 790 | else_if_branches else_if_branch 791 { 792 $$ = $1; 793 $$->emplace_back(std::move(*$2)); 794 delete $2; 795 } 796 ; 797 798rterm_side_effect: rterm '(' rterm_items ')' 799 { 800 $$ = new FunctionCallExpression(std::unique_ptr<Expression>($1), std::move(*$3), @$); 801 delete $3; 802 } 803 | T_IF '(' rterm ')' rterm_scope else_if_branches 804 { 805 std::vector<std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression> > > ebranches; 806 $6->swap(ebranches); 807 delete $6; 808 809 std::unique_ptr<Expression> afalse; 810 811 for (int i = ebranches.size() - 1; i >= 0; i--) { 812 auto& ebranch = ebranches[i]; 813 afalse.reset(new ConditionalExpression(std::move(ebranch.first), std::move(ebranch.second), std::move(afalse), @6)); 814 } 815 816 $$ = new ConditionalExpression(std::unique_ptr<Expression>($3), std::unique_ptr<Expression>($5), std::move(afalse), @$); 817 } 818 | T_IF '(' rterm ')' rterm_scope else_if_branches T_ELSE rterm_scope 819 { 820 std::vector<std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression> > > ebranches; 821 $6->swap(ebranches); 822 delete $6; 823 824 $8->MakeInline(); 825 826 std::unique_ptr<Expression> afalse{$8}; 827 828 for (int i = ebranches.size() - 1; i >= 0; i--) { 829 auto& ebranch = ebranches[i]; 830 afalse.reset(new ConditionalExpression(std::move(ebranch.first), std::move(ebranch.second), std::move(afalse), @6)); 831 } 832 833 $$ = new ConditionalExpression(std::unique_ptr<Expression>($3), std::unique_ptr<Expression>($5), std::move(afalse), @$); 834 } 835 | rterm '?' rterm ':' rterm 836 { 837 $$ = new ConditionalExpression(std::unique_ptr<Expression>($1), std::unique_ptr<Expression>($3), std::unique_ptr<Expression>($5), @$); 838 } 839 ; 840 841rterm_no_side_effect_no_dict: T_STRING 842 { 843 $$ = MakeLiteralRaw(std::move(*$1)); 844 delete $1; 845 } 846 | T_NUMBER 847 { 848 $$ = MakeLiteralRaw($1); 849 } 850 | T_BOOLEAN 851 { 852 $$ = MakeLiteralRaw($1); 853 } 854 | T_NULL 855 { 856 $$ = MakeLiteralRaw(); 857 } 858 | rterm '.' T_IDENTIFIER %dprec 2 859 { 860 $$ = new IndexerExpression(std::unique_ptr<Expression>($1), MakeLiteral(std::move(*$3)), @$); 861 delete $3; 862 } 863 | rterm '[' rterm ']' 864 { 865 $$ = new IndexerExpression(std::unique_ptr<Expression>($1), std::unique_ptr<Expression>($3), @$); 866 } 867 | T_IDENTIFIER 868 { 869 $$ = new VariableExpression(std::move(*$1), context->GetImports(), @1); 870 delete $1; 871 } 872 | T_MULTIPLY rterm %prec DEREF_OP 873 { 874 $$ = new DerefExpression(std::unique_ptr<Expression>($2), @$); 875 } 876 | T_BINARY_AND rterm %prec REF_OP 877 { 878 $$ = new RefExpression(std::unique_ptr<Expression>($2), @$); 879 } 880 | '!' rterm 881 { 882 $$ = new LogicalNegateExpression(std::unique_ptr<Expression>($2), @$); 883 } 884 | '~' rterm 885 { 886 $$ = new NegateExpression(std::unique_ptr<Expression>($2), @$); 887 } 888 | T_PLUS rterm %prec UNARY_PLUS 889 { 890 $$ = $2; 891 } 892 | T_MINUS rterm %prec UNARY_MINUS 893 { 894 $$ = new SubtractExpression(MakeLiteral(0), std::unique_ptr<Expression>($2), @$); 895 } 896 | T_THIS 897 { 898 $$ = new GetScopeExpression(ScopeThis); 899 } 900 | T_GLOBALS 901 { 902 $$ = new GetScopeExpression(ScopeGlobal); 903 } 904 | T_LOCALS 905 { 906 $$ = new GetScopeExpression(ScopeLocal); 907 } 908 | T_CURRENT_FILENAME 909 { 910 $$ = MakeLiteralRaw(@$.Path); 911 } 912 | T_CURRENT_LINE 913 { 914 $$ = MakeLiteralRaw(@$.FirstLine); 915 } 916 | identifier T_FOLLOWS 917 { 918 BeginFlowControlBlock(context, FlowControlReturn, false); 919 } 920 rterm_scope %dprec 2 921 { 922 EndFlowControlBlock(context); 923 924 std::vector<String> args; 925 args.emplace_back(std::move(*$1)); 926 delete $1; 927 928 $$ = new FunctionExpression("<anonymous>", std::move(args), {}, std::unique_ptr<Expression>($4), @$); 929 } 930 | identifier T_FOLLOWS rterm %dprec 1 931 { 932 ASSERT(!dynamic_cast<DictExpression *>($3)); 933 934 std::vector<String> args; 935 args.emplace_back(std::move(*$1)); 936 delete $1; 937 938 $$ = new FunctionExpression("<anonymous>", std::move(args), {}, std::unique_ptr<Expression>($3), @$); 939 } 940 | '(' identifier_items ')' use_specifier T_FOLLOWS 941 { 942 BeginFlowControlBlock(context, FlowControlReturn, false); 943 } 944 rterm_scope %dprec 2 945 { 946 EndFlowControlBlock(context); 947 948 $$ = new FunctionExpression("<anonymous>", std::move(*$2), std::move(*$4), std::unique_ptr<Expression>($7), @$); 949 delete $2; 950 delete $4; 951 } 952 | '(' identifier_items ')' use_specifier T_FOLLOWS rterm %dprec 1 953 { 954 ASSERT(!dynamic_cast<DictExpression *>($6)); 955 956 $$ = new FunctionExpression("<anonymous>", std::move(*$2), std::move(*$4), std::unique_ptr<Expression>($6), @$); 957 delete $2; 958 delete $4; 959 } 960 | rterm_array 961 | '(' 962 { 963 context->m_OpenBraces++; 964 } 965 rterm ')' 966 { 967 context->m_OpenBraces--; 968 $$ = $3; 969 } 970 | rterm T_LOGICAL_OR rterm { MakeRBinaryOp<LogicalOrExpression>(&$$, $1, $3, @1, @3); } 971 | rterm T_LOGICAL_AND rterm { MakeRBinaryOp<LogicalAndExpression>(&$$, $1, $3, @1, @3); } 972 | rterm T_BINARY_OR rterm { MakeRBinaryOp<BinaryOrExpression>(&$$, $1, $3, @1, @3); } 973 | rterm T_BINARY_AND rterm { MakeRBinaryOp<BinaryAndExpression>(&$$, $1, $3, @1, @3); } 974 | rterm T_IN rterm { MakeRBinaryOp<InExpression>(&$$, $1, $3, @1, @3); } 975 | rterm T_NOT_IN rterm { MakeRBinaryOp<NotInExpression>(&$$, $1, $3, @1, @3); } 976 | rterm T_EQUAL rterm { MakeRBinaryOp<EqualExpression>(&$$, $1, $3, @1, @3); } 977 | rterm T_NOT_EQUAL rterm { MakeRBinaryOp<NotEqualExpression>(&$$, $1, $3, @1, @3); } 978 | rterm T_LESS_THAN rterm { MakeRBinaryOp<LessThanExpression>(&$$, $1, $3, @1, @3); } 979 | rterm T_LESS_THAN_OR_EQUAL rterm { MakeRBinaryOp<LessThanOrEqualExpression>(&$$, $1, $3, @1, @3); } 980 | rterm T_GREATER_THAN rterm { MakeRBinaryOp<GreaterThanExpression>(&$$, $1, $3, @1, @3); } 981 | rterm T_GREATER_THAN_OR_EQUAL rterm { MakeRBinaryOp<GreaterThanOrEqualExpression>(&$$, $1, $3, @1, @3); } 982 | rterm T_SHIFT_LEFT rterm { MakeRBinaryOp<ShiftLeftExpression>(&$$, $1, $3, @1, @3); } 983 | rterm T_SHIFT_RIGHT rterm { MakeRBinaryOp<ShiftRightExpression>(&$$, $1, $3, @1, @3); } 984 | rterm T_PLUS rterm { MakeRBinaryOp<AddExpression>(&$$, $1, $3, @1, @3); } 985 | rterm T_MINUS rterm { MakeRBinaryOp<SubtractExpression>(&$$, $1, $3, @1, @3); } 986 | rterm T_MULTIPLY rterm { MakeRBinaryOp<MultiplyExpression>(&$$, $1, $3, @1, @3); } 987 | rterm T_DIVIDE_OP rterm { MakeRBinaryOp<DivideExpression>(&$$, $1, $3, @1, @3); } 988 | rterm T_MODULO rterm { MakeRBinaryOp<ModuloExpression>(&$$, $1, $3, @1, @3); } 989 | rterm T_XOR rterm { MakeRBinaryOp<XorExpression>(&$$, $1, $3, @1, @3); } 990 | T_FUNCTION '(' identifier_items ')' use_specifier 991 { 992 BeginFlowControlBlock(context, FlowControlReturn, false); 993 } 994 rterm_scope 995 { 996 EndFlowControlBlock(context); 997 998 $$ = new FunctionExpression("<anonymous>", std::move(*$3), std::move(*$5), std::unique_ptr<Expression>($7), @$); 999 delete $3; 1000 delete $5; 1001 } 1002 | T_NULLARY_LAMBDA_BEGIN 1003 { 1004 BeginFlowControlBlock(context, FlowControlReturn, false); 1005 } 1006 statements T_NULLARY_LAMBDA_END 1007 { 1008 EndFlowControlBlock(context); 1009 1010 std::vector<std::unique_ptr<Expression> > dlist; 1011 decltype(dlist.size()) num = 0; 1012 for (auto& litem : *$3) { 1013 if (!litem.second.SideEffect && num != $3->size() - 1) 1014 yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used."); 1015 dlist.emplace_back(std::move(litem.first)); 1016 num++; 1017 } 1018 delete $3; 1019 std::unique_ptr<DictExpression> aexpr{new DictExpression(std::move(dlist), @$)}; 1020 aexpr->MakeInline(); 1021 1022 $$ = new FunctionExpression("<anonymous>", {}, {}, std::move(aexpr), @$); 1023 } 1024 ; 1025 1026rterm_no_side_effect: 1027 rterm_no_side_effect_no_dict %dprec 1 1028 | rterm_dict %dprec 2 1029 { 1030 std::unique_ptr<Expression> expr{$1}; 1031 BindToScope(expr, ScopeThis); 1032 $$ = expr.release(); 1033 } 1034 ; 1035 1036rterm: 1037 rterm_side_effect %dprec 2 1038 | rterm_no_side_effect %dprec 1 1039 ; 1040 1041target_type_specifier: /* empty */ 1042 { 1043 $$ = new String(); 1044 } 1045 | T_TO identifier 1046 { 1047 $$ = $2; 1048 } 1049 ; 1050 1051default_specifier: /* empty */ 1052 { 1053 $$ = false; 1054 } 1055 | T_DEFAULT 1056 { 1057 $$ = true; 1058 } 1059 ; 1060 1061ignore_specifier: /* empty */ 1062 { 1063 $$ = false; 1064 } 1065 | T_IGNORE_ON_ERROR 1066 { 1067 $$ = true; 1068 } 1069 ; 1070 1071use_specifier: /* empty */ 1072 { 1073 $$ = new std::map<String, std::unique_ptr<Expression> >(); 1074 } 1075 | T_USE '(' use_specifier_items ')' 1076 { 1077 $$ = $3; 1078 } 1079 ; 1080 1081use_specifier_items: use_specifier_item 1082 { 1083 $$ = new std::map<String, std::unique_ptr<Expression> >(); 1084 $$->emplace(std::move(*$1)); 1085 delete $1; 1086 } 1087 | use_specifier_items ',' use_specifier_item 1088 { 1089 $$ = $1; 1090 $$->emplace(std::move(*$3)); 1091 delete $3; 1092 } 1093 ; 1094 1095use_specifier_item: identifier 1096 { 1097 std::unique_ptr<Expression> var (new VariableExpression(*$1, context->GetImports(), @1)); 1098 $$ = new std::pair<String, std::unique_ptr<Expression> >(std::move(*$1), std::move(var)); 1099 delete $1; 1100 } 1101 | identifier T_SET rterm 1102 { 1103 $$ = new std::pair<String, std::unique_ptr<Expression> >(std::move(*$1), std::unique_ptr<Expression>($3)); 1104 delete $1; 1105 } 1106 ; 1107 1108apply_for_specifier: /* empty */ 1109 | T_FOR '(' optional_var identifier T_FOLLOWS optional_var identifier T_IN rterm ')' 1110 { 1111 context->m_FKVar.top() = std::move(*$4); 1112 delete $4; 1113 1114 context->m_FVVar.top() = std::move(*$7); 1115 delete $7; 1116 1117 context->m_FTerm.top() = $9; 1118 } 1119 | T_FOR '(' optional_var identifier T_IN rterm ')' 1120 { 1121 context->m_FKVar.top() = std::move(*$4); 1122 delete $4; 1123 1124 context->m_FVVar.top() = ""; 1125 1126 context->m_FTerm.top() = $6; 1127 } 1128 ; 1129 1130optional_rterm: /* empty */ 1131 { 1132 $$ = MakeLiteralRaw(); 1133 } 1134 | rterm 1135 ; 1136 1137apply: 1138 { 1139 context->m_Apply.push(true); 1140 context->m_SeenAssign.push(false); 1141 context->m_SeenIgnore.push(false); 1142 context->m_Assign.push(NULL); 1143 context->m_Ignore.push(NULL); 1144 context->m_FKVar.push(""); 1145 context->m_FVVar.push(""); 1146 context->m_FTerm.push(NULL); 1147 } 1148 T_APPLY identifier optional_rterm apply_for_specifier target_type_specifier use_specifier ignore_specifier 1149 { 1150 BeginFlowControlBlock(context, FlowControlReturn, false); 1151 } 1152 rterm_scope_require_side_effect 1153 { 1154 EndFlowControlBlock(context); 1155 1156 context->m_Apply.pop(); 1157 1158 String type = std::move(*$3); 1159 delete $3; 1160 String target = std::move(*$6); 1161 delete $6; 1162 1163 if (!ApplyRule::IsValidSourceType(type)) 1164 BOOST_THROW_EXCEPTION(ScriptError("'apply' cannot be used with type '" + type + "'", @3)); 1165 1166 if (!ApplyRule::IsValidTargetType(type, target)) { 1167 if (target == "") { 1168 std::vector<String> types = ApplyRule::GetTargetTypes(type); 1169 String typeNames; 1170 1171 for (std::vector<String>::size_type i = 0; i < types.size(); i++) { 1172 if (typeNames != "") { 1173 if (i == types.size() - 1) 1174 typeNames += " or "; 1175 else 1176 typeNames += ", "; 1177 } 1178 1179 typeNames += "'" + types[i] + "'"; 1180 } 1181 1182 BOOST_THROW_EXCEPTION(ScriptError("'apply' target type is ambiguous (can be one of " + typeNames + "): use 'to' to specify a type", DebugInfoRange(@2, @3))); 1183 } else 1184 BOOST_THROW_EXCEPTION(ScriptError("'apply' target type '" + target + "' is invalid", @6)); 1185 } 1186 1187 bool seen_assign = context->m_SeenAssign.top(); 1188 context->m_SeenAssign.pop(); 1189 1190 // assign && !ignore 1191 if (!seen_assign && !context->m_FTerm.top()) 1192 BOOST_THROW_EXCEPTION(ScriptError("'apply' is missing 'assign'/'for'", DebugInfoRange(@2, @3))); 1193 1194 std::unique_ptr<Expression> ignore{context->m_Ignore.top()}; 1195 context->m_Ignore.pop(); 1196 1197 std::unique_ptr<Expression> assign; 1198 1199 if (!seen_assign) 1200 assign = MakeLiteral(true); 1201 else 1202 assign.reset(context->m_Assign.top()); 1203 1204 context->m_Assign.pop(); 1205 1206 std::unique_ptr<Expression> filter; 1207 1208 if (ignore) { 1209 std::unique_ptr<Expression>rex{new LogicalNegateExpression(std::move(ignore), DebugInfoRange(@2, @5))}; 1210 1211 filter.reset(new LogicalAndExpression(std::move(assign), std::move(rex), DebugInfoRange(@2, @5))); 1212 } else 1213 filter.swap(assign); 1214 1215 String fkvar = std::move(context->m_FKVar.top()); 1216 context->m_FKVar.pop(); 1217 1218 String fvvar = std::move(context->m_FVVar.top()); 1219 context->m_FVVar.pop(); 1220 1221 std::unique_ptr<Expression> fterm{context->m_FTerm.top()}; 1222 context->m_FTerm.pop(); 1223 1224 $$ = new ApplyExpression(std::move(type), std::move(target), std::unique_ptr<Expression>($4), std::move(filter), context->GetPackage(), std::move(fkvar), std::move(fvvar), std::move(fterm), std::move(*$7), $8, std::unique_ptr<Expression>($10), DebugInfoRange(@2, @8)); 1225 delete $7; 1226 } 1227 ; 1228 1229newlines: T_NEWLINE 1230 | T_NEWLINE newlines 1231 ; 1232 1233optional_newlines: /* empty */ 1234 | newlines 1235 ; 1236 1237/* required separator */ 1238sep: ',' optional_newlines 1239 | ';' optional_newlines 1240 | newlines 1241 ; 1242 1243%% 1244