250, 256, 263, 270, 277, 288, 296, 297, 307, 308,
315, 316, 330, 331, 335, 336, 339, 340, 343, 344,
352, 363, 374, 385, 389, 399, 407, 417, 418, 422,
- 429, 436, 446, 460, 471, 485, 492, 502, 508, 514,
- 520, 526, 532, 538, 545, 556, 570, 579, 583, 593,
- 606, 614, 622, 635, 637, 642, 643, 648, 657, 658,
- 659, 663, 664, 666, 671, 672, 676, 677, 679, 683,
- 689, 695, 701, 707, 711, 718, 725, 732, 736, 743,
- 750
+ 430, 438, 449, 464, 475, 489, 497, 508, 514, 520,
+ 526, 532, 538, 544, 551, 562, 577, 586, 590, 600,
+ 614, 622, 630, 643, 645, 650, 651, 656, 665, 666,
+ 667, 671, 672, 674, 679, 680, 684, 685, 687, 691,
+ 697, 703, 709, 715, 719, 726, 733, 740, 744, 751,
+ 758
};
#endif
/* Line 1391 of yacc.c */
#line 1366 "parser.cpp"
break;
+ case 18: /* "KEYWORD_POS" */
+
+/* Line 1391 of yacc.c */
+#line 163 "parser.y"
+ { free((yyvaluep->str)); };
+
+/* Line 1391 of yacc.c */
+#line 1375 "parser.cpp"
+ break;
case 25: /* "PARAM" */
/* Line 1391 of yacc.c */
{ if((yyvaluep->str)) free((yyvaluep->str)); };
/* Line 1391 of yacc.c */
-#line 1375 "parser.cpp"
+#line 1384 "parser.cpp"
break;
case 28: /* "CMP_OP" */
{ free((yyvaluep->str)); };
/* Line 1391 of yacc.c */
-#line 1384 "parser.cpp"
+#line 1393 "parser.cpp"
break;
case 50: /* "commands" */
{ delete (yyvaluep->sel); };
/* Line 1391 of yacc.c */
-#line 1393 "parser.cpp"
+#line 1402 "parser.cpp"
break;
case 51: /* "command" */
{ delete (yyvaluep->sel); };
/* Line 1391 of yacc.c */
-#line 1402 "parser.cpp"
+#line 1411 "parser.cpp"
break;
case 52: /* "cmd_plain" */
{ delete (yyvaluep->sel); };
/* Line 1391 of yacc.c */
-#line 1411 "parser.cpp"
+#line 1420 "parser.cpp"
break;
case 54: /* "help_topic" */
{ _gmx_selexpr_free_values((yyvaluep->val)); };
/* Line 1391 of yacc.c */
-#line 1420 "parser.cpp"
+#line 1429 "parser.cpp"
break;
case 55: /* "selection" */
{ delete (yyvaluep->sel); };
/* Line 1391 of yacc.c */
-#line 1429 "parser.cpp"
+#line 1438 "parser.cpp"
break;
case 59: /* "string" */
{ free((yyvaluep->str)); };
/* Line 1391 of yacc.c */
-#line 1438 "parser.cpp"
+#line 1447 "parser.cpp"
break;
case 60: /* "sel_expr" */
{ delete (yyvaluep->sel); };
/* Line 1391 of yacc.c */
-#line 1447 "parser.cpp"
+#line 1456 "parser.cpp"
+ break;
+ case 61: /* "pos_mod" */
+
+/* Line 1391 of yacc.c */
+#line 164 "parser.y"
+ { if((yyvaluep->str)) free((yyvaluep->str)); };
+
+/* Line 1391 of yacc.c */
+#line 1465 "parser.cpp"
break;
case 62: /* "num_expr" */
{ delete (yyvaluep->sel); };
/* Line 1391 of yacc.c */
-#line 1456 "parser.cpp"
+#line 1474 "parser.cpp"
break;
case 63: /* "str_expr" */
{ delete (yyvaluep->sel); };
/* Line 1391 of yacc.c */
-#line 1465 "parser.cpp"
+#line 1483 "parser.cpp"
break;
case 64: /* "pos_expr" */
{ delete (yyvaluep->sel); };
/* Line 1391 of yacc.c */
-#line 1474 "parser.cpp"
+#line 1492 "parser.cpp"
break;
case 65: /* "method_params" */
{ _gmx_selexpr_free_params((yyvaluep->param)); };
/* Line 1391 of yacc.c */
-#line 1483 "parser.cpp"
+#line 1501 "parser.cpp"
break;
case 66: /* "method_param_list" */
{ _gmx_selexpr_free_params((yyvaluep->param)); };
/* Line 1391 of yacc.c */
-#line 1492 "parser.cpp"
+#line 1510 "parser.cpp"
break;
case 67: /* "method_param" */
{ _gmx_selexpr_free_params((yyvaluep->param)); };
/* Line 1391 of yacc.c */
-#line 1501 "parser.cpp"
+#line 1519 "parser.cpp"
break;
case 68: /* "value_list" */
{ _gmx_selexpr_free_values((yyvaluep->val)); };
/* Line 1391 of yacc.c */
-#line 1510 "parser.cpp"
+#line 1528 "parser.cpp"
break;
case 69: /* "value_list_contents" */
{ _gmx_selexpr_free_values((yyvaluep->val)); };
/* Line 1391 of yacc.c */
-#line 1519 "parser.cpp"
+#line 1537 "parser.cpp"
break;
case 70: /* "basic_value_list" */
{ _gmx_selexpr_free_values((yyvaluep->val)); };
/* Line 1391 of yacc.c */
-#line 1528 "parser.cpp"
+#line 1546 "parser.cpp"
break;
case 71: /* "basic_value_list_contents" */
{ _gmx_selexpr_free_values((yyvaluep->val)); };
/* Line 1391 of yacc.c */
-#line 1537 "parser.cpp"
+#line 1555 "parser.cpp"
break;
case 72: /* "value_item" */
{ _gmx_selexpr_free_values((yyvaluep->val)); };
/* Line 1391 of yacc.c */
-#line 1546 "parser.cpp"
+#line 1564 "parser.cpp"
break;
case 73: /* "basic_value_item" */
{ _gmx_selexpr_free_values((yyvaluep->val)); };
/* Line 1391 of yacc.c */
-#line 1555 "parser.cpp"
+#line 1573 "parser.cpp"
break;
case 74: /* "value_item_range" */
{ _gmx_selexpr_free_values((yyvaluep->val)); };
/* Line 1391 of yacc.c */
-#line 1564 "parser.cpp"
+#line 1582 "parser.cpp"
break;
default:
#line 423 "parser.y"
{
BEGIN_ACTION;
+ scoped_ptr_sfree posmodGuard((yyvsp[(1) - (2)].str));
set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), NULL, (yyvsp[(1) - (2)].str), scanner));
CHECK_SEL((yyval.sel));
END_ACTION;
case 40:
/* Line 1806 of yacc.c */
-#line 430 "parser.y"
+#line 431 "parser.y"
{
BEGIN_ACTION;
+ scoped_ptr_sfree posmodGuard((yyvsp[(1) - (3)].str));
set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (3)].meth), process_value_list((yyvsp[(3) - (3)].val), NULL), (yyvsp[(1) - (3)].str), scanner));
CHECK_SEL((yyval.sel));
END_ACTION;
case 41:
/* Line 1806 of yacc.c */
-#line 437 "parser.y"
+#line 439 "parser.y"
{
BEGIN_ACTION;
+ scoped_ptr_sfree posmodGuard((yyvsp[(1) - (3)].str));
set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (3)].meth), process_value_list((yyvsp[(3) - (3)].val), NULL), (yyvsp[(1) - (3)].str), scanner));
CHECK_SEL((yyval.sel));
END_ACTION;
case 42:
/* Line 1806 of yacc.c */
-#line 447 "parser.y"
+#line 450 "parser.y"
{
BEGIN_ACTION;
+ scoped_ptr_sfree posmodGuard((yyvsp[(1) - (3)].str));
set((yyval.sel), _gmx_sel_init_method((yyvsp[(2) - (3)].meth), (yyvsp[(3) - (3)].param), (yyvsp[(1) - (3)].str), scanner));
CHECK_SEL((yyval.sel));
END_ACTION;
case 43:
/* Line 1806 of yacc.c */
-#line 461 "parser.y"
+#line 465 "parser.y"
{
BEGIN_ACTION;
SelectionTreeElementPointer sel(
case 44:
/* Line 1806 of yacc.c */
-#line 472 "parser.y"
+#line 476 "parser.y"
{
BEGIN_ACTION;
SelectionTreeElementPointer sel(
case 45:
/* Line 1806 of yacc.c */
-#line 486 "parser.y"
+#line 490 "parser.y"
{
BEGIN_ACTION;
+ scoped_ptr_sfree posmodGuard((yyvsp[(1) - (2)].str));
set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), NULL, (yyvsp[(1) - (2)].str), scanner));
CHECK_SEL((yyval.sel));
END_ACTION;
case 46:
/* Line 1806 of yacc.c */
-#line 493 "parser.y"
+#line 498 "parser.y"
{
BEGIN_ACTION;
+ scoped_ptr_sfree posmodGuard((yyvsp[(1) - (3)].str));
set((yyval.sel), _gmx_sel_init_method((yyvsp[(2) - (3)].meth), (yyvsp[(3) - (3)].param), (yyvsp[(1) - (3)].str), scanner));
CHECK_SEL((yyval.sel));
END_ACTION;
case 47:
/* Line 1806 of yacc.c */
-#line 503 "parser.y"
+#line 509 "parser.y"
{
BEGIN_ACTION;
set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '+', scanner));
case 48:
/* Line 1806 of yacc.c */
-#line 509 "parser.y"
+#line 515 "parser.y"
{
BEGIN_ACTION;
set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '-', scanner));
case 49:
/* Line 1806 of yacc.c */
-#line 515 "parser.y"
+#line 521 "parser.y"
{
BEGIN_ACTION;
set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '*', scanner));
case 50:
/* Line 1806 of yacc.c */
-#line 521 "parser.y"
+#line 527 "parser.y"
{
BEGIN_ACTION;
set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '/', scanner));
case 51:
/* Line 1806 of yacc.c */
-#line 527 "parser.y"
+#line 533 "parser.y"
{
BEGIN_ACTION;
set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(2) - (2)].sel)), SelectionTreeElementPointer(), '-', scanner));
case 52:
/* Line 1806 of yacc.c */
-#line 533 "parser.y"
+#line 539 "parser.y"
{
BEGIN_ACTION;
set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '^', scanner));
case 53:
/* Line 1806 of yacc.c */
-#line 538 "parser.y"
+#line 544 "parser.y"
{ (yyval.sel) = (yyvsp[(2) - (3)].sel); }
break;
case 54:
/* Line 1806 of yacc.c */
-#line 546 "parser.y"
+#line 552 "parser.y"
{
BEGIN_ACTION;
SelectionTreeElementPointer sel(
case 55:
/* Line 1806 of yacc.c */
-#line 557 "parser.y"
+#line 563 "parser.y"
{
BEGIN_ACTION;
+ scoped_ptr_sfree posmodGuard((yyvsp[(1) - (2)].str));
set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), NULL, (yyvsp[(1) - (2)].str), scanner));
CHECK_SEL((yyval.sel));
END_ACTION;
case 56:
/* Line 1806 of yacc.c */
-#line 571 "parser.y"
+#line 578 "parser.y"
{
BEGIN_ACTION;
set((yyval.sel), _gmx_sel_init_const_position((yyvsp[(2) - (7)].r), (yyvsp[(4) - (7)].r), (yyvsp[(6) - (7)].r)));
case 57:
/* Line 1806 of yacc.c */
-#line 579 "parser.y"
+#line 586 "parser.y"
{ (yyval.sel) = (yyvsp[(2) - (3)].sel); }
break;
case 58:
/* Line 1806 of yacc.c */
-#line 584 "parser.y"
+#line 591 "parser.y"
{
BEGIN_ACTION;
set((yyval.sel), _gmx_sel_init_method((yyvsp[(1) - (2)].meth), (yyvsp[(2) - (2)].param), NULL, scanner));
case 59:
/* Line 1806 of yacc.c */
-#line 594 "parser.y"
+#line 601 "parser.y"
{
BEGIN_ACTION;
+ scoped_ptr_sfree keywordGuard((yyvsp[(1) - (3)].str));
set((yyval.sel), _gmx_sel_init_position(get((yyvsp[(3) - (3)].sel)), (yyvsp[(1) - (3)].str), scanner));
CHECK_SEL((yyval.sel));
END_ACTION;
case 60:
/* Line 1806 of yacc.c */
-#line 607 "parser.y"
+#line 615 "parser.y"
{
BEGIN_ACTION;
set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel))));
case 61:
/* Line 1806 of yacc.c */
-#line 615 "parser.y"
+#line 623 "parser.y"
{
BEGIN_ACTION;
set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel))));
case 62:
/* Line 1806 of yacc.c */
-#line 623 "parser.y"
+#line 631 "parser.y"
{
BEGIN_ACTION;
set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel))));
case 63:
/* Line 1806 of yacc.c */
-#line 636 "parser.y"
+#line 644 "parser.y"
{ (yyval.param) = process_param_list((yyvsp[(1) - (1)].param)); }
break;
case 64:
/* Line 1806 of yacc.c */
-#line 638 "parser.y"
+#line 646 "parser.y"
{ (yyval.param) = process_param_list((yyvsp[(1) - (2)].param)); }
break;
case 65:
/* Line 1806 of yacc.c */
-#line 642 "parser.y"
+#line 650 "parser.y"
{ (yyval.param) = NULL; }
break;
case 66:
/* Line 1806 of yacc.c */
-#line 644 "parser.y"
+#line 652 "parser.y"
{ (yyvsp[(2) - (2)].param)->next = (yyvsp[(1) - (2)].param); (yyval.param) = (yyvsp[(2) - (2)].param); }
break;
case 67:
/* Line 1806 of yacc.c */
-#line 649 "parser.y"
+#line 657 "parser.y"
{
BEGIN_ACTION;
(yyval.param) = _gmx_selexpr_create_param((yyvsp[(1) - (2)].str));
case 68:
/* Line 1806 of yacc.c */
-#line 657 "parser.y"
+#line 665 "parser.y"
{ (yyval.val) = NULL; }
break;
case 69:
/* Line 1806 of yacc.c */
-#line 658 "parser.y"
+#line 666 "parser.y"
{ (yyval.val) = (yyvsp[(1) - (1)].val); }
break;
case 70:
/* Line 1806 of yacc.c */
-#line 659 "parser.y"
+#line 667 "parser.y"
{ (yyval.val) = (yyvsp[(2) - (3)].val); }
break;
case 71:
/* Line 1806 of yacc.c */
-#line 663 "parser.y"
+#line 671 "parser.y"
{ (yyval.val) = (yyvsp[(1) - (1)].val); }
break;
case 72:
/* Line 1806 of yacc.c */
-#line 665 "parser.y"
+#line 673 "parser.y"
{ (yyvsp[(2) - (2)].val)->next = (yyvsp[(1) - (2)].val); (yyval.val) = (yyvsp[(2) - (2)].val); }
break;
case 73:
/* Line 1806 of yacc.c */
-#line 667 "parser.y"
+#line 675 "parser.y"
{ (yyvsp[(3) - (3)].val)->next = (yyvsp[(1) - (3)].val); (yyval.val) = (yyvsp[(3) - (3)].val); }
break;
case 74:
/* Line 1806 of yacc.c */
-#line 671 "parser.y"
+#line 679 "parser.y"
{ (yyval.val) = (yyvsp[(1) - (1)].val); }
break;
case 75:
/* Line 1806 of yacc.c */
-#line 672 "parser.y"
+#line 680 "parser.y"
{ (yyval.val) = (yyvsp[(2) - (3)].val); }
break;
case 76:
/* Line 1806 of yacc.c */
-#line 676 "parser.y"
+#line 684 "parser.y"
{ (yyval.val) = (yyvsp[(1) - (1)].val); }
break;
case 77:
/* Line 1806 of yacc.c */
-#line 678 "parser.y"
+#line 686 "parser.y"
{ (yyvsp[(2) - (2)].val)->next = (yyvsp[(1) - (2)].val); (yyval.val) = (yyvsp[(2) - (2)].val); }
break;
case 78:
/* Line 1806 of yacc.c */
-#line 680 "parser.y"
+#line 688 "parser.y"
{ (yyvsp[(3) - (3)].val)->next = (yyvsp[(1) - (3)].val); (yyval.val) = (yyvsp[(3) - (3)].val); }
break;
case 79:
/* Line 1806 of yacc.c */
-#line 684 "parser.y"
+#line 692 "parser.y"
{
BEGIN_ACTION;
(yyval.val) = _gmx_selexpr_create_value_expr(get((yyvsp[(1) - (1)].sel)));
case 80:
/* Line 1806 of yacc.c */
-#line 690 "parser.y"
+#line 698 "parser.y"
{
BEGIN_ACTION;
(yyval.val) = _gmx_selexpr_create_value_expr(get((yyvsp[(1) - (1)].sel)));
case 81:
/* Line 1806 of yacc.c */
-#line 696 "parser.y"
+#line 704 "parser.y"
{
BEGIN_ACTION;
(yyval.val) = _gmx_selexpr_create_value_expr(get((yyvsp[(1) - (1)].sel)));
case 82:
/* Line 1806 of yacc.c */
-#line 702 "parser.y"
+#line 710 "parser.y"
{
BEGIN_ACTION;
(yyval.val) = _gmx_selexpr_create_value_expr(get((yyvsp[(1) - (1)].sel)));
case 83:
/* Line 1806 of yacc.c */
-#line 707 "parser.y"
+#line 715 "parser.y"
{ (yyval.val) = (yyvsp[(1) - (1)].val); }
break;
case 84:
/* Line 1806 of yacc.c */
-#line 712 "parser.y"
+#line 720 "parser.y"
{
BEGIN_ACTION;
(yyval.val) = _gmx_selexpr_create_value(INT_VALUE);
case 85:
/* Line 1806 of yacc.c */
-#line 719 "parser.y"
+#line 727 "parser.y"
{
BEGIN_ACTION;
(yyval.val) = _gmx_selexpr_create_value(REAL_VALUE);
case 86:
/* Line 1806 of yacc.c */
-#line 726 "parser.y"
+#line 734 "parser.y"
{
BEGIN_ACTION;
(yyval.val) = _gmx_selexpr_create_value(STR_VALUE);
case 87:
/* Line 1806 of yacc.c */
-#line 732 "parser.y"
+#line 740 "parser.y"
{ (yyval.val) = (yyvsp[(1) - (1)].val); }
break;
case 88:
/* Line 1806 of yacc.c */
-#line 737 "parser.y"
+#line 745 "parser.y"
{
BEGIN_ACTION;
(yyval.val) = _gmx_selexpr_create_value(INT_VALUE);
case 89:
/* Line 1806 of yacc.c */
-#line 744 "parser.y"
+#line 752 "parser.y"
{
BEGIN_ACTION;
(yyval.val) = _gmx_selexpr_create_value(REAL_VALUE);
case 90:
/* Line 1806 of yacc.c */
-#line 751 "parser.y"
+#line 759 "parser.y"
{
BEGIN_ACTION;
(yyval.val) = _gmx_selexpr_create_value(REAL_VALUE);
/* Line 1806 of yacc.c */
-#line 2833 "parser.cpp"
+#line 2859 "parser.cpp"
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
%type <val> basic_value_list basic_value_list_contents basic_value_item
%type <val> help_topic
-%destructor { free($$); } HELP_TOPIC STR IDENTIFIER CMP_OP string
-%destructor { if($$) free($$); } PARAM
+%destructor { free($$); } HELP_TOPIC STR IDENTIFIER KEYWORD_POS CMP_OP string
+%destructor { if($$) free($$); } PARAM pos_mod
%destructor { delete $$; } commands command cmd_plain selection
%destructor { delete $$; } sel_expr num_expr str_expr pos_expr
%destructor { _gmx_selexpr_free_params($$); } method_params method_param_list method_param
sel_expr: pos_mod KEYWORD_GROUP
{
BEGIN_ACTION;
+ scoped_ptr_sfree posmodGuard($1);
set($$, _gmx_sel_init_keyword($2, NULL, $1, scanner));
CHECK_SEL($$);
END_ACTION;
| pos_mod KEYWORD_STR basic_value_list
{
BEGIN_ACTION;
+ scoped_ptr_sfree posmodGuard($1);
set($$, _gmx_sel_init_keyword($2, process_value_list($3, NULL), $1, scanner));
CHECK_SEL($$);
END_ACTION;
| pos_mod KEYWORD_NUMERIC basic_value_list
{
BEGIN_ACTION;
+ scoped_ptr_sfree posmodGuard($1);
set($$, _gmx_sel_init_keyword($2, process_value_list($3, NULL), $1, scanner));
CHECK_SEL($$);
END_ACTION;
sel_expr: pos_mod METHOD_GROUP method_params
{
BEGIN_ACTION;
+ scoped_ptr_sfree posmodGuard($1);
set($$, _gmx_sel_init_method($2, $3, $1, scanner));
CHECK_SEL($$);
END_ACTION;
num_expr: pos_mod KEYWORD_NUMERIC %prec NUM_REDUCT
{
BEGIN_ACTION;
+ scoped_ptr_sfree posmodGuard($1);
set($$, _gmx_sel_init_keyword($2, NULL, $1, scanner));
CHECK_SEL($$);
END_ACTION;
| pos_mod METHOD_NUMERIC method_params
{
BEGIN_ACTION;
+ scoped_ptr_sfree posmodGuard($1);
set($$, _gmx_sel_init_method($2, $3, $1, scanner));
CHECK_SEL($$);
END_ACTION;
| pos_mod KEYWORD_STR
{
BEGIN_ACTION;
+ scoped_ptr_sfree posmodGuard($1);
set($$, _gmx_sel_init_keyword($2, NULL, $1, scanner));
CHECK_SEL($$);
END_ACTION;
pos_expr: KEYWORD_POS OF sel_expr %prec PARAM_REDUCT
{
BEGIN_ACTION;
+ scoped_ptr_sfree keywordGuard($1);
set($$, _gmx_sel_init_position(get($3), $1, scanner));
CHECK_SEL($$);
END_ACTION;
if (expr->type == SEL_CONST && expr->v.type != GROUP_VALUE)
{
/* If so, just assign the constant value to the variable */
- if (!_gmx_sel_add_var_symbol(sc->symtab, name, expr))
- {
- return SelectionTreeElementPointer();
- }
+ sc->symtab->addVariable(name, expr);
goto finish;
}
/* Check if we are assigning a variable to another variable */
if (expr->type == SEL_SUBEXPRREF)
{
/* If so, make a simple alias */
- if (!_gmx_sel_add_var_symbol(sc->symtab, name, expr->child))
- {
- return SelectionTreeElementPointer();
- }
+ sc->symtab->addVariable(name, expr->child);
goto finish;
}
/* Create the root element */
/* Update flags */
_gmx_selelem_update_flags(root, scanner);
/* Add the variable to the symbol table */
- if (!_gmx_sel_add_var_symbol(sc->symtab, name, root->child))
- {
- return SelectionTreeElementPointer();
- }
+ sc->symtab->addVariable(name, root->child);
finish:
srenew(sc->varstrs, sc->nvars + 1);
sc->varstrs[sc->nvars] = strdup(pselstr);
#include <stdlib.h>
#include <string.h>
-#include "typedefs.h"
-#include "smalloc.h"
-#include "string2.h"
+#include <string>
+
+#include "gromacs/legacyheaders/typedefs.h"
+#include "gromacs/legacyheaders/smalloc.h"
+#include "gromacs/legacyheaders/string2.h"
#include "gromacs/utility/errorcodes.h"
#include "gromacs/utility/exceptions.h"
_gmx_sel_lexer_process_identifier(YYSTYPE *yylval, char *yytext, size_t yyleng,
gmx_sel_lexer_t *state)
{
- gmx_sel_symrec_t *symbol;
- e_symbol_t symtype;
-
/* Check if the identifier matches with a parameter name */
if (state->msp >= 0)
{
}
/* Check if the identifier matches with a symbol */
- symbol = _gmx_sel_find_symbol_len(state->sc->symtab, yytext, yyleng, false);
+ const gmx::SelectionParserSymbol *symbol
+ = state->sc->symtab->findSymbol(std::string(yytext, yyleng), false);
/* If there is no match, return the token as a string */
if (!symbol)
{
_gmx_sel_lexer_add_token(yytext, yyleng, state);
return IDENTIFIER;
}
- _gmx_sel_lexer_add_token(_gmx_sel_sym_name(symbol), -1, state);
- symtype = _gmx_sel_sym_type(symbol);
+ _gmx_sel_lexer_add_token(symbol->name().c_str(), -1, state);
+ gmx::SelectionParserSymbol::SymbolType symtype = symbol->type();
/* Reserved symbols should have been caught earlier */
- if (symtype == SYMBOL_RESERVED)
+ if (symtype == gmx::SelectionParserSymbol::ReservedSymbol)
{
GMX_ERROR_NORET(gmx::eeInternalError,
"Mismatch between tokenizer and reserved symbol table");
return INVALID;
}
/* For variable symbols, return the type of the variable value */
- if (symtype == SYMBOL_VARIABLE)
+ if (symtype == gmx::SelectionParserSymbol::VariableSymbol)
{
- gmx::SelectionTreeElementPointer var = _gmx_sel_sym_value_var(symbol);
+ gmx::SelectionTreeElementPointer var = symbol->variableValue();
/* Return simple tokens for constant variables */
if (var->type == SEL_CONST)
{
return INVALID; /* Should not be reached. */
}
/* For method symbols, return the correct type */
- if (symtype == SYMBOL_METHOD)
+ if (symtype == gmx::SelectionParserSymbol::MethodSymbol)
{
- gmx_ana_selmethod_t *method;
-
- method = _gmx_sel_sym_value_method(symbol);
+ gmx_ana_selmethod_t *method = symbol->methodValue();
return init_method_token(yylval, method, state->prev_pos_kw > 0, state);
}
/* For position symbols, we need to return KEYWORD_POS, but we also need
* some additional handling. */
- if (symtype == SYMBOL_POS)
+ if (symtype == gmx::SelectionParserSymbol::PositionSymbol)
{
state->bMatchOf = true;
- yylval->str = _gmx_sel_sym_name(symbol);
+ yylval->str = strdup(symbol->name().c_str());
state->prev_pos_kw = 2;
return KEYWORD_POS;
}
#include <string>
#include <vector>
+#include <boost/scoped_ptr.hpp>
+
#include "../legacyheaders/typedefs.h"
#include "../onlinehelp/helptopicinterface.h"
namespace gmx
{
+
//! Smart pointer for managing an internal selection data object.
typedef gmx_unique_ptr<internal::SelectionData>::type SelectionDataPointer;
//! Container for storing a list of selections internally.
typedef std::vector<SelectionDataPointer> SelectionDataList;
-}
+
+class SelectionParserSymbolTable;
+
+} // namespace gmx
/*! \internal \brief
* Information for a collection of selections.
struct gmx_ana_index_t gall;
/** Memory pool used for selection evaluation. */
struct gmx_sel_mempool_t *mempool;
- /** Parser symbol table. */
- struct gmx_sel_symtab_t *symtab;
+ //! Parser symbol table.
+ boost::scoped_ptr<gmx::SelectionParserSymbolTable> symtab;
//! Root of help topic tree (NULL is no help yet requested).
gmx::HelpTopicPointer rootHelp;
};
sc_.top = NULL;
gmx_ana_index_clear(&sc_.gall);
sc_.mempool = NULL;
- sc_.symtab = NULL;
-
- _gmx_sel_symtab_create(&sc_.symtab);
- gmx_ana_selmethod_register_defaults(sc_.symtab);
+ sc_.symtab.reset(new SelectionParserSymbolTable);
+ gmx_ana_selmethod_register_defaults(sc_.symtab.get());
}
SelectionCollection::Impl::~Impl()
{
+ clearSymbolTable();
sc_.sel.clear();
sc_.root.reset();
for (int i = 0; i < sc_.nvars; ++i)
{
_gmx_sel_mempool_destroy(sc_.mempool);
}
- clearSymbolTable();
}
void
SelectionCollection::Impl::clearSymbolTable()
{
- if (sc_.symtab)
- {
- _gmx_sel_symtab_free(sc_.symtab);
- sc_.symtab = NULL;
- }
+ sc_.symtab.reset();
}
#include <vector>
#include <utility>
-#include <boost/shared_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
#include "gromacs/onlinehelp/helptopic.h"
#include "gromacs/onlinehelp/helpwritercontext.h"
// TODO: This is not a very elegant way of getting the list of selection
// methods, but this needs to be rewritten in any case if/when #652 is
// implemented.
- gmx_sel_symtab_t *symtab;
- _gmx_sel_symtab_create(&symtab);
- gmx_ana_selmethod_register_defaults(symtab);
- boost::shared_ptr<gmx_sel_symtab_t> symtabGuard(symtab, &_gmx_sel_symtab_free);
+ boost::scoped_ptr<SelectionParserSymbolTable> symtab(
+ new SelectionParserSymbolTable);
+ gmx_ana_selmethod_register_defaults(symtab.get());
- gmx_sel_symrec_t *symbol = _gmx_sel_first_symbol(symtab, SYMBOL_METHOD);
- while (symbol)
+ SelectionParserSymbolIterator symbol
+ = symtab->beginIterator(SelectionParserSymbol::MethodSymbol);
+ while (symbol != symtab->endIterator())
{
- const char *symname = _gmx_sel_sym_name(symbol);
- const gmx_ana_selmethod_t *method = _gmx_sel_sym_value_method(symbol);
+ const std::string &symname = symbol->name();
+ const gmx_ana_selmethod_t *method = symbol->methodValue();
methods_.push_back(std::make_pair(std::string(symname), method));
if (method->help.nlhelp > 0 && method->help.help != NULL)
{
addSubTopic(HelpTopicPointer(new KeywordDetailsHelpTopic(*method)));
}
- symbol = _gmx_sel_next_symbol(symbol, SYMBOL_METHOD);
+ ++symbol;
}
}
#include <ctype.h>
#include <stdarg.h>
-#include <macros.h>
-#include <string2.h>
+#include "gromacs/legacyheaders/macros.h"
+#include "gromacs/legacyheaders/string2.h"
#include "gromacs/selection/selmethod.h"
+#include "gromacs/utility/exceptions.h"
#include "symrec.h"
*/
static bool
check_params(FILE *fp, const char *name, int nparams, gmx_ana_selparam_t param[],
- gmx_sel_symtab_t *symtab)
+ const gmx::SelectionParserSymbolTable &symtab)
{
bool bOk = true;
- gmx_sel_symrec_t *sym;
int i, j;
if (nparams > 0 && !param)
continue;
}
/* Check that the name does not conflict with a method */
- if (_gmx_sel_find_symbol(symtab, param[i].name, true))
+ if (symtab.findSymbol(param[i].name, true))
{
report_param_error(fp, name, param[i].name, "error: name conflicts with another method or a keyword");
bOk = false;
}
} /* End of parameter loop */
/* Check parameters of existing methods */
- sym = _gmx_sel_first_symbol(symtab, SYMBOL_METHOD);
- while (sym)
+ gmx::SelectionParserSymbolIterator symbol
+ = symtab.beginIterator(gmx::SelectionParserSymbol::MethodSymbol);
+ while (symbol != symtab.endIterator())
{
- gmx_ana_selmethod_t *method = _gmx_sel_sym_value_method(sym);
+ gmx_ana_selmethod_t *method = symbol->methodValue();
gmx_ana_selparam_t *param =
gmx_ana_selmethod_find_param(name, method);
if (param)
report_param_error(fp, method->name, param->name, "error: name conflicts with another method or a keyword");
bOk = false;
}
- sym = _gmx_sel_next_symbol(sym, SYMBOL_METHOD);
+ ++symbol;
}
return bOk;
}
* compiler, and evaluation functions can deal with the method.
*/
static bool
-check_method(FILE *fp, gmx_ana_selmethod_t *method, gmx_sel_symtab_t *symtab)
+check_method(FILE *fp, gmx_ana_selmethod_t *method,
+ const gmx::SelectionParserSymbolTable &symtab)
{
bool bOk = true;
* compiler, and evaluation functions can deal with the method.
*/
static bool
-check_modifier(FILE *fp, gmx_ana_selmethod_t *method, gmx_sel_symtab_t *symtab)
+check_modifier(FILE *fp, gmx_ana_selmethod_t *method,
+ const gmx::SelectionParserSymbolTable &symtab)
{
bool bOk = true;
* All problems are described to \p stderr.
*/
int
-gmx_ana_selmethod_register(gmx_sel_symtab_t *symtab,
+gmx_ana_selmethod_register(gmx::SelectionParserSymbolTable *symtab,
const char *name, gmx_ana_selmethod_t *method)
{
bool bOk;
/* Check the method */
if (method->flags & SMETH_MODIFIER)
{
- bOk = check_modifier(stderr, method, symtab);
+ bOk = check_modifier(stderr, method, *symtab);
}
else
{
- bOk = check_method(stderr, method, symtab);
+ bOk = check_method(stderr, method, *symtab);
}
/* Try to register the method if everything is ok */
- if (bOk)
+ if (bOk)
{
- if (!_gmx_sel_add_method_symbol(symtab, name, method))
+ try
{
+ symtab->addMethod(name, method);
+ }
+ catch (const gmx::APIError &ex)
+ {
+ report_error(stderr, name, ex.what());
bOk = false;
}
}
* registered.
*/
int
-gmx_ana_selmethod_register_defaults(gmx_sel_symtab_t *symtab)
+gmx_ana_selmethod_register_defaults(gmx::SelectionParserSymbolTable *symtab)
{
size_t i;
int rc;
namespace gmx
{
class PositionCalculationCollection;
+class SelectionParserSymbolTable;
} // namespace gmx
struct gmx_ana_pos_t;
/** Registers a selection method. */
int
-gmx_ana_selmethod_register(struct gmx_sel_symtab_t *symtab,
+gmx_ana_selmethod_register(gmx::SelectionParserSymbolTable *symtab,
const char *name, gmx_ana_selmethod_t *method);
/** Registers all selection methods in the library. */
int
-gmx_ana_selmethod_register_defaults(struct gmx_sel_symtab_t *symtab);
+gmx_ana_selmethod_register_defaults(gmx::SelectionParserSymbolTable *symtab);
/** Finds a parameter from a selection method by name. */
gmx_ana_selparam_t *
*/
/*! \internal \file
* \brief
- * Implements functions in symrec.h.
+ * Implements classes in symrec.h.
*
* \author Teemu Murtola <teemu.murtola@cbr.su.se>
* \ingroup module_selection
*/
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include <map>
+#include <string>
+#include <utility>
#include "gromacs/legacyheaders/macros.h"
-#include "gromacs/legacyheaders/smalloc.h"
-#include "gromacs/legacyheaders/string2.h"
-#include "gromacs/selection/poscalc.h"
+#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/uniqueptr.h"
+#include "poscalc.h"
#include "selelem.h"
#include "symrec.h"
-/*! \internal \brief
- * Symbol table for the selection parser.
- */
-struct gmx_sel_symtab_t
+namespace gmx
{
- /** Pointer to the first symbol in the linked list of symbols. */
- gmx_sel_symrec_t *first;
-};
+
+/********************************************************************
+ * SelectionParserSymbol
+ */
/*! \internal \brief
- * Single symbol for the selection parser.
+ * Private implementation class for SelectionParserSymbol.
*
- * \todo
- * Make this a proper class.
+ * \ingroup module_selection
*/
-struct gmx_sel_symrec_t
+class SelectionParserSymbol::Impl
{
- /** Name of the symbol. */
- char *name;
- /** Type of the symbol. */
- e_symbol_t type;
- /** Pointer to the method structure (\ref SYMBOL_METHOD). */
- struct gmx_ana_selmethod_t *meth;
- /** Pointer to the variable value (\ref SYMBOL_VARIABLE). */
- gmx::SelectionTreeElementPointer var;
- /** Pointer to the next symbol. */
- struct gmx_sel_symrec_t *next;
-};
+ public:
+ /*! \brief
+ * Initializes a symbol.
+ *
+ * \param[in] type Type for the symbol.
+ * \param[in] name Name for the symbol.
+ *
+ * The symbol table is responsible for initializing the \a meth_ and
+ * \a var_ members as appropriate.
+ */
+ Impl(SymbolType type, const char *name)
+ : name_(name), type_(type), meth_(NULL)
+ {
+ }
-/** List of reserved symbols to register in add_reserved_symbols(). */
-static const char *const sym_reserved[] = {
- "group",
- "to",
- "not",
- "and",
- "or",
- "xor",
- "yes",
- "no",
- "on",
- "off",
- "help",
+ //! Name of the symbol.
+ std::string name_;
+ //! Type of the symbol.
+ SymbolType type_;
+ //! Pointer to the method structure (\ref MethodSymbol).
+ gmx_ana_selmethod_t *meth_;
+ //! Pointer to the variable value (\ref VariableSymbol).
+ SelectionTreeElementPointer var_;
};
-/*!
- * \param[in] sym Symbol to query.
- * \returns The name of \p sym.
- *
- * The returned pointer should not be free'd.
- */
-char *
-_gmx_sel_sym_name(gmx_sel_symrec_t *sym)
+SelectionParserSymbol::SelectionParserSymbol(Impl *impl)
+ : impl_(impl)
{
- return sym->name;
}
-/*!
- * \param[in] sym Symbol to query.
- * \returns The type of \p sym.
- */
-e_symbol_t
-_gmx_sel_sym_type(gmx_sel_symrec_t *sym)
+SelectionParserSymbol::~SelectionParserSymbol()
{
- return sym->type;
}
-/*!
- * \param[in] sym Symbol to query.
- * \returns The method associated with \p sym, or NULL if \p sym is not a
- * \ref SYMBOL_METHOD symbol.
- */
-struct gmx_ana_selmethod_t *
-_gmx_sel_sym_value_method(gmx_sel_symrec_t *sym)
+const std::string &
+SelectionParserSymbol::name() const
+{
+ return impl_->name_;
+}
+
+SelectionParserSymbol::SymbolType
+SelectionParserSymbol::type() const
{
- GMX_RELEASE_ASSERT(sym->type == SYMBOL_METHOD,
+ return impl_->type_;
+}
+
+gmx_ana_selmethod_t *
+SelectionParserSymbol::methodValue() const
+{
+ GMX_RELEASE_ASSERT(type() == MethodSymbol,
"Attempting to get method handle for a non-method symbol");
- return sym->meth;
+ return impl_->meth_;
}
-/*!
- * \param[in] sym Symbol to query.
- * \returns The variable expression associated with \p sym, or NULL if
- * \p sym is not a \ref SYMBOL_VARIABLE symbol.
- */
const gmx::SelectionTreeElementPointer &
-_gmx_sel_sym_value_var(gmx_sel_symrec_t *sym)
+SelectionParserSymbol::variableValue() const
{
- GMX_RELEASE_ASSERT(sym->type == SYMBOL_VARIABLE,
+ GMX_RELEASE_ASSERT(type() == VariableSymbol,
"Attempting to get variable value for a non-variable symbol");
- return sym->var;
+ return impl_->var_;
}
-/*! \brief
- * Adds the reserved symbols to a symbol table.
- *
- * \param[in,out] tab Symbol table to which the symbols are added.
+/********************************************************************
+ * SelectionParserSymbolTable::Impl
+ */
+
+/*! \internal \brief
+ * Private implementation class for SelectionParserSymbolTable.
+ *
+ * All methods in this class may throw std::bad_alloc if out of memory.
*
- * Assumes that the symbol table is empty.
+ * \ingroup module_selection
*/
-static void
-add_reserved_symbols(gmx_sel_symtab_t *tab)
+class SelectionParserSymbolTable::Impl
{
- gmx_sel_symrec_t *last;
- size_t i;
+ public:
+ //! Smart pointer type for managing a SelectionParserSymbol.
+ typedef gmx::gmx_unique_ptr<SelectionParserSymbol>::type
+ SymbolPointer;
+ //! Container type for the list of symbols.
+ typedef std::map<std::string, SymbolPointer> SymbolMap;
+
+ /*! \brief
+ * Adds a symbol to the symbol list.
+ *
+ * \param[in] symbol Symbol to add.
+ */
+ void addSymbol(SymbolPointer symbol);
+ //! Adds the reserved symbols to this symbol table.
+ void addReservedSymbols();
+ //! Adds the position symbols to this symbol table.
+ void addPositionSymbols();
+
+ //! Symbols in this symbol table.
+ SymbolMap symbols_;
+};
- last = NULL;
- for (i = 0; i < asize(sym_reserved); ++i)
+void
+SelectionParserSymbolTable::Impl::addSymbol(SymbolPointer symbol)
+{
+ symbols_.insert(std::make_pair(symbol->name(), move(symbol)));
+}
+
+void
+SelectionParserSymbolTable::Impl::addReservedSymbols()
+{
+ const char *const sym_reserved[] = {
+ "group",
+ "to",
+ "not",
+ "and",
+ "or",
+ "xor",
+ "yes",
+ "no",
+ "on",
+ "off",
+ "help",
+ };
+
+ for (size_t i = 0; i < asize(sym_reserved); ++i)
{
- gmx_sel_symrec_t *sym = new gmx_sel_symrec_t();
- sym->name = strdup(sym_reserved[i]);
- sym->type = SYMBOL_RESERVED;
- sym->meth = NULL;
- sym->next = NULL;
- if (last)
- {
- last->next = sym;
- }
- else
- {
- tab->first = sym;
- }
- last = sym;
+ SymbolPointer sym(new SelectionParserSymbol(
+ new SelectionParserSymbol::Impl(
+ SelectionParserSymbol::ReservedSymbol, sym_reserved[i])));
+ addSymbol(move(sym));
}
}
-/*! \brief
- * Adds the position symbols to the symbol list.
- *
- * \param[in,out] tab Symbol table to which the symbols are added.
- */
-static void
-add_position_symbols(gmx_sel_symtab_t *tab)
+void
+SelectionParserSymbolTable::Impl::addPositionSymbols()
{
- gmx_sel_symrec_t *last;
- int i;
-
const char *const *postypes
= gmx::PositionCalculationCollection::typeEnumValues;
- last = tab->first;
- while (last && last->next)
+ for (int i = 0; postypes[i] != NULL; ++i)
{
- last = last->next;
+ SymbolPointer sym(new SelectionParserSymbol(
+ new SelectionParserSymbol::Impl(
+ SelectionParserSymbol::PositionSymbol, postypes[i])));
+ addSymbol(move(sym));
}
- for (i = 0; postypes[i] != NULL; ++i)
- {
- gmx_sel_symrec_t *sym = new gmx_sel_symrec_t();
- sym->name = strdup(postypes[i]);
- sym->type = SYMBOL_POS;
- sym->meth = NULL;
- sym->next = NULL;
- if (last)
+}
+
+/********************************************************************
+ * SelectionParserSymbolIterator
+ */
+
+/*! \internal \brief
+ * Private implementation class for SelectionParserSymbolIterator.
+ *
+ * \ingroup module_selection
+ */
+class SelectionParserSymbolIterator::Impl
+{
+ public:
+ //! Shorthand for the underlying iterator type.
+ typedef SelectionParserSymbolTable::Impl::SymbolMap::const_iterator
+ IteratorType;
+
+ /*! \brief
+ * Constructs an end iterator.
+ *
+ * \param[in] end Iterator to the end of the iterated container.
+ */
+ explicit Impl(IteratorType end)
+ : iter_(end), end_(end)
{
- last->next = sym;
}
- else
+ /*! \brief
+ * Constructs an iterator.
+ *
+ * \param[in] iter Iterator to the current symbol.
+ * \param[in] end Iterator to the end of the iterated container.
+ */
+ Impl(IteratorType iter, IteratorType end)
+ : iter_(iter), end_(end)
{
- tab->first = sym;
}
- last = sym;
- }
-}
-/*!
- * \param[out] tabp Symbol table pointer to initialize.
- *
- * Reserved and position symbols are added to the created table.
- */
-int
-_gmx_sel_symtab_create(gmx_sel_symtab_t **tabp)
+ //! Underlying iterator to the symbol container.
+ IteratorType iter_;
+ //! End of the symbol container being iterated.
+ IteratorType end_;
+};
+
+SelectionParserSymbolIterator::SelectionParserSymbolIterator(Impl *impl)
+ : impl_(impl)
{
- gmx_sel_symtab_t *tab;
+}
- snew(tab, 1);
- add_reserved_symbols(tab);
- add_position_symbols(tab);
- *tabp = tab;
- return 0;
+SelectionParserSymbolIterator::SelectionParserSymbolIterator(
+ const SelectionParserSymbolIterator &other)
+ : impl_(new Impl(*other.impl_))
+{
}
-/*!
- * \param[in] tab Symbol table to free.
- *
- * The pointer \p tab is invalid after the call.
- */
-void
-_gmx_sel_symtab_free(gmx_sel_symtab_t *tab)
+SelectionParserSymbolIterator::~SelectionParserSymbolIterator()
{
- gmx_sel_symrec_t *sym;
+}
- while (tab->first)
- {
- sym = tab->first;
- tab->first = sym->next;
- sfree(sym->name);
- delete sym;
- }
- sfree(tab);
+SelectionParserSymbolIterator &SelectionParserSymbolIterator::operator=(
+ const SelectionParserSymbolIterator &other)
+{
+ impl_.reset(new Impl(*other.impl_));
+ return *this;
}
-/*!
- * \param[in] tab Symbol table to search.
- * \param[in] name Symbol name to find.
- * \param[in] bExact If false, symbols that begin with \p name are also
- * considered.
- * \returns Pointer to the symbol with name \p name, or NULL if not found.
- *
- * If no exact match is found and \p bExact is false, returns a symbol that
- * begins with \p name if a unique matching symbol is found.
- */
-gmx_sel_symrec_t *
-_gmx_sel_find_symbol(gmx_sel_symtab_t *tab, const char *name, bool bExact)
+bool SelectionParserSymbolIterator::operator==(
+ const SelectionParserSymbolIterator &other) const
{
- return _gmx_sel_find_symbol_len(tab, name, strlen(name), bExact);
+ return impl_->iter_ == other.impl_->iter_;
}
-/*!
- * \param[in] tab Symbol table to search.
- * \param[in] name Symbol name to find.
- * \param[in] len Only consider the first \p len characters of \p name.
- * \param[in] bExact If false, symbols that begin with \p name are also
- * considered.
- * \returns Pointer to the symbol with name \p name, or NULL if not found.
- *
- * If no exact match is found and \p bExact is false, returns a symbol that
- * begins with \p name if a unique matching symbol is found.
- *
- * The parameter \p len is there to allow using this function from scanner.l
- * without modifying the text to be scanned or copying it.
- */
-gmx_sel_symrec_t *
-_gmx_sel_find_symbol_len(gmx_sel_symtab_t *tab, const char *name, size_t len,
- bool bExact)
+const SelectionParserSymbol &SelectionParserSymbolIterator::operator*() const
{
- gmx_sel_symrec_t *sym;
- gmx_sel_symrec_t *match;
- bool bUnique;
- bool bMatch;
-
- match = NULL;
- bUnique = true;
- bMatch = false;
- sym = tab->first;
- while (sym)
- {
- if (!strncmp(sym->name, name, len))
- {
- if (strlen(sym->name) == len)
- {
- return sym;
- }
- if (bMatch)
- {
- bUnique = false;
- }
- bMatch = true;
- if (sym->type == SYMBOL_METHOD)
- {
- match = sym;
- }
- }
- sym = sym->next;
- }
- if (bExact)
- {
- return NULL;
- }
+ return *impl_->iter_->second;
+}
- if (!bUnique)
+SelectionParserSymbolIterator &SelectionParserSymbolIterator::operator++()
+{
+ SelectionParserSymbol::SymbolType type = impl_->iter_->second->type();
+ do
{
- fprintf(stderr, "parse error: ambiguous symbol\n");
- return NULL;
+ ++impl_->iter_;
}
- return match;
+ while (impl_->iter_ != impl_->end_ && impl_->iter_->second->type() != type);
+ return *this;
}
-/*!
- * \param[in] tab Symbol table to search.
- * \param[in] type Type of symbol to find.
- * \returns The first symbol in \p tab with type \p type,
- * or NULL if there are no such symbols.
+/********************************************************************
+ * SelectionParserSymbolTable
*/
-gmx_sel_symrec_t *
-_gmx_sel_first_symbol(gmx_sel_symtab_t *tab, e_symbol_t type)
-{
- gmx_sel_symrec_t *sym;
- sym = tab->first;
- while (sym)
- {
- if (sym->type == type)
- {
- return sym;
- }
- sym = sym->next;
- }
- return NULL;
+SelectionParserSymbolTable::SelectionParserSymbolTable()
+ : impl_(new Impl)
+{
+ impl_->addReservedSymbols();
+ impl_->addPositionSymbols();
}
-/*!
- * \param[in] after Start the search after this symbol.
- * \param[in] type Type of symbol to find.
- * \returns The next symbol after \p after with type \p type,
- * or NULL if there are no more symbols.
- */
-gmx_sel_symrec_t *
-_gmx_sel_next_symbol(gmx_sel_symrec_t *after, e_symbol_t type)
+SelectionParserSymbolTable::~SelectionParserSymbolTable()
{
- gmx_sel_symrec_t *sym;
+}
- sym = after->next;
- while (sym)
+const SelectionParserSymbol *
+SelectionParserSymbolTable::findSymbol(const std::string &name,
+ bool bExact) const
+{
+ Impl::SymbolMap::const_iterator sym = impl_->symbols_.lower_bound(name);
+ if (sym == impl_->symbols_.end())
{
- if (sym->type == type)
+ return NULL;
+ }
+ if (sym->second->name() == name)
+ {
+ return sym->second.get();
+ }
+ if (!bExact && startsWith(sym->second->name(), name))
+ {
+ Impl::SymbolMap::const_iterator next = sym;
+ ++next;
+ if (next != impl_->symbols_.end()
+ && startsWith(next->second->name(), name))
+ {
+ GMX_THROW(InvalidInputError("'" + name + "' is ambiguous"));
+ }
+ if (sym->second->type() == SelectionParserSymbol::MethodSymbol)
{
- return sym;
+ return sym->second.get();
}
- sym = sym->next;
}
return NULL;
}
-/*! \brief
- * Internal utility function used in adding symbols to a symbol table.
- *
- * \param[in,out] tab Symbol table to add the symbol to.
- * \param[in] name Name of the symbol to add.
- * \param[out] ctype On error, the type of the conflicting symbol is
- * written to \p *ctype.
- * \returns Pointer to the new symbol record, or NULL if \p name
- * conflicts with an existing symbol.
- */
-static gmx_sel_symrec_t *
-add_symbol(gmx_sel_symtab_t *tab, const char *name, e_symbol_t *ctype)
+SelectionParserSymbolIterator
+SelectionParserSymbolTable::beginIterator(SelectionParserSymbol::SymbolType type) const
{
- gmx_sel_symrec_t *sym, *psym;
-
- /* Check if there is a conflicting symbol */
- psym = NULL;
- sym = tab->first;
- while (sym)
+ Impl::SymbolMap::const_iterator sym;
+ Impl::SymbolMap::const_iterator end = impl_->symbols_.end();
+ for (sym = impl_->symbols_.begin(); sym != end; ++sym)
{
- if (!gmx_strcasecmp(sym->name, name))
+ if (sym->second->type() == type)
{
- *ctype = sym->type;
- return NULL;
+ return SelectionParserSymbolIterator(
+ new SelectionParserSymbolIterator::Impl(sym, end));
}
- psym = sym;
- sym = sym->next;
}
-
- /* Create a new symbol record */
- if (psym == NULL)
- {
- tab->first = new gmx_sel_symrec_t();
- sym = tab->first;
- }
- else
- {
- psym->next = new gmx_sel_symrec_t();
- sym = psym->next;
- }
- sym->name = strdup(name);
- sym->meth = NULL;
- sym->next = NULL;
- return sym;
+ return endIterator();
}
-/*!
- * \param[in,out] tab Symbol table to add the symbol to.
- * \param[in] name Name of the new symbol.
- * \param[in] sel Value of the variable.
- * \returns Pointer to the created symbol record, or NULL if there was a
- * symbol with the same name.
- */
-gmx_sel_symrec_t *
-_gmx_sel_add_var_symbol(gmx_sel_symtab_t *tab, const char *name,
- const gmx::SelectionTreeElementPointer &sel)
+SelectionParserSymbolIterator
+SelectionParserSymbolTable::endIterator() const
{
- gmx_sel_symrec_t *sym;
- e_symbol_t ctype;
+ return SelectionParserSymbolIterator(
+ new SelectionParserSymbolIterator::Impl(impl_->symbols_.end()));
+}
- sym = add_symbol(tab, name, &ctype);
- if (!sym)
+void
+SelectionParserSymbolTable::addVariable(const char *name,
+ const gmx::SelectionTreeElementPointer &sel)
+{
+ // In the current parser implementation, a syntax error is produced before
+ // this point is reached, but the check is here for robustness.
+ Impl::SymbolMap::const_iterator other = impl_->symbols_.find(name);
+ if (other != impl_->symbols_.end())
{
- fprintf(stderr, "parse error: ");
- switch (ctype)
+ if (other->second->type() == SelectionParserSymbol::VariableSymbol)
{
- case SYMBOL_RESERVED:
- case SYMBOL_POS:
- fprintf(stderr, "variable name (%s) conflicts with a reserved keyword\n",
- name);
- break;
- case SYMBOL_VARIABLE:
- fprintf(stderr, "duplicate variable name (%s)\n", name);
- break;
- case SYMBOL_METHOD:
- fprintf(stderr, "variable name (%s) conflicts with a selection keyword\n",
- name);
- break;
+ GMX_THROW(InvalidInputError(
+ formatString("Reassigning variable '%s' is not supported",
+ name)));
+ }
+ else
+ {
+ GMX_THROW(InvalidInputError(
+ formatString("Variable name '%s' conflicts with a reserved keyword",
+ name)));
}
- return NULL;
}
-
- sym->type = SYMBOL_VARIABLE;
- sym->var = sel;
- return sym;
+ Impl::SymbolPointer sym(new SelectionParserSymbol(
+ new SelectionParserSymbol::Impl(
+ SelectionParserSymbol::VariableSymbol, name)));
+ sym->impl_->var_ = sel;
+ impl_->addSymbol(move(sym));
}
-/*!
- * \param[in,out] tab Symbol table to add the symbol to.
- * \param[in] name Name of the new symbol.
- * \param[in] method Method that this symbol represents.
- * \returns Pointer to the created symbol record, or NULL if there was a
- * symbol with the same name.
- */
-gmx_sel_symrec_t *
-_gmx_sel_add_method_symbol(gmx_sel_symtab_t *tab, const char *name,
- struct gmx_ana_selmethod_t *method)
+void
+SelectionParserSymbolTable::addMethod(const char *name,
+ gmx_ana_selmethod_t *method)
{
- gmx_sel_symrec_t *sym;
- e_symbol_t ctype;
-
- sym = add_symbol(tab, name, &ctype);
- if (!sym)
+ if (impl_->symbols_.find(name) != impl_->symbols_.end())
{
- fprintf(stderr, "parse error: ");
- switch (ctype)
- {
- case SYMBOL_RESERVED:
- case SYMBOL_POS:
- fprintf(stderr, "method name (%s) conflicts with a reserved keyword\n",
- name);
- break;
- case SYMBOL_VARIABLE:
- fprintf(stderr, "method name (%s) conflicts with a variable name\n",
- name);
- break;
- case SYMBOL_METHOD:
- fprintf(stderr, "duplicate method name (%s)\n", name);
- break;
- }
- return NULL;
+ GMX_THROW(APIError(
+ formatString("Method name '%s' conflicts with another symbol",
+ name)));
}
-
- sym->type = SYMBOL_METHOD;
- sym->meth = method;
- return sym;
+ Impl::SymbolPointer sym(new SelectionParserSymbol(
+ new SelectionParserSymbol::Impl(
+ SelectionParserSymbol::MethodSymbol, name)));
+ sym->impl_->meth_ = method;
+ impl_->addSymbol(move(sym));
}
+
+} // namespace gmx
#ifndef GMX_SELECTION_SYMREC_H
#define GMX_SELECTION_SYMREC_H
+#include <iterator>
+#include <string>
+
+#include "gromacs/utility/common.h"
+
#include "selelem.h"
struct gmx_ana_selmethod_t;
-/** Defines the type of the symbol. */
-typedef enum
+namespace gmx
+{
+
+class SelectionParserSymbolTable;
+
+/*! \internal \brief
+ * Single symbol for the selection parser.
+ *
+ * Public methods in this class do not throw.
+ *
+ * \ingroup module_selection
+ */
+class SelectionParserSymbol
+{
+ public:
+ //! Defines the type of the symbol.
+ enum SymbolType
+ {
+ ReservedSymbol, //!< The symbol is a reserved keyword.
+ VariableSymbol, //!< The symbol is a variable.
+ MethodSymbol, //!< The symbol is a selection method.
+ PositionSymbol //!< The symbol is a position keyword.
+ };
+
+ ~SelectionParserSymbol();
+
+ //! Returns the name of the symbol.
+ const std::string &name() const;
+ //! Returns the type of the symbol.
+ SymbolType type() const;
+
+ /*! \brief
+ * Returns the method associated with a \ref MethodSymbol symbol.
+ *
+ * \returns The method associated with the symbol.
+ *
+ * Must only be called if type() returns \ref MethodSymbol.
+ */
+ gmx_ana_selmethod_t *methodValue() const;
+ /*! \brief
+ * Returns the selection tree associated with a \ref VariableSymbol symbol.
+ *
+ * \returns The variable expression associated with the symbol.
+ *
+ * Must only be called if type() returns \ref VariableSymbol.
+ */
+ const SelectionTreeElementPointer &variableValue() const;
+
+ private:
+ class Impl;
+
+ /*! \brief
+ * Initializes a new symbol with the given data.
+ *
+ * \param impl Implementation data.
+ * \throws std::bad_alloc if out of memory.
+ *
+ * Only the parent symbol table creates symbol objects.
+ */
+ explicit SelectionParserSymbol(Impl *impl);
+
+ PrivateImplPointer<Impl> impl_;
+
+ /*! \brief
+ * Needed to call the constructor and for other initialization.
+ */
+ friend class SelectionParserSymbolTable;
+};
+
+/*! \internal \brief
+ * Input iterator for iterating symbols of a given type.
+ *
+ * Behaves as standard C++ input iterator. To get an iterator, call
+ * SelectionParserSymbolTable::beginIterator(). Each time the iterator is
+ * incremented, it moves to the next symbol of the type given when the iterator
+ * was created. When there are no more symbols, the iterator will equal
+ * SelectionParserSymbolTable::endIterator(). It is not allowed to dereference
+ * or increment an iterator that has reached the end.
+ *
+ * Construction and assignment may throw std::bad_alloc if out of memory.
+ * Other methods do not throw.
+ *
+ * \see SelectionParserSymbolTable::beginIterator()
+ *
+ * \ingroup module_selection
+ */
+class SelectionParserSymbolIterator
+ : public std::iterator<std::input_iterator_tag, const SelectionParserSymbol>
+{
+ public:
+ //! Creates an independent copy of an iterator.
+ SelectionParserSymbolIterator(const SelectionParserSymbolIterator &other);
+ ~SelectionParserSymbolIterator();
+
+ //! Creates an independent copy of an iterator.
+ SelectionParserSymbolIterator &
+ operator=(const SelectionParserSymbolIterator &other);
+
+ //! Equality comparison for iterators.
+ bool operator==(const SelectionParserSymbolIterator &other) const;
+ //! Inequality comparison for iterators.
+ bool operator!=(const SelectionParserSymbolIterator &other) const
+ {
+ return !operator==(other);
+ }
+ //! Dereferences the iterator.
+ reference operator*() const;
+ //! Dereferences the iterator.
+ pointer operator->() const { return &operator*(); }
+ //! Moves the iterator to the next symbol.
+ SelectionParserSymbolIterator &operator++();
+ //! Moves the iterator to the next symbol.
+ SelectionParserSymbolIterator operator++(int)
+ {
+ SelectionParserSymbolIterator tmp(*this);
+ operator++();
+ return tmp;
+ }
+
+ private:
+ class Impl;
+
+ /*! \brief
+ * Initializes a new iterator with the given data.
+ *
+ * \param impl Implementation data.
+ *
+ * Only the parent symbol table can create non-default-constructed
+ * iterators.
+ */
+ explicit SelectionParserSymbolIterator(Impl *impl);
+
+ PrivateImplPointer<Impl> impl_;
+
+ /*! \brief
+ * Needed to access the constructor.
+ */
+ friend class SelectionParserSymbolTable;
+};
+
+/*! \internal \brief
+ * Symbol table for the selection parser.
+ *
+ * \ingroup module_selection
+ */
+class SelectionParserSymbolTable
{
- SYMBOL_RESERVED, /**< The symbol is a reserved keyword. */
- SYMBOL_VARIABLE, /**< The symbol is a variable. */
- SYMBOL_METHOD, /**< The symbol is a selection method. */
- SYMBOL_POS /**< The symbol is a position keyword. */
-} e_symbol_t;
-
-/** Symbol table for the selection parser. */
-typedef struct gmx_sel_symtab_t gmx_sel_symtab_t;
-/** Single symbol for the selection parser. */
-typedef struct gmx_sel_symrec_t gmx_sel_symrec_t;
-
-/** Returns the name of a symbol. */
-char *
-_gmx_sel_sym_name(gmx_sel_symrec_t *sym);
-/** Returns the type of a symbol. */
-e_symbol_t
-_gmx_sel_sym_type(gmx_sel_symrec_t *sym);
-/** Returns the method associated with a \ref SYMBOL_METHOD symbol. */
-struct gmx_ana_selmethod_t *
-_gmx_sel_sym_value_method(gmx_sel_symrec_t *sym);
-/** Returns the selection tree associated with a \ref SYMBOL_VARIABLE symbol. */
-const gmx::SelectionTreeElementPointer &
-_gmx_sel_sym_value_var(gmx_sel_symrec_t *sym);
-
-/** Creates a new symbol table. */
-int
-_gmx_sel_symtab_create(gmx_sel_symtab_t **tabp);
-/** Frees all memory allocated for a symbol table. */
-void
-_gmx_sel_symtab_free(gmx_sel_symtab_t *tab);
-/** Finds a symbol by name. */
-gmx_sel_symrec_t *
-_gmx_sel_find_symbol(gmx_sel_symtab_t *tab, const char *name, bool bExact);
-/** Finds a symbol by name. */
-gmx_sel_symrec_t *
-_gmx_sel_find_symbol_len(gmx_sel_symtab_t *tab, const char *name, size_t len,
- bool bExact);
-/** Returns the first symbol of a given type. */
-gmx_sel_symrec_t *
-_gmx_sel_first_symbol(gmx_sel_symtab_t *tab, e_symbol_t type);
-/** Returns the next symbol of a given type. */
-gmx_sel_symrec_t *
-_gmx_sel_next_symbol(gmx_sel_symrec_t *after, e_symbol_t type);
-/** Adds a new variable symbol. */
-gmx_sel_symrec_t *
-_gmx_sel_add_var_symbol(gmx_sel_symtab_t *tab, const char *name,
- const gmx::SelectionTreeElementPointer &sel);
-/** Adds a new method symbol. */
-gmx_sel_symrec_t *
-_gmx_sel_add_method_symbol(gmx_sel_symtab_t *tab, const char *name,
- struct gmx_ana_selmethod_t *method);
+ public:
+ /*! \brief
+ * Creates a new symbol table.
+ *
+ * \throws std::bad_alloc if out of memory.
+ *
+ * The created table is initialized with reserved and position symbols.
+ */
+ SelectionParserSymbolTable();
+ ~SelectionParserSymbolTable();
+
+ /*! \brief
+ * Finds a symbol by name.
+ *
+ * \param[in] name Symbol name to find.
+ * \param[in] bExact If false, symbols that begin with \p name are also
+ * considered.
+ * \returns Pointer to the symbol with name \p name, or
+ * NULL if not found.
+ * \throws InvalidInputError if \p bExact is false and an ambiguous
+ * symbol is provided.
+ *
+ * If no exact match is found and \p bExact is false, returns a symbol
+ * that begins with \p name if a unique matching symbol is found.
+ * Only selection methods are considered for this inexact match.
+ */
+ const SelectionParserSymbol *
+ findSymbol(const std::string &name, bool bExact) const;
+
+ /*! \brief
+ * Returns the start iterator for iterating symbols of a given type.
+ *
+ * \param[in] type Type of symbols to iterate over.
+ * \returns Iterator that points to the first symbol of type \p type.
+ * \throws std::bad_alloc if out of memory.
+ *
+ * \see SelectionParserSymbolIterator
+ */
+ SelectionParserSymbolIterator
+ beginIterator(SelectionParserSymbol::SymbolType type) const;
+ /*! \brief
+ * Returns the end iterator for symbol iteration.
+ *
+ * \throws std::bad_alloc if out of memory.
+ *
+ * Currently, the end value is the same for all symbol types.
+ *
+ * \see SelectionParserSymbolIterator
+ */
+ SelectionParserSymbolIterator endIterator() const;
+
+ /*! \brief
+ * Adds a new variable symbol.
+ *
+ * \param[in] name Name of the new symbol.
+ * \param[in] sel Value of the variable.
+ * \throws std::bad_alloc if out of memory.
+ * \throws InvalidInputError if there was a symbol with the same
+ * name.
+ */
+ void addVariable(const char *name,
+ const SelectionTreeElementPointer &sel);
+ /*! \brief
+ * Adds a new method symbol.
+ *
+ * \param[in] name Name of the new symbol.
+ * \param[in] method Method that this symbol represents.
+ * \throws std::bad_alloc if out of memory.
+ * \throws APIError if there was a symbol with the same name.
+ */
+ void addMethod(const char *name, gmx_ana_selmethod_t *method);
+
+ private:
+ class Impl;
+
+ PrivateImplPointer<Impl> impl_;
+
+ /*! \brief
+ * Needed to access implementation types.
+ */
+ friend class SelectionParserSymbolIterator;
+};
+
+} // namespace gmx
#endif
namespace gmx
{
+/*! \brief
+ * Tests whether a string starts with another string.
+ *
+ * \param[in] str String to process.
+ * \param[in] prefix Prefix to find.
+ * \returns true if \p str starts with \p prefix.
+ *
+ * Returns true if \p prefix is empty.
+ * Does not throw.
+ *
+ * \inpublicapi
+ */
+bool inline startsWith(const std::string &str, const std::string &prefix)
+{
+ return str.compare(0, prefix.length(), prefix) == 0;
+}
+
/*! \brief
* Tests whether a string ends with another string.
*
* \param[in] str String to process.
* \param[in] suffix Suffix to find.
- * \returns true if \p str ends with suffix.
+ * \returns true if \p str ends with \p suffix.
*
* Returns true if \p suffix is NULL or empty.
* Does not throw.
* Tests for simple string utilities
*/
+TEST(StringUtilityTest, StartsWithWorks)
+{
+ EXPECT_TRUE(gmx::startsWith("foobar", "foo"));
+ EXPECT_TRUE(gmx::startsWith("foobar", ""));
+ EXPECT_TRUE(gmx::startsWith("", ""));
+ EXPECT_FALSE(gmx::startsWith("", "foobar"));
+ EXPECT_FALSE(gmx::startsWith("foo", "foobar"));
+ EXPECT_FALSE(gmx::startsWith("foobar", "oob"));
+}
+
TEST(StringUtilityTest, EndsWithWorks)
{
EXPECT_TRUE(gmx::endsWith("foobar", "bar"));
EXPECT_TRUE(gmx::endsWith("foobar", NULL));
EXPECT_TRUE(gmx::endsWith("foobar", ""));
+ EXPECT_TRUE(gmx::endsWith("", ""));
+ EXPECT_FALSE(gmx::endsWith("", "foobar"));
EXPECT_FALSE(gmx::endsWith("foobar", "bbar"));
EXPECT_FALSE(gmx::endsWith("foobar", "barr"));
EXPECT_FALSE(gmx::endsWith("foobar", "foofoobar"));