Please review any and all PUBLIC repositories, groups and associate files. These allow anyone on the Internet to access without authentication. Repository and group owners are responsible for their content and permission settings. Go to your project(s), click on Settings > General and expand the "Visibility, project features, permissions" to change this setting.

Introduction of SORT option for SHOW Table and SHOW Chart operation

parent d92d9483
-- MP_generator.rig Phoenix -> C++ code generator
-- V 3.0
-- Mikhail Auguston, 03/22/15
-- last modified 04/04/19
-- last modified 12/02/19
-- use: MP_generator intermediate_file
-----------------------------------
#AG
......@@ -45,13 +45,12 @@
$event_attributes:= $model.event_attributes;
$view_object_list:= $model.view_objects;
$AD_list:= $model.AD_list;
$TABLE_list:= $model.TABLE_list;
$CHART_list:= $model.CHART_list;
OPEN GEN #IMPLODE( $model.output_file '.cpp' ); -- for C++ code
OPEN MSG ' '; --for error messages
--MSG<< '>>>>>>>>>>>>>' input tree ;--<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
--PRINT $model;--<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
GEN<< '/* Monterey Phoenix-> C++ compiler, v.4.0, March 2018';
GEN<< ' Mikhail Auguston, NPS, CS Dept, Monterey, CA, USA';GEN<<;
GEN<< 'SCHEMA' $model.schema trace generator for scope $model.scope;
......@@ -126,6 +125,10 @@
GEN<< ' unique_num = 0; derivation_path_mark = -1;';
GEN<< @ ' JSON.open("' $model.output_file '.json");';
GEN<< ' global_flag =' @ $model.global_flag ';';
-- add tab names to all table and chart objects
#add_tab_names_to_table_objects($TABLE_list); -- these rules in MP4_view_gen.rig
#add_tab_names_to_chart_objects($CHART_list);
GEN<< ' cout<< "generating traces for scope' $model.scope '"<<endl;';
GEN<< '//----------------------------';
GEN<<' try{';
......@@ -309,8 +312,165 @@
*>
##
#initial_thread_construction
-- called from #generate_operation branch 2 (COORDINATE)
$variable
<. selection_pattern:
/GEN<< ' //' preparing thread for $variable;
GEN<< ' for(int i = 0; i < len; i++){';
-- prepare variables used in SUCH THAT bool_expr
GEN<< ' //' preparing loop variables for use in SUCH THAT and FROM;
GEN<< ' ' $variable '= i;';
GEN<< ' if(' @ $variable '_list.size() == thread_length){';
-- if $variable list has reached the limit,
-- all the rest of loop variables are assigned the schema event
-- if later SUCH THIS is satisfied, thread will be rejected anyway because of exceeding length
FORALL $v IN LAST #generate_operation $source_tree DO
IF $v <> $variable ->
GEN<< ' ' $v '= 0;'
ELSIF T -> BREAK
FI
OD;
GEN<] '}';
GEN<< ' else{';
-- if the $variable thread length has not yet been exceeded,
-- then synchronize all loop variables defined before $v
FORALL $v IN LAST #generate_operation $source_tree DO
IF $v <> $variable ->
GEN<< ' ' $v '=' @ $v '_list[' $variable '_list.size()];'
ELSIF T -> BREAK
FI
OD;
GEN<] '};';
GEN<< ' if(in_matrix[i * len + ' LAST #generate_operation $source_tree.$variable ']){';
GEN<< @' if( (';
$or_op:= ' '/
(. (* /GEN<] @ $or_op/
( '$$EVENT' /GEN<] '(Stack[i]->type == Atom ||'
'Stack[i]->type == ROOT_node ||'
'Stack[i]->type == Composite_event_instance_node)'/ !
'$$ATOM' /GEN<] '(Stack[i]->type == Atom)'/ !
'$$ROOT' /GEN<] '(Stack[i]->type == ROOT_node)'/ !
'$$COMPOSITE' /GEN<] '(Stack[i]->type == Composite_event_instance_node)'/ !
$event_name /GEN<] @ ' (Stack[i]->name == Event_' $event_name ')'/ )
/$or_op:= '||'/
*) .)
/GEN<] ')'/,
[ such_that:
/GEN<] '&&'/
#generate_expr ]
.>
/GEN<] @ ' ){';
GEN<< ' //' make sure this is fresh event not yet shared;
GEN<< ' int found = 0;';
GEN<< @' for(vector<int>:: iterator s = '
$variable '_list.begin(); s != ' $variable '_list.end(); s++){';
GEN<< ' if((found = eq_matrix[i * len + *s])) break;';
GEN<< ' }';
GEN<< @' if(!found) ' $variable '_list.push_back(i);';
GEN<< ' }';
GEN<< ' } };'/
##
#thread_synchronization
-- called from #generate_operation branch 2 (COORDINATE)
$variable
<. [ source_index: $source_index ], -- for <!> only
synchronization:
( '!>>'
/GEN<<;
GEN<< ' //' for syncronized source sort the list
and check for total order;
GEN<< @ ' sort_and_check_coordinated_events('
$variable '_list);' / !
(. (+
(
SHIFT_LEFT
/GEN<<;
GEN<< ' //' do the SHIFT_LEFT reshuffling;
GEN<< @ ' if(' $variable '_list.size() > 0) ';
GEN<< @ ' rotate('
$variable '_list.begin(), ' $variable '_list.begin() + 1, '
$variable '_list.end());'/ !
SHIFT_RIGHT
/GEN<<;
GEN<< ' //' do the SHIFT_RIGHT reshuffling;
GEN<< @ ' if(' $variable '_list.size() > 0) ';
GEN<< @ ' rotate('
$variable '_list.begin(), ' $variable '_list.end() - 1, '
$variable '_list.end());'/ !
<. CUT_FRONT: $num .>
/GEN<<;
GEN<< ' //' do the CUT_FRONT $num reshuffling;
GEN<< @ ' if(' $variable '_list.size() >=' $num ')';
GEN<< @ ' ' $variable '_list.erase(' $variable '_list.begin(),'
$variable '_list.begin() + ' $num ');';
GEN<< ' else throw failed;'/ !
<. CUT_END: $num .>
/GEN<<;
GEN<< ' //' do the CUT_END $num reshuffling;
GEN<< @ ' if(' $variable '_list.size() >=' $num ')';
GEN<< @ ' ' $variable '_list.erase(' $variable '_list.end() - ' $num
', ' $variable '_list.end());';
GEN<< ' else throw failed;'/ !
<. FIRST: $num .>
/GEN<<;
GEN<< ' //' do the FIRST $num reshuffling;
GEN<< @ ' if(' $variable '_list.size() >=' $num ')' ;
GEN<< @ ' ' $variable '_list.erase(' $variable '_list.begin() + ' $num ', '
$variable '_list.end());';
GEN<< ' else throw failed;'/ !
<. 'LAST': $num .>
/GEN<<;
GEN<< ' //' do the 'LAST' $num reshuffling;
GEN<< @ ' if(' $variable '_list.size() >=' $num ')' ;
GEN<< @ ' ' $variable '_list.erase(' $variable '_list.begin(), '
$variable '_list.end() - ' $num ');';
GEN<< ' else throw failed;'/ !
REVERSE
/GEN<<;
GEN<< ' //' do the REVERSE reshuffling;
GEN<< @ ' reverse(' $variable '_list.begin(), '
$variable '_list.end());'/ !
SORT
/GEN<<;
GEN<< ' //' do the SORT reshuffling;
GEN<< @ ' topological_sort(' $variable '_list);'/
)
+) .) !
$perm:= ('<!>' ! '<!CHAIN>')
/GEN<< ' // ****' $perm source with permutations '****';
#generate_asynchronous_source_point($variable $source_index $perm);/ !
$a -- Default
/GEN<< ' //' no processing needed for the default source @ $variable '_list'/
)
.>
##
---------------------------------------------------------------------------------
#generate_operation
-- global: $source_tree, used in #initial_thread_construction
<. operation: simple_action_list,
list: (. (* #generate_operation *) .) .>;;
......@@ -320,10 +480,11 @@
-- generates a new nested block for each COORDINATE
-- to ensure the proper scope for variables
/LAST #generate_coordination_class $nesting_depth +:= 1;
GEN<< ' { // COORDINATE operation'/,
GEN<< ' { //' COORDINATE operation;
GEN<< ' int' thread_length '= -1;'/,
source_list:
<* $variable:
<* $variable:
/GEN<< ' int' @ $variable '; // thread variable';
GEN<< @ ' vector<int> ' $variable
'_list; // list of coordinated events' /
......@@ -352,156 +513,23 @@
*>,
-- second pass
source_list:
/GEN<<;
GEN<< ' // create lists of coordinated events';
GEN<< ' for(int i = 0; i < len; i++){'/
<* $variable:
<. [ such_that: $st ],
selection_pattern:
/GEN<< ' if(in_matrix[i * len + ' $source_tree.$variable ']){';
IF $st ->
-- prepare variables used in SUCH THAT bool_expr
GEN<< ' //' preparing variable for SUCH THAT ;
GEN<< ' ' $variable '= i;'
FI;
GEN<< @' if( (';
$or_op:= ' '/
(. (* /GEN<] @ $or_op/
( -- '$$ANY' /GEN<] 'true'/ !
'$$EVENT' /GEN<] '(Stack[i]->type == Atom ||'
'Stack[i]->type == ROOT_node ||'
'Stack[i]->type == Composite_event_instance_node)'/ !
'$$ATOM' /GEN<] '(Stack[i]->type == Atom)'/ !
'$$ROOT' /GEN<] '(Stack[i]->type == ROOT_node)'/ !
'$$COMPOSITE' /GEN<] '(Stack[i]->type == Composite_event_instance_node)'/ !
$event_name
/GEN<] @ ' (Stack[i]->name == Event_'
$event_name ')'/
)
/$or_op:= '||'/
*) .)
/GEN<] ')'/,
[ such_that:
/GEN<] '&&'/
#generate_expr ]
.>
/GEN<] @ ' ){';
GEN<< ' //' make sure this is fresh event not yet shared;
GEN<< ' int found = 0;';
GEN<< @' for(vector<int>:: iterator s = '
$variable '_list.begin(); s != ' $variable '_list.end(); s++){';
GEN<< ' if((found = eq_matrix[i * len + *s])) break;';
GEN<< ' }';
GEN<< @' if(!found) ' $variable '_list.push_back(i);';
GEN<< ' }';
GEN<< ' }'/
*>
source_list:
/GEN<<;
GEN<< ' // create lists of coordinated events'/
/GEN<< ' }'/,
source_list:
<* $variable:
<. [ source_index: $source_index ], -- for <!> only
synchronization:
( '!>>'
/GEN<<;
GEN<< ' //' for syncronized source sort the list
and check for total order;
GEN<< @ ' sort_and_check_coordinated_events('
$variable '_list);' / !
(. (+
(
SHIFT_LEFT
/GEN<<;
GEN<< ' //' do the SHIFT_LEFT reshuffling;
GEN<< @ ' if(' $variable '_list.size() > 0) ';
GEN<< @ ' rotate('
$variable '_list.begin(), ' $variable '_list.begin() + 1, '
$variable '_list.end());'/ !
SHIFT_RIGHT
/GEN<<;
GEN<< ' //' do the SHIFT_RIGHT reshuffling;
GEN<< @ ' if(' $variable '_list.size() > 0) ';
GEN<< @ ' rotate('
$variable '_list.begin(), ' $variable '_list.end() - 1, '
$variable '_list.end());'/ !
<. CUT_FRONT: $num .>
/GEN<<;
GEN<< ' //' do the CUT_FRONT $num reshuffling;
GEN<< @ ' if(' $variable '_list.size() >=' $num ')';
GEN<< @ ' ' $variable '_list.erase(' $variable '_list.begin(),'
$variable '_list.begin() + ' $num ');';
GEN<< ' else throw failed;'/ !
<. CUT_END: $num .>
/GEN<<;
GEN<< ' //' do the CUT_END $num reshuffling;
GEN<< @ ' if(' $variable '_list.size() >=' $num ')';
GEN<< @ ' ' $variable '_list.erase(' $variable '_list.end() - ' $num
', ' $variable '_list.end());';
GEN<< ' else throw failed;'/ !
<. FIRST: $num .>
/GEN<<;
GEN<< ' //' do the FIRST $num reshuffling;
GEN<< @ ' if(' $variable '_list.size() >=' $num ')' ;
GEN<< @ ' ' $variable '_list.erase(' $variable '_list.begin() + ' $num ', '
$variable '_list.end());';
GEN<< ' else throw failed;'/ !
<. 'LAST': $num .>
/GEN<<;
GEN<< ' //' do the 'LAST' $num reshuffling;
GEN<< @ ' if(' $variable '_list.size() >=' $num ')' ;
GEN<< @ ' ' $variable '_list.erase(' $variable '_list.begin(), '
$variable '_list.end() - ' $num ');';
GEN<< ' else throw failed;'/ !
REVERSE
/GEN<<;
GEN<< ' //' do the REVERSE reshuffling;
GEN<< @ ' reverse(' $variable '_list.begin(), '
$variable '_list.end());'/ !
SORT
/GEN<<;
GEN<< ' //' do the SORT reshuffling;
GEN<< @ ' topological_sort(' $variable '_list);'/
)
+) .) !
$perm:= ('<!>' ! '<!CHAIN>')
/#check_selected_lists_for_same_length($source_list);
GEN<< ' // ****' $perm source with permutations '****';
#generate_asynchronous_source_point($variable $source_index $perm);/ !
$a -- Default
/GEN<< ' //' no processing needed for the default source @ $variable '_list'/
)
.>
*> ,
<* $variable: $thread_description
/#initial_thread_construction($variable $thread_description);
#thread_synchronization($variable $thread_description);
GEN<< ' //' finally check the thread length;
GEN<< ' if(thread_length < 0)' thread_length '=' @ $variable '_list.size();';
GEN<< ' if(thread_length !=' @ $variable '_list.size()) throw failed;';
GEN<<;/
*>,
body: $body,
body: / #check_selected_lists_for_same_length($source_list);
GEN<< ' //' do the COORDINATE;
body: / GEN<< ' //' do the COORDINATE;
IF $body[1] <> ';' -> -- if non-empty DO-OD body
GEN<< ' for(int i = 0; i <' #IMPLODE($source_list[1][1] '_list.size()') '; i++){';
GEN<< ' for(int i = 0; i < thread_length; i++){';
FORALL $var IN $source_list DO
GEN<< @ ' ' $var[1] '= ' $var[1] '_list[i];'
OD
......@@ -520,7 +548,7 @@
FI;
IF LAST #generate_coordination_class $nesting_depth < 2 ->
GEN<< ' create_matrices(); //' to check for axiom violation;
GEN<< ' //print_matrices(); //<<<<<<<<<<<<'
--GEN<< ' //print_matrices(); //<<<<<<<<<<<<'
FI;
GEN<< '} //' end of COORDINATE;
LAST #generate_coordination_class $nesting_depth +:= -1/
......@@ -703,7 +731,12 @@
-- or use std::to_string(int) std::to_string(double) , but not all C++ compilers support it
<. operation: SAY
/GEN<< ' { // SAY_event generation';
/IF LAST #AG $global_generation_flag ->
#generate_global_SAY_message($);
-- to avoid adding SAY as event and create_matrices()
RETURN T;
FI;
GEN<< ' { // SAY_event generation';
GEN<< ' string message;'/,
list: #string_construction_gen
/GEN<< ' message = convert.str();'/
......@@ -754,6 +787,7 @@ GEN<< ' make_equality_complete(' $v1 ',' $v2 ');'/ ;;
#gen_SET_timing_attribute !
#generate_view_object_title_update !
#generate_report_increment !
#generate_add_tuple !
#generate_view_object_CLEAR_op !
#generate_view_object_SHOW !
#generate_Graph_description_processing !
......
......@@ -39,7 +39,7 @@
##
#thread
-- called from #coordinate_composition, Quantified_bool_expr in #bool_expr3,
-- called from #coordination_source, Quantified_bool_expr in #bool_expr3,
-- and aggregate operations
( $var:= #variable ! -- returns 'abc_variable'
......@@ -54,7 +54,7 @@
!
$a /#error( $a err2 ); FAIL/ )
[ 'FROM' $source:= #event_instance ]
[ $f:= 'FROM' $source:= #event_instance ]
-- the default for source is FROM THIS
/IF NOT $source ->
......@@ -127,10 +127,11 @@
/LAST #MP $coordination_nesting +:=1;
$asynchronous_source_count := NULL;
-- maintain the $source_list
$old_source_list:= COPY(LAST #MP $source_list)/
$old_source_list:= COPY(LAST #MP $source_list)/
(+ $coord++:= #coordination_source
/LAST #MP $source_list ++:= $coord/ -- adjust variable list
(+ $cs:= #coordination_source
/$coord++:= $cs;
LAST #MP $source_list ++:= $coord/ -- adjust variable list
-- also calculates LAST #top_composition_operation $asynchronous_source_count for <!>
+',')
......@@ -199,7 +200,7 @@
#event_reshuffling_option
'<' '!' [ $chain:= CHAIN ] '>'
-- asynchronous reshufflinh is detected
-- asynchronous reshuffling is detected
/IF LAST #MP $coordination_nesting > 1 ->
#error( $ err43 ); FAIL
FI;
......@@ -514,7 +515,8 @@
#graph_processing !
#graph_operation !
#loop_over_graph !
#FOR_loop )
#FOR_loop !
#add_tuple_command )
)
#semicolon
+)
......
......@@ -64,7 +64,6 @@
-- +) .)
-- .>
-- *>
-- used by #prepare_share_all in second_pass.rig to check whether shared events have been defined
-- $share_all_ops: <* work_name: <. operation: SHARE_ALL,
-- work: work_name,
......@@ -101,6 +100,8 @@
--
-- requested for Activity Diagrams
-- $AD_list: <* event_name: (ROOT ! composite) *> go to the event trace screen
-- $TABLE_list: <. table_name: table_description -- see $res in #VIEW_description
-- $CHART_list: <. chart_name: chart_description -- see $res in #VIEW_description
-- $global_SAY_present: (T ! NULL) to create global_SAY list in the .cpp file
--
-- $node_variables: <* variable_name: #unique_number() *>
......@@ -155,7 +156,7 @@
--
------------- VIEW object descriptions -----------------------------
-- $global_flag: (true ! false) if GLOBAL section is present
-- $view_objects: <* object_name: ( <. type: ( REPORT ! GRAPH ),
-- $view_objects: <* object_name: ( <. type: ( REPORT ! GRAPH ! TABLE),
-- name: $report_name,
-- work: work_name, -- for class generation
-- work2: $work2 -- for container name
......@@ -230,7 +231,9 @@
-- plain_attributes: $BUILD_block.plain_attributes,
-- global: $global -- list of operations
-- .>
IF NOT $roots ->
#error( $input_file err90 ); FAIL
FI;
--*********** 2nd pass, insert/expand composite events,
-- create $new_root_table, $new_composites
......@@ -274,6 +277,8 @@
view_objects: $view_objects,
global_flag: $global_flag, -- (true ! false)
AD_list: $AD_list,
TABLE_list: $TABLE_list,
CHART_list: $CHART_list,
global_SAY_present: $global_SAY_present
.>;
......@@ -427,7 +432,7 @@
'PRECEDES' !
'REJECT' ! 'REPORT' ! 'RESET' ! 'ROOT' !
'SAY' ! 'SET' ! 'SHARE' ! 'SHOW' ! 'SUCH' ! 'SUM' ! 'start' ! 'STEP' !
'THAT' ! 'THEN' ! 'THIS' ! 'TIMES' ! trace_id ! 'true' !
'TABLE' ! 'TABS' ! 'THAT' ! 'THEN' ! 'THIS' ! 'TIMES' ! trace_id ! 'true' !
'WHEN' ! 'WITHIN' !
'$$scope'
)
......
......@@ -99,31 +99,6 @@ assignment_op: $assignment_op, -- for :=, +=, -=, *=, /=, AND=, OR=
-------------------------------------------------------------------------------------
#check_selected_lists_for_same_length
$source_list
/GEN<<;
IF #LEN($source_list) > 1 ->
GEN<< ' //' check that selected lists are of the same length;
GEN<< @ ' if(';
$first_arg:= #IMPLODE($source_list[1][1] '_list.size()!= ');
$i:= 2;
$or_op:= ' ';
LOOP
IF $i > #LEN($source_list) -> BREAK FI;
GEN<] $or_op @ $first_arg $source_list[$i][1] '_list.size() ';
$i +:= 1;
$or_op:= '||';
END;
GEN<] ')';
GEN<< ' { throw failed;};';
GEN<<;
ELSIF T ->
GEN<< ' // single source, no list length check needed'
FI/
##
----------------------------------------------------------------
#generate_aggregate_functions
<* $work_name: #generate_aggregate_function *>
##
......
-- MP4_parse_view_objects.rig
-- Created by Mikhail Auguston on 12/3/18.
-- last updated 02/13/2019
-- last updated 11/11/2019
--------------------------------------------
---- parsing view objects and commands -----
--------------------------------------------
......@@ -10,36 +10,45 @@
LAST #MP $global_flag := 'true'/
(*
$elt_list !.:=
( #VIEW_description !
( #VIEW_description ! -- add to operations,
-- since title may be recalculated
#global_composition_operation !
$x /#error( $x err67 ); FAIL/ ) -- undefined operation in GLOBAL
#semicolon
( #semicolon ! / #error( $x err4); FAIL/ )
*)
/RETURN $elt_list/
##
#VIEW_description
$res:= #report_or_graph_description
$object:= ( REPORT ! GRAPH ! TABLE ! (BAR CHART))
-- $object = CHART for BAR CHART
/IF LAST #MP $mode = block ->
#error( $res.operation err69 ); FAIL
FI;
RETURN $res ++ <. mode: LAST #MP $mode .>/
##
#error( $object err80 ); FAIL
FI/
#report_or_graph_description
$object:= ( REPORT ! GRAPH)
$object_name:= $Id
/IF LAST #MP $view_objects.$object_name ->
#error( $object_name err66 ); FAIL
FI/
( '{' ! $a /#error( $a err21 ); FAIL/)
/$title:= (. ' ' .)/ -- default title
[ TITLE $title:= #string_constructor
[ TITLE $title:= #string_constructor
(';' ! $a /#error( $a err4 ); FAIL/) ]
[ V'($object = TABLE)
TABS
$tab_list := #tab_list
#semicolon
]
[ V'($object = CHART)
$chart:= #process_CHART
]
( '}' ! $a /#error( $a err22 ); FAIL/)
/$work:= #IMPLODE( $object '_' #unique_number() '_' #unique_number());
/$work:= #IMPLODE( $object '_' #unique_number() );
-- for class name
$un := #unique_number();
IF $object = TABLE AND NOT $tab_list ->
#error( $object err83); FAIL FI;
$res:= <. operation: #IMPLODE( $object '_description'),
type: $object,
name: $object_name,
......@@ -48,11 +57,86 @@
work: $work,
unique_num: $un,
list: $title,
mode: LAST #MP $mode .> ;
mode: LAST #MP $mode,
-- specific for Table
tab_list: $tab_list -- for TABLE
.> ;
-- add specific for CHART fields, if any
$res ++:= $chart;
-- add tis Chart to the Table on which it is based
IF $chart ->
$charts:= LAST #MP $TABLE_list.($chart.source_table_name).chart_list;
$charts ++:= <. $object_name: $res.work2 .>;
LAST #MP $TABLE_list.($chart.source_table_name) ++:=
<. chart_list: $charts .>;
LAST #MP $view_objects.($chart.source_table_name) ++:=
<. chart_list: $charts .>
FI;
LAST #MP $view_objects ++:= <. $object_name: $res .>;
IF $object = TABLE ->
LAST #MP $TABLE_list ++:= <. $object_name: $res .>;
FI;
IF $object = CHART ->
LAST #MP $CHART_list ++:= <. $object_name: $res .>;
FI;
RETURN $res/
##
#tab_list
-- tab declarations
(+
$type:= ( number ! string !
$x:= S'($$ <> ';') /#error( $x err81 ); FAIL/ )
$tab_name := $Id
/IF $list.$tab_name ->
#error( $type err86); FAIL -- double defined tab
FI;
$list ++:= <. $tab_name: $type .> /
+',')
/RETURN $list/
##
#process_CHART
( 'FROM' ! $a /#error( $a err87); FAIL/ )
$table_name:= $Id
/IF NOT LAST #MP $TABLE_list.$table_name ->
#error( $table_name err82); FAIL -- table not defined
FI/
(';' ! $a /#error( $a err4 ); FAIL/)
( 'X_AXIS' ! $a /#error( $a err88); FAIL/ )
$x_tab_name := $Id
/IF NOT LAST #MP $TABLE_list.$table_name.tab_list.$x_tab_name ->
#error( $x_tab_name err84); FAIL -- x_tab not defined in Table