C++ classes for selection parser symbol table.
authorTeemu Murtola <teemu.murtola@gmail.com>
Sat, 11 Aug 2012 11:53:38 +0000 (14:53 +0300)
committerTeemu Murtola <teemu.murtola@gmail.com>
Tue, 28 Aug 2012 03:34:48 +0000 (06:34 +0300)
Convert the implementation of selection parser symbol table to use C++
classes.
 - Removes a few exception safety issues that were present in the
   initialization, as well as direct prints to stderr.
 - Documentation now follows the new Doxygen layout.
 - Removes some underscore-prefixed global names.

Related to #655 and #880.

Change-Id: Iecb690fa2e413c9dc487aacffac62a248ea3867a

13 files changed:
src/gromacs/selection/parser.cpp
src/gromacs/selection/parser.y
src/gromacs/selection/parsetree.cpp
src/gromacs/selection/scanner_internal.cpp
src/gromacs/selection/selectioncollection-impl.h
src/gromacs/selection/selectioncollection.cpp
src/gromacs/selection/selhelp.cpp
src/gromacs/selection/selmethod.cpp
src/gromacs/selection/selmethod.h
src/gromacs/selection/symrec.cpp
src/gromacs/selection/symrec.h
src/gromacs/utility/stringutil.h
src/gromacs/utility/tests/stringutil.cpp

index 617655360bd9322540fd680d4ff0f56a433688ff..e4f16e82b41d9717fa0abda52b1725fd06921f7d 100644 (file)
@@ -541,12 +541,12 @@ static const yytype_uint16 yyrline[] =
      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
 
@@ -1364,6 +1364,15 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
 /* 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  */
@@ -1371,7 +1380,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { if((yyvaluep->str)) free((yyvaluep->str));              };
 
 /* Line 1391 of yacc.c  */
-#line 1375 "parser.cpp"
+#line 1384 "parser.cpp"
        break;
       case 28: /* "CMP_OP" */
 
@@ -1380,7 +1389,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { free((yyvaluep->str));                     };
 
 /* Line 1391 of yacc.c  */
-#line 1384 "parser.cpp"
+#line 1393 "parser.cpp"
        break;
       case 50: /* "commands" */
 
@@ -1389,7 +1398,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { delete (yyvaluep->sel);                    };
 
 /* Line 1391 of yacc.c  */
-#line 1393 "parser.cpp"
+#line 1402 "parser.cpp"
        break;
       case 51: /* "command" */
 
@@ -1398,7 +1407,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { delete (yyvaluep->sel);                    };
 
 /* Line 1391 of yacc.c  */
-#line 1402 "parser.cpp"
+#line 1411 "parser.cpp"
        break;
       case 52: /* "cmd_plain" */
 
@@ -1407,7 +1416,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { delete (yyvaluep->sel);                    };
 
 /* Line 1391 of yacc.c  */
-#line 1411 "parser.cpp"
+#line 1420 "parser.cpp"
        break;
       case 54: /* "help_topic" */
 
@@ -1416,7 +1425,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { _gmx_selexpr_free_values((yyvaluep->val)); };
 
 /* Line 1391 of yacc.c  */
-#line 1420 "parser.cpp"
+#line 1429 "parser.cpp"
        break;
       case 55: /* "selection" */
 
@@ -1425,7 +1434,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { delete (yyvaluep->sel);                    };
 
 /* Line 1391 of yacc.c  */
-#line 1429 "parser.cpp"
+#line 1438 "parser.cpp"
        break;
       case 59: /* "string" */
 
@@ -1434,7 +1443,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { free((yyvaluep->str));                     };
 
 /* Line 1391 of yacc.c  */
-#line 1438 "parser.cpp"
+#line 1447 "parser.cpp"
        break;
       case 60: /* "sel_expr" */
 
@@ -1443,7 +1452,16 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { 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" */
 
@@ -1452,7 +1470,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { delete (yyvaluep->sel);                    };
 
 /* Line 1391 of yacc.c  */
-#line 1456 "parser.cpp"
+#line 1474 "parser.cpp"
        break;
       case 63: /* "str_expr" */
 
@@ -1461,7 +1479,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { delete (yyvaluep->sel);                    };
 
 /* Line 1391 of yacc.c  */
-#line 1465 "parser.cpp"
+#line 1483 "parser.cpp"
        break;
       case 64: /* "pos_expr" */
 
@@ -1470,7 +1488,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { delete (yyvaluep->sel);                    };
 
 /* Line 1391 of yacc.c  */
-#line 1474 "parser.cpp"
+#line 1492 "parser.cpp"
        break;
       case 65: /* "method_params" */
 
@@ -1479,7 +1497,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { _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" */
 
@@ -1488,7 +1506,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { _gmx_selexpr_free_params((yyvaluep->param)); };
 
 /* Line 1391 of yacc.c  */
-#line 1492 "parser.cpp"
+#line 1510 "parser.cpp"
        break;
       case 67: /* "method_param" */
 
@@ -1497,7 +1515,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { _gmx_selexpr_free_params((yyvaluep->param)); };
 
 /* Line 1391 of yacc.c  */
-#line 1501 "parser.cpp"
+#line 1519 "parser.cpp"
        break;
       case 68: /* "value_list" */
 
@@ -1506,7 +1524,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { _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" */
 
@@ -1515,7 +1533,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { _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" */
 
@@ -1524,7 +1542,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { _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" */
 
@@ -1533,7 +1551,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { _gmx_selexpr_free_values((yyvaluep->val)); };
 
 /* Line 1391 of yacc.c  */
-#line 1537 "parser.cpp"
+#line 1555 "parser.cpp"
        break;
       case 72: /* "value_item" */
 
@@ -1542,7 +1560,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { _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" */
 
@@ -1551,7 +1569,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { _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" */
 
@@ -1560,7 +1578,7 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
        { _gmx_selexpr_free_values((yyvaluep->val)); };
 
 /* Line 1391 of yacc.c  */
-#line 1564 "parser.cpp"
+#line 1582 "parser.cpp"
        break;
 
       default:
@@ -2305,6 +2323,7 @@ yyreduce:
 #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;
@@ -2314,9 +2333,10 @@ yyreduce:
   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;
@@ -2326,9 +2346,10 @@ yyreduce:
   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;
@@ -2338,9 +2359,10 @@ yyreduce:
   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;
@@ -2350,7 +2372,7 @@ yyreduce:
   case 43:
 
 /* Line 1806 of yacc.c  */
-#line 461 "parser.y"
+#line 465 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer sel(
@@ -2366,7 +2388,7 @@ yyreduce:
   case 44:
 
 /* Line 1806 of yacc.c  */
-#line 472 "parser.y"
+#line 476 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer sel(
@@ -2382,9 +2404,10 @@ yyreduce:
   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;
@@ -2394,9 +2417,10 @@ yyreduce:
   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;
@@ -2406,7 +2430,7 @@ yyreduce:
   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));
@@ -2417,7 +2441,7 @@ yyreduce:
   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));
@@ -2428,7 +2452,7 @@ yyreduce:
   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));
@@ -2439,7 +2463,7 @@ yyreduce:
   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));
@@ -2450,7 +2474,7 @@ yyreduce:
   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));
@@ -2461,7 +2485,7 @@ yyreduce:
   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));
@@ -2472,14 +2496,14 @@ yyreduce:
   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(
@@ -2495,9 +2519,10 @@ yyreduce:
   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;
@@ -2507,7 +2532,7 @@ yyreduce:
   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)));
@@ -2518,14 +2543,14 @@ yyreduce:
   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));
@@ -2537,9 +2562,10 @@ yyreduce:
   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;
@@ -2549,7 +2575,7 @@ yyreduce:
   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))));
@@ -2560,7 +2586,7 @@ yyreduce:
   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))));
@@ -2571,7 +2597,7 @@ yyreduce:
   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))));
@@ -2582,35 +2608,35 @@ yyreduce:
   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));
@@ -2622,84 +2648,84 @@ yyreduce:
   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)));
@@ -2710,7 +2736,7 @@ yyreduce:
   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)));
@@ -2721,7 +2747,7 @@ yyreduce:
   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)));
@@ -2732,7 +2758,7 @@ yyreduce:
   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)));
@@ -2743,14 +2769,14 @@ yyreduce:
   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);
@@ -2762,7 +2788,7 @@ yyreduce:
   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);
@@ -2774,7 +2800,7 @@ yyreduce:
   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);
@@ -2786,14 +2812,14 @@ yyreduce:
   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);
@@ -2805,7 +2831,7 @@ yyreduce:
   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);
@@ -2817,7 +2843,7 @@ yyreduce:
   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);
@@ -2829,7 +2855,7 @@ yyreduce:
 
 
 /* Line 1806 of yacc.c  */
-#line 2833 "parser.cpp"
+#line 2859 "parser.cpp"
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
index db8431bfc5eef601e44603d0fe1b50eff49cf181..b286edaedce9459fa839637bfe6304f56b9c89e9 100644 (file)
@@ -160,8 +160,8 @@ using gmx::SelectionTreeElementPointer;
 %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
@@ -422,6 +422,7 @@ pos_mod:     EMPTY_POSMOD       { $$ = NULL; }
 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;
@@ -429,6 +430,7 @@ sel_expr:    pos_mod KEYWORD_GROUP
            | 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;
@@ -436,6 +438,7 @@ sel_expr:    pos_mod KEYWORD_GROUP
            | 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;
@@ -446,6 +449,7 @@ sel_expr:    pos_mod KEYWORD_GROUP
 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;
@@ -485,6 +489,7 @@ num_expr:    TOK_INT
 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;
@@ -492,6 +497,7 @@ num_expr:    pos_mod KEYWORD_NUMERIC    %prec NUM_REDUCT
            | 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;
@@ -556,6 +562,7 @@ str_expr:    string
            | pos_mod KEYWORD_STR
              {
                  BEGIN_ACTION;
+                 scoped_ptr_sfree posmodGuard($1);
                  set($$, _gmx_sel_init_keyword($2, NULL, $1, scanner));
                  CHECK_SEL($$);
                  END_ACTION;
@@ -593,6 +600,7 @@ pos_expr:    METHOD_POS method_params
 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;
index 3168400d257c8d9efdc2f455d0f4da2f1c85bd7e..b005eb3d1d01943c259633007c6bf20e04109e3c 100644 (file)
@@ -1138,20 +1138,14 @@ _gmx_sel_assign_variable(const char *name,
     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 */
@@ -1166,10 +1160,7 @@ _gmx_sel_assign_variable(const char *name,
     /* 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);
index d7a2c791d74f56d35aee4f82eaa7c8f95206c3c7..b7a6691b50acc9c57b44a31a59fce883396c6c50 100644 (file)
 #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"
@@ -215,9 +217,6 @@ int
 _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)
     {
@@ -274,7 +273,8 @@ _gmx_sel_lexer_process_identifier(YYSTYPE *yylval, char *yytext, size_t yyleng,
     }
 
     /* 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)
     {
@@ -282,19 +282,19 @@ _gmx_sel_lexer_process_identifier(YYSTYPE *yylval, char *yytext, size_t yyleng,
         _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)
         {
@@ -331,19 +331,17 @@ _gmx_sel_lexer_process_identifier(YYSTYPE *yylval, char *yytext, size_t yyleng,
         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;
     }
index cc8391e89980d9989e14ab3a4fba37897090a2f0..9ccf506b7b2490d438242470b2c3dbfebfb415d9 100644 (file)
@@ -44,6 +44,8 @@
 #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.
@@ -92,8 +98,8 @@ struct gmx_ana_selcollection_t
     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;
 };
index d55ef58716ff921ed3a18c60978361a22028e002..6e8d228c78d12b18ac182c908f884917b39af48c 100644 (file)
@@ -83,15 +83,14 @@ SelectionCollection::Impl::Impl()
     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)
@@ -104,18 +103,13 @@ SelectionCollection::Impl::~Impl()
     {
         _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();
 }
 
 
index a22a9fad643805ae8515d7ab42cb82ab051db0d1..2255ba69894d3b1b75180fe9e887e63ec729c870 100644 (file)
@@ -39,7 +39,7 @@
 #include <vector>
 #include <utility>
 
-#include <boost/shared_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
 
 #include "gromacs/onlinehelp/helptopic.h"
 #include "gromacs/onlinehelp/helpwritercontext.h"
@@ -496,22 +496,22 @@ KeywordsHelpTopic::KeywordsHelpTopic()
     // 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;
     }
 }
 
index 11759808d77c5825381b486ae408757fc6913b06..517baa550e512aa79cd422bf98bf20b92b00a85e 100644 (file)
 #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"
 
@@ -219,10 +220,9 @@ report_param_error(FILE *fp, const char *mname, const char *pname,
  */
 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)
@@ -379,17 +379,18 @@ check_params(FILE *fp, const char *name, int nparams, gmx_ana_selparam_t 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)
@@ -397,7 +398,7 @@ check_params(FILE *fp, const char *name, int nparams, gmx_ana_selparam_t 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;
 }
@@ -487,7 +488,8 @@ check_callbacks(FILE *fp, gmx_ana_selmethod_t *method)
  * 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;
 
@@ -557,7 +559,8 @@ check_method(FILE *fp, gmx_ana_selmethod_t *method, gmx_sel_symtab_t *symtab)
  * 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;
 
@@ -616,7 +619,7 @@ check_modifier(FILE *fp, gmx_ana_selmethod_t *method, gmx_sel_symtab_t *symtab)
  * 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;
@@ -624,17 +627,22 @@ gmx_ana_selmethod_register(gmx_sel_symtab_t *symtab,
     /* 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;
         }
     }
@@ -652,7 +660,7 @@ gmx_ana_selmethod_register(gmx_sel_symtab_t *symtab,
  *   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;
index fd9b5d71e1ca448e208ee0d828e942a164f49639..ccca8df62ba224d733fbd2de39f3595fff5cec1e 100644 (file)
 namespace gmx
 {
 class PositionCalculationCollection;
+class SelectionParserSymbolTable;
 } // namespace gmx
 
 struct gmx_ana_pos_t;
@@ -650,11 +651,11 @@ typedef struct gmx_ana_selmethod_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 *
index 36648878fb6d18cd344e12e896dd267087d2705d..0cd0f2d3665f4dd552390a07c3641d59f913185e 100644 (file)
  */
 /*! \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
index 4fcdf7f8ca6eeeb7413df8ef48ee5186010f60e1..26125f8f1d550eb293ed4e4e228a7b42d14884a1 100644 (file)
 #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
index 22feb60485914838a370d3d6066a4d4ceb359862..f6bb5c917409a4cd4b8973b01872079f9c88402b 100644 (file)
 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.
index 433306268f06e5b28732ec162911c6eb79841f43..335f8f0ab66d02369586361805aacde787337542 100644 (file)
@@ -56,11 +56,23 @@ namespace
  * 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"));