#!/usr/bin/perl -w
package MpmasQlEqnTranslatorMarpa;
use strict;

use Marpa::R2;

use lib '/usr/local/lib/mpmasql/modules';
use IndexedTable;
use IndexedTableLink;

use File::Spec;
use Data::Dumper qw/Dumper/;
use Carp qw/croak/;
use MpmasQl3EqnElements;
use MpmasMILPActivity;
use MpmasInputfile;
use SimpleObjectRegistry;
use CtUtilities qw(nice_hash_dump);
use Scalar::Util qw(looks_like_number);

use Exporter;
use Storable qw(dclone);

use MpmasQLRegistry;

my $logTime = 0;

sub set_logTime{
	$logTime = $_[1];
}
use constant logMem => 0;

local $Carp::Verbose = 0;

my $verbose = 0;

##GRAMMAR definitions
#Shared rules
#section and info definitions
MARPA_SHARED_RULES:

my $shrdRules = <<'SHAREDRULEDOC';
			
set ::= name bless => set
		| name indexed bless => indexedSet
		| ('{') expressionListStringsAllowed ('}') action => ::first
		| setFunction action => ::first
		| tableSetReference action => ::first
		| set ('except') set bless => setDifference
		| subsetCondition action => ::first
#		| ('{') ('}') bless => emptySet
							

tableReference ::= columnName ('@') tableName indexed bless => tableReference
				  | ('[') stringContentElement (']') ('@') tableName indexed bless => tableReferenceVarCol
tableSetReference ::=  ('#') ('distinct_values_in_column') ('(') columnName ('@') tableName (')') bless => tableSetReferenceDistinct	
				  | ('#') ('distinct_values_in_column') ('(') columnName ('@') tableName  indexed (')') bless => tableSetReferenceDistinct	
				  | ('#') ('distinct_values_in_column') ('(') ('[') stringContentElement (']') ('@') tableName (')') bless => tableSetReferenceVarColDistinct
				  | ('#') ('distinct_values_in_column') ('(') ('[') stringContentElement (']') ('@') tableName  indexed (')') bless => tableSetReferenceVarColDistinct
				  | columnName ('@') tableName indexed bless => tableSetReference				
				  | ('[') stringContentElement (']') ('@') tableName indexed bless => tableSetReferenceVarCol
   

function ::=			 ('#') ('sum') iteratorDefinition ('(') anyExpression (')') bless => sumFunction
			| ('#') ('product') iteratorDefinition ('(') anyExpression (')') bless => productFunction
			
setFunction ::= 		  ('#') ('set_from_mapping') ('(') iteratorDefinition (',') anyExpression (')') bless => setMappingFunction
				| ('#') ('set_from_mapping_set') ('(') iteratorDefinition (',') set (')') 	   bless => setMappingFunction			





iteratorDefinition ::= ('{') iteratorAtomic ('in') set ('}') bless => iteratorDefinition




indexed		::= ('[') iteratorList (']')  action => ::first
iteratorList ::= iterator* separator => <comma>  bless => index

#stringContent2  ::= stringContentElement+  bless => stringContentList


				
iteratorAtomic ::= name bless => iterator 
				



#Lexemes:

tableName ~ <one or more word characters>
columnName ~ <one or more word characters>
name ~ <any letter that is not x> <zero or more word characters> 


<any letter that is not x> ~ [a-wyzA-Z]
<zero or more word characters> ~ [\w]*
<one or more word characters> ~ [\w]+

SHAREDRULEDOC

MARPA_INFO_RULES:

my $infoRules = <<'INFOSECTIONS';
infoDefinition ::=  infoStarter infoContent bless => infoContent
infoContent ::= 
infoContent ::= infoText action => ::first

infoText ~ infoCharset+
infoCharset ~ <not a hash> | <escaped hash> | <safe hash 1> | <safe hash 2> | <safe hash 3> | <safe hash 4>

sectionDefinition ::= 		sectionStarter infoText bless => sectionHeading

sectionStarter ~	  <hash> 'section'					
sectionStarter ~ <hash> 'subsection'			
sectionStarter ~ <hash> 'subsubsection'	

<hash> ~ '#'
<not a hash> ~  [^#]+
#<not a hash or backslash> ~  [^\\#]+
#<not newline> ~ [^\n]
<escaped hash>  ~ '\#'
#<backslash> ~ [\\]
<safe hash 1> ~ [^\s] '#'
<safe hash 2> ~ [^\n] '\n' '#'
<safe hash 3> ~ [^\n]  <ws not newline> '#'
<safe hash 4> ~ [^\n] '\n' <ws not newline> '#'
<ws not newline> ~ [\t ]+

infoStarter ~ <hash> 'info'

INFOSECTIONS

MARPA_FUNCTION_RULES:

my $basicExpressionssAndSets = <<'BASICFUNCTIONS';


anyExpression ::= 
     number bless => number
   | anyParameter action => ::first
   | function action => ::first
   | ('(') anyExpression (')') assoc => group action => ::first
  || anyExpression ('^') anyExpression  assoc => right  bless => exponentiation
  || ('-') anyExpression bless => negation
   | ('!') anyExpression bless => Not
  || anyExpression ('*') anyExpression bless => multiplication
   | anyExpression ('/') anyExpression bless => division
  || anyExpression ('+') anyExpression bless => addition
   | anyExpression ('-') anyExpression bless => subtraction
  || anyExpression ('>=') anyExpression bless => greater_equal
   | anyExpression ('<=') anyExpression bless => less_equal
   | anyExpression ('>') anyExpression bless => greater
   | anyExpression ('<') anyExpression bless => less
  || anyExpression ('==') anyExpression bless => equal
   | anyExpression ('!=') anyExpression bless => not_equal
  || anyExpression ('&&') anyExpression bless => And
   | anyExpression ('||') anyExpression bless => Or
   
   

expressionList ::= anyExpression* separator => <comma> bless => expressionList

expressionListStringsAllowed ::= stringContentElement* separator => <comma> bless => expressionList
   

function ::=  ('#') ('if') ('(') anyExpression (',') anyExpression (',') anyExpression  (')') bless => if
			| ('#') ('if_elsif') ('(')  conditionThenList (')')  action => ::first
			| ('#') ('is_equal') ('(') stringContentElement (',') stringContentElement (')') bless => isEqual
			|  stringContentElement ('equals') stringContentElement  bless => isEqual
			|  stringContentElement ('does_not_equal') stringContentElement  bless => isNotEqual
			| ('#') ('is_part_of') ('(') anyExpression (',') set (')') bless => isIn
			|  anyExpression ('is_element_of') set  bless => isIn

			| ('#') ('is_part_of') ('(') stringContentElement (',') set (')') bless => isIn
			|  stringContentElement ('is_element_of') set  bless => isIn
            | ('#') ('ifnull') ('(') anyExpression (',')  anyExpression  (')') bless => ifnull


			| ('#') ('regexp') ('(') stringContentElement (',') stringContentElement (')') bless => regexp
			|  stringContentElement ('fits_the_pattern') stringContentElement  bless => regexp

			| ('#') ('count') ('(') set (')') bless => count

			| ('#') ('var') ('(') anyParameter (')') bless => var

			| ('#') ('min') ('(') anyExpression (',') expressionList (')') bless => min
			| ('#') ('max') ('(') anyExpression (',') expressionList (')') bless => max
			| ('#') ('min') ('(') set (')') bless => minSet
			| ('#') ('max') ('(') set (')') bless => maxSet

			| ('#') ('e') ('(') anyExpression (')') bless => e 
			| ('#') ('ln') ('(') anyExpression (')') bless => ln 
			| ('#') ('random_number') ('(') anyExpression (')') bless => random_number 
			| ('#') ('classifyToMultiple') ('(') anyExpression(',') anyExpression (')') bless => classifyToMultiple
			| ('#') ('classify_to_multiple') ('(') anyExpression(',') anyExpression (')') bless => classifyToMultiple

			| ('#') ('round_to') ('(') anyExpression (',') anyExpression (')') bless => round_to 
			| ('#') ('floor') ('(') anyExpression (')') bless => floor
			| ('#') ('mod') ('(') anyExpression (',') anyExpression (')') bless => modulo 
 			


			| ('#') ('fvalue') ('(') anyExpression (',') anyExpression (')') bless => fvalue
			| ('#') ('annuityFactor') ('(') anyExpression (',') anyExpression (')') bless => annuityFactor 
			| ('#') ('presentValueOfAnnuityFactor') ('(') anyExpression (',') anyExpression (')') bless =>  financePVofAnnuityFactor
			| ('#') ('financeFrmRate') ('(') anyExpression (',') anyExpression (',') anyExpression (')') bless => financeFrmRate
			| ('#') ('financeFrmPrincipalPaidAtAge') ('(') anyExpression (',') anyExpression (',') anyExpression (',') anyExpression (')') bless => financeFrmPrincipalPaidAtAge
			| ('#') ('financeFrmDepreciationAtAge') ('(') anyExpression (',') anyExpression (',') anyExpression (',') anyExpression (',') anyExpression (',') anyExpression(')') bless => financeFrmDepreciationAtAge
			| ('#') ('financeFrmInterestPaidAtAge') ('(') anyExpression (',') anyExpression (',') anyExpression (',') anyExpression (')') bless => financeFrmInterestPaidAtAge
			| ('#') ('financeFrmTimeValueFactor') ('(') anyExpression (',') anyExpression (',') anyExpression (')') bless => financeFrmTimeValueFactor
		
			| ('#') ('warn') ('(') stringContentElement (')') bless => userWarning
			| ('#') ('error') ('(') stringContentElement (')') bless => userError
			| ('#') ('report') ('(') stringContentElement (',') anyExpression (')') bless => userReport
		
			| ('#') ('crashNumeric') ('(') stringContentElement (',') stringContentElement (')') bless => userReport
			| ('#') ('crashUndef') ('(') stringContentElement  (')') bless => userReportUndef
			| ('#') ('lengthOfText') ('(') stringContentElement  (')') bless => lengthOfText

			

setFunction ::= ('#') ('sequence') ('(') anyExpression (',') anyExpression (',') anyExpression (')') bless => sequence
				| ('#') ('steps') ('(') anyExpression (',') anyExpression (',') anyExpression (')') bless => sequence
				| ('#') ('union') ('(') unionSetList (')') action => ::first
				| ('#') ('list_concat') ('(') unionSetList (')') action => ::first
				| ('#') ('intersection') ('(') intersectionSetList (')') action => ::first
				| ('#') ('mperiodsThrough') ('(') expressionList (')') bless => mperiodsThrough
				| ('#') ('mperiodsAndAfter') ('(') anyExpression (',') anyExpression (',') anyExpression (')') bless => mperiodsAndAfter
				| ('#') ('fromMaxXYtoZ') ('(') anyExpression (',') anyExpression (',') anyExpression (')') bless => fromMaxXYtoZ
				| ('#') ('fromXtoMinYZ') ('(') anyExpression (',') anyExpression (',') anyExpression (')') bless => fromXtoMinYZ
				| ('#') ('if') ('(') anyExpression (',') set (',') set  (')') bless => if
				| ('#') ('if_elsif') ('(')  conditionThenSetList (')')  action => ::first
				| ('#') ('cartesian_concat') ('(') cartesianConcatList (')') action => ::first
				| ('#') ('cartesian_power_concat') ('(') set (',') anyExpression (')') bless => cartesian_power_concat
				| ('#') ('warn') ('(') stringContentElement (')') bless => userWarning
				| ('#') ('error') ('(') stringContentElement (')') bless => userError


			
				
				
stringFunction ::=  ('#') ('if') ('(') anyExpression (',') stringContentElement (',') stringContentElement  (')') bless => if
				|   ('#') ('if_elsif') ('(') conditionThenStringList  (')')  action => ::first
				| ('#') ('partOfText') ('(') stringContentElement (',') anyExpression (',') anyExpression (')') bless => partOfText
				| ('#') ('report') ('(') stringContentElement (',') stringContentElement (')') bless => userReport
				| ('#') ('list') ('(') set (')') bless => list
				| ('#') ('qlist') ('(') set (')') bless => qlist
				| ('#') ('var') ('(') anyParameter (')') bless => var
				
unionSetList ::= set+ separator => <comma> bless => union
intersectionSetList ::= set+ separator => <comma> bless => intersection
cartesianConcatList ::= set+ separator => <comma> bless => cartesian_concat


conditionThenList ::= conditionThenListElement+ separator => <comma> bless => if_elsif
conditionThenListElement ::= anyExpression (',') anyExpression bless => conditionThenListElement

conditionThenStringList ::= conditionThenStringListElement+ separator => <comma> bless => if_elsif
conditionThenStringListElement ::= anyExpression (',') stringContentElement bless => conditionThenListElement

conditionThenSetList ::= conditionThenSetListElement+ separator => <comma> bless => if_elsif_set
conditionThenSetListElement ::= anyExpression (',') set bless => conditionThenSetListElement


number ~ [\d.]+ 
<comma> ~ ','

BASICFUNCTIONS

my $subsetConditionRule = << 'SUBSETCONDITIONRULE';
subsetCondition ::=	 ('all') iteratorDefinition ('where') anyExpression bless => subset
SUBSETCONDITIONRULE


my $basicStringsAndComments = <<'BASICSTRINGS';

pureString ::= 			 	 double_quoted_string bless => String 
							| empty_string action => ::undef

double_quoted_non_quote	~ [^"]
double_quoted_string	~ ["] double_quoted_body ["]
double_quoted_string	~ ["] ["]
double_quoted_body		~ double_quoted_char_set+
double_quoted_char_set	~ escaped_double_char | escaped_double_quote | double_quoted_non_quote


empty_string			~ ['] [']
empty_string			~ ["] ["]

escaped_double_char		~ '\' double_quoted_non_quote
escaped_double_quote	~ '\"'
#escaped_single_char		~ '\' single_quoted_non_quote
#escaped_single_quote	~ '\' [']
#single_quoted_non_quote	~ [^']
#single_quoted_string	~ ['] single_quoted_body [']
#single_quoted_string	~ ['] [']
#single_quoted_body		~ single_quoted_char_set+
#single_quoted_char_set	~ escaped_single_char | escaped_single_quote | single_quoted_non_quote

:discard ~ <C style comment>
<C style comment> ~ '/*' <comment interior> '*/'
<comment interior> ~
    <optional non stars>
    <optional star prefixed segments>
    <optional pre final stars>
<optional non stars> ~ [^*]*
<optional star prefixed segments> ~ <star prefixed segment>*
<star prefixed segment> ~ <stars> [^/*] <optional star free text>
<stars> ~ [*]+
<optional star free text> ~ [^*]*
<optional pre final stars> ~ [*]*



:discard ~ whitespace
whitespace ~ [\s]+

BASICSTRINGS

MARPA_MPM_RULES:
# eqn files
my $eqnRules = <<'RULEDOC';

:default ::= action => ::array
lexeme default = latm => 1

#Rules
:start ::= eqnFile

eqnFile ::= eqnFileElement* 
eqnFileElement ::=    equationDefinition  action => ::first 
					| sectionDefinition  action => ::first
					| infoDefinition  action => ::first
					| decisionVariableDefinition action => ::first
					| assetDefinition action => ::first
					| equationOrder action => ::first	
					| decisionVariableOrder action => ::first
					| parameterDefinition action => ::first
					| setDefinition action => ::first

equationOrder ::= ('#') ('sort_order_equations') equationOrderList action => ::first
decisionVariableOrder ::= ('#') ('sort_order_decision_variables') decisionVariableOrderList action => ::first

equationOrderList ::= typeName+ separator => <comma> bless => equationOrderDefinition
decisionVariableOrderList ::= typeName+ separator => <comma> bless => decisionVariableOrderDefinition



#Equation defition terms
equationDefinition ::= (equationStarter) eqName iteratorDefinitionRestrictedList constraintAttributeDefinitionList lhs relation rhs bless => equationDefinition


relation ::= <relsign>  bless => relsign 

rhs	::=	  anyExpression bless => RHS 
        | marketSpecificRhs action => ::first 
		|| mpmasInsertExpression bless => RHS 
		| mpmasInsertExpressionWithDefault  bless => RHS
		| mpmasInsertExpressionIf	bless => RHS
		|| mpmasInsertExpressionCompound bless => RHS
		
		
marketSpecificRhs ::=	 ('{') iteratorAtomic ('represents') ('MARKETS') ('}')  anyExpression bless => marketSpecificRHS 


lhs ::=  firstlhsTerm lhsTermList bless => LHS action => mergeFirstLhsTerm
lhsTermList ::= lhsTerm* #bless => lhsTermList



firstlhsTerm ::= <addop>  simpleLhsTerm bless => lhsTerm
			  |	 <addop>  marketSpecificLhsTerm bless => lhsTerm
			  |  <addop>  sumExpression bless => lhsTerm
			  
			  |  simpleLhsTerm bless => lhsTerm action => preponePlus
			  |  sumExpression bless => lhsTerm action => preponePlus
			  |	 marketSpecificLhsTerm bless => lhsTerm action => preponePlus
			  
lhsTerm ::=    <addop>  simpleLhsTerm bless => lhsTerm
			|  <addop>  sumExpression bless => lhsTerm
			|  <addop>  marketSpecificLhsTerm bless => lhsTerm 
simpleLhsTerm ::= 		coefficient decisionVariable bless => simpleLhsTerm	
					|   coefficient decisionVariable <question mark> bless => simpleLhsTerm	
sumExpression ::=  sumFunction simpleLhsTerm bless => sumExpression
				 | sumFunction  ('(') simpleLhsTerm (')') bless => sumExpression
				 | sumFunction marketSpecificLhsTerm bless => sumExpression
				 | sumFunction  ('(') marketSpecificLhsTerm (')') bless => sumExpression
				 | sumFunction sumExpression bless => sumExpression
				 | sumFunction ('(') sumExpression (')') bless => sumExpression
				 

marketSpecificLhsTerm ::=   ('{') iteratorAtomic ('represents') ('MARKETS') ('}') marketSpecificCoefficient decisionVariable bless => marketSpecificLhsTerm	
						|   ('{') iteratorAtomic ('represents') ('MARKETS') ('}') marketSpecificCoefficient decisionVariable <question mark> bless => marketSpecificLhsTerm				


decisionVariable	::=   decName  bless => decVar
						| decName indexed bless => decVarIndexed
						

coefficient ::=  action => replace_by_one bless => number #if nothing explicitly written, implicit 1
coefficient ::=  multiplicativeExpression ('*') action => ::first
			   || multiplicativeMpmasInsertExpression ('*') action => ::first 
				| ('(') mpmasInsertExpression (')') ('*') action => ::first
				| ('(') mpmasInsertExpressionWithDefault (')') ('*') action => ::first
				| ('(') mpmasInsertExpressionIf (')') ('*') action => ::first
				| mpmasInsertExpressionIf  ('*') action => ::first
			   || mpmasInsertExpressionCompoundMultiplicative ('*') action => ::first
				|('(') mpmasInsertExpressionCompound (')') ('*') action => ::first

#no inserters allowed in market-specific coefficients, use a market-specific inserter instead!
#leaving it empty also does not make any sense
marketSpecificCoefficient ::=  multiplicativeExpression ('*') action => ::first



sumFunction ::= ('sum')  iteratorDefinition  action => ::first 

iterator	::=   iteratorAtomic action => ::first  
				| indexedParameter action => ::first
				| anyExpression bless => Expression
				| stringContentElement  action => ::first



indexedDecVarAllowed		::= ('[') iteratorListDecVarAllowed (']')  action => ::first
iteratorListDecVarAllowed ::= iteratorDecVarAllowed* separator => <comma>  bless => index
iteratorDecVarAllowed	::=   iteratorAtomic action => ::first  
							| indexedParameter action => ::first
							| decisionVariable action => ::first
							| assetReferenceId action => ::first
							| anyExpression bless => Expression
							| stringContentElement  action => ::first

anyParameter ::= parameter action => ::first
		| indexedParameter action => ::first
		| assetReferenceNumeric action => ::first
		| tableReference action => ::first

anyParameterNoAssets ::= 	  parameter action => ::first
		| indexedParameter action => ::first
		| tableReference action => ::first


anyExpressionNoAssets ::= 
     number bless => number
   | anyParameterNoAssets action => ::first
   | function action => ::first
   | ('(') anyExpressionNoAssets (')') assoc => group action => ::first
  || anyExpressionNoAssets ('^') anyExpressionNoAssets  assoc => right  bless => exponentiation
  || ('-') anyExpressionNoAssets bless => negation
   | ('!') anyExpressionNoAssets bless => Not
  || anyExpressionNoAssets ('*') anyExpressionNoAssets bless => multiplication
   | anyExpressionNoAssets ('/') anyExpressionNoAssets bless => division
  || anyExpressionNoAssets ('+') anyExpressionNoAssets bless => addition
   | anyExpressionNoAssets ('-') anyExpressionNoAssets bless => subtraction
  || anyExpressionNoAssets ('>=') anyExpressionNoAssets bless => greater_equal
   | anyExpressionNoAssets ('<=') anyExpressionNoAssets bless => less_equal
   | anyExpressionNoAssets ('>') anyExpressionNoAssets bless => greater
   | anyExpressionNoAssets ('<') anyExpressionNoAssets bless => less
  || anyExpressionNoAssets ('==') anyExpressionNoAssets bless => equal
   | anyExpressionNoAssets ('!=') anyExpressionNoAssets bless => not_equal
  || anyExpressionNoAssets ('&&') anyExpressionNoAssets bless => And
   | anyExpressionNoAssets ('||') anyExpressionNoAssets bless => Or


indexedParameter ::= name indexed bless => indexedParameter
parameter ::= name bless => parameter

stringFunctionAssets ::=  ('#') ('if') ('(') anyExpression (',') stringContentElementNoAssets (',') stringContentElementNoAssets  (')') bless => if



#Decision Variable definition
decisionVariableDefinition ::= (dvariableStarter) decName iteratorDefinitionRestrictedList decVarAttributeDefinitionList mpmasReaderList bless => decisionVariableDefinition


#Asset definition
assetDefinition ::= (assetStarter) assetName iteratorDefinitionRestrictedList assetAttributeDefinitionList bless => assetDefinition

assetReferenceNumeric ::=	 assetName (<period>) assetNumericAttributeNameNoMpmas bless => assetReference
					| assetName indexed (<period>) assetNumericAttributeNameNoMpmas bless => indexedAssetReference

assetReferenceString ::=	 assetName (<period>) assetStringAttributeName bless => assetReference
						  | assetName indexed (<period>) assetStringAttributeName bless => indexedAssetReference

assetReferenceId ::= assetName (<period>) 'id' bless => assetReference
						  | assetName indexed (<period>) 'id' bless => indexedAssetReference
					

assetReferenceIdBeforeAssets ::= assetName (<period>) 'id' bless => assetReferenceIdFast
						  | assetName indexed (<period>) 'id' bless => indexedAssetReferenceIdFast

						  
#Attribute definitions
decVarAttributeDefinitionList ::= decVarattributeDefinition* separator => <semicolon> proper => 0 bless => attributeList
decVarattributeDefinition ::= stringAttributeName (<colon>) stringContentElement bless => attribute
decVarattributeDefinition ::= decVarNumericAttributeNameCanMpmas (<colon>) attributeContentWithInsert bless => attribute
decVarattributeDefinition ::= decVarNumericAttributeNameNoMpmas (<colon>) attributeContentNoInsert bless => attribute

constraintAttributeDefinitionList ::= constraintAttributeDefinition* separator => <semicolon> proper => 0 bless => attributeList
constraintAttributeDefinition ::= stringAttributeName (<colon>) stringContentElement bless => attribute
constraintAttributeDefinition ::= constraintNumericAttributeNameNoMpmas (<colon>) attributeContentNoInsert bless => attribute

assetAttributeDefinitionList ::= assetAttributeDefinition* separator => <semicolon> proper => 0 bless => attributeList
assetAttributeDefinition ::= assetStringAttributeName (<colon>) stringContentElementNoAssets bless => attribute
							
assetAttributeDefinition ::= assetNumericAttributeNameNoMpmas (<colon>) attributeContentAssetNoInsert bless => attribute

assetAttributeDefinition ::= assetIndexedAttributeName iteratorDefinitionRestrictedList (<colon>) stringContentElementNoAssets (<thin right arrow>)   attributeContentAssetNoInsert      bless => hashAttribute


attributeContentWithInsert  ::=   mpmasInsertExpression action => ::first
								| mpmasInsertExpressionWithDefault action => ::first
								| mpmasInsertExpressionIf action => ::first
								|| mpmasInsertExpressionCompound action => ::first
								| anyExpression bless => Expression
								
attributeContentNoInsert  ::=    anyExpression bless => Expression
attributeContentAssetNoInsert  ::=    anyExpressionNoAssets bless => Expression
								
								
#stringContent  ::=  stringContentElement+  bless => attributeContentList


stringContentElement ::=      anyExpression bless => Expression
						   || pureString action => ::first
							| assetReferenceString action => ::first
							| assetReferenceId action => ::first
							| decisionVariable action => ::first
							| stringFunction action => ::first
						   || pureString stringContentElement pureString bless => concatenate
						    | stringContentElement pureString stringContentElement bless => concatenate
						    | stringContentElement ('~') stringContentElement bless => concatOp
						    | pureString stringContentElement bless => concatOp
						    
						    | stringContentElement pureString bless => concatOp

stringContentElementNoAssets ::=  anyExpressionNoAssets bless => Expression
						   || pureString action => ::first
							| assetReferenceIdBeforeAssets action => ::first
							| stringFunctionAssets action => ::first
						   || pureString stringContentElementNoAssets pureString bless => concatenate
						    | stringContentElementNoAssets pureString stringContentElementNoAssets bless => concatenate
						    | stringContentElementNoAssets ('~') stringContentElementNoAssets bless => concatOp
						    | pureString stringContentElementNoAssets bless => concatOp
						    
						    | stringContentElementNoAssets pureString bless => concatOp
			



stringAttributeName	 ::=      'description' action => mpmasQlInternalAttributeDescription
							| 'unit' action => ::first
							| 'type' action => ::first		
							| 'labgrp' action => ::first							
							
assetStringAttributeName	 ::=      'description' action => mpmasQlInternalAttributeDescription
							| 'unit' action => ::first
							| 'type' action => ::first							
							| 'innogrp' action => ::first							 
							| 'oname'  action => ::first	
							| 'new_asset_sparked_at_end_of_life' action => ::first
							| 'new_asset_sparked_when_disinvested' action => ::first						 
							
decVarNumericAttributeNameCanMpmas ::=   		  'lbound' action => ::first
							| 'ubound' action => ::first
							| 'objective' action => mpmasQlInternalAttributeObjective						 
							| 'orow' action => mpmasQlInternalAttributeObjective
							| 'mperiod' action => ::first					
	
decVarNumericAttributeNameNoMpmas ::=                     'integer' action => mpmasQlInternalAttributeInteger
							| 'integ' action => mpmasQlInternalAttributeInteger
							| 'priority' action => ::first
							| 'quadratic' action => ::first	
							| 'pseudo_down' action => ::first	
							| 'pseudo_up' action => ::first	

constraintNumericAttributeNameNoMpmas ::=      'mperiod' action => ::first
											|  'range' action => ::first
											
assetNumericAttributeNameNoMpmas ::=   'mperiod' action => ::first
									 | 'div' action => ::first
									 | 'divisible' action => mpmasQlInternalAttributeDivisible
									 | 'acqcost' action => ::first 
									 | 'lifetime' action => ::first
									 | 'terrain' action => ::first
									 | 'mininvest' action => ::first
									 | 'multiplier'  action => ::first
									 | 'innovativeness' action => ::first
									 | 'eqshare' action => ::first
									 | 'irate'  action => ::first
									 | 'landreq'  action => ::first
									 | 'available_until_period' action => ::first
									 | 'sex'  action => ::first
									 | 'inflation_rate_past' action => ::first
									 | 'minimum_age_at_simulation_start' action => ::first
									 | 'maximum_age_at_simulation_start' action => ::first
									 | 'resale_share resale_book_share' action => ::first
									 | 'disinvest_completely' action => ::first
									 | 'plot_capacity_layer' action => ::first
									 | 'plot_capacity_used' action => ::first
									 | 'can_be_attached_to_rented_land' action => ::first
									 | 'compensation_when_returning_with_rented_land' action => ::first
									 | 'resale_topup' action => ::first
									 | 'resale_topup_reduction_per_year_of_age' action => ::first
									 | 'is_livestock' action => ::first
									 | 'internal_accounting' action => ::first

assetIndexedAttributeName	 ::=      'offspring_at_age' action => ::first
									| 'offspring_probability' action => ::first
							

							
multiplicativeExpression ::= 
     number bless => number
   | anyParameter action => ::first
   | function action => ::first
   | ('(') anyExpression (')') assoc => group action => ::first
  || exponentiableExpression ('^') exponentiableExpression assoc => right bless => exponentiation
  || ('-') multiplicativeExpression bless => negation
  || multiplicativeExpression ('*') multiplicativeExpression bless => multiplication
   | multiplicativeExpression ('/') multiplicativeExpression bless => division							

exponentiableExpression ::= 
     number bless => number
   | anyParameter action => ::first
   | function action => ::first
   | ('(') anyExpression (')') assoc => group action => ::first 
  || exponentiableExpression ('^') exponentiableExpression assoc => right bless => exponentiation
						
	


#multiplicativeExpressionForInserter ::= 
#     number bless => number
#   | anyParameter action => ::first
#   | function action => ::first
#   | ('(') anyExpression (')') assoc => group action => ::first
#  || exponentiableExpression ('^') exponentiableExpression assoc => right bless => exponentiation
#  || ('-') multiplicativeExpressionForInserter bless => negation
#  || multiplicativeExpressionForInserter ('*') multiplicativeExpressionForInserter bless => multiplication

singleTermNonInserter ::= 
     number bless => number
   | anyParameter action => ::first
   | function action => ::first
   | ('(') anyExpression (')') assoc => group action => ::first


 exponentialTermNonInserter ::=
    singleTermNonInserter action => ::first
  || exponentialTermNonInserter ('^') exponentialTermNonInserter assoc => right bless => exponentiation

multiplicativeTermNonInserter ::= 
    exponentialTermNonInserter action => ::first
  || ('-') exponentialTermNonInserter bless => negation
  || multiplicativeTermNonInserter ('*') multiplicativeTermNonInserter bless => multiplication

multidivTermNonInserter ::= 
    exponentialTermNonInserter action => ::first
  || ('-') exponentialTermNonInserter bless => negation
  || multidivTermNonInserter ('*') multidivTermNonInserter bless => multiplication
   | multidivTermNonInserter ('/') multidivTermNonInserter bless => division
 						


			
			

							
#Mpmas insert value definitions
		
mpmasInsertExpressionWithDefault ::= 	mpmasInsertExpression ('||') anyExpression bless => OrInserter	
										| ('(') mpmasInsertExpression (')') ('||') anyExpression bless => OrInserter	

mpmasInsertExpressionIf	::=   ('#') ('if') ('(') anyExpression (',') mpmasInsertExpression (',')  mpmasInsertExpression  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') anyExpression (',')  mpmasInsertExpression  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') mpmasInsertExpression (',')  anyExpression  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') mpmasInsertExpressionIf (',')  mpmasInsertExpressionIf  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') mpmasInsertExpressionIf (',')  mpmasInsertExpression  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') mpmasInsertExpression (',')  mpmasInsertExpressionIf  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') mpmasInsertExpressionWithDefault (',')  mpmasInsertExpressionWithDefault  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') anyExpression (',')  mpmasInsertExpressionWithDefault  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') mpmasInsertExpressionWithDefault (',')  anyExpression  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') mpmasInsertExpressionWithDefault (',')  mpmasInsertExpression  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') mpmasInsertExpression (',')  mpmasInsertExpressionWithDefault  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') mpmasInsertExpressionIf (',')  mpmasInsertExpressionWithDefault  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') mpmasInsertExpressionWithDefault (',')  mpmasInsertExpressionIf  (')') bless => ifInserter
						   || ('#') ('if') ('(') anyExpression (',') mpmasInsertExpressionCompound (',')  mpmasInsertExpression  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') mpmasInsertExpression (',')  mpmasInsertExpressionCompound  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') mpmasInsertExpressionCompound (',')  mpmasInsertExpressionIf  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') mpmasInsertExpressionIf (',')  mpmasInsertExpressionCompound  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') mpmasInsertExpressionCompound (',')  mpmasInsertExpressionWithDefault  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') mpmasInsertExpressionWithDefault (',')  mpmasInsertExpressionCompound  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') mpmasInsertExpressionCompound (',')  anyExpression  (')') bless => ifInserter
							| ('#') ('if') ('(') anyExpression (',') anyExpression (',')  mpmasInsertExpressionCompound  (')') bless => ifInserter
						   || ('#') ('if') ('(') anyExpression (',') mpmasInsertExpressionCompound (',')  mpmasInsertExpressionCompound  (')') bless => ifInserter
							

mpmasInsertExpressionSingleTerm ::=
		  pureMpmasInsertExpression action => ::first
	|   ('(') mpmasInsertExpression (')') action => ::first
	



mpmasInsertExpressionCompoundMultiplicative ::= 	
				mpmasInsertExpressionSingleTerm action => ::first
				 |  ('(') mpmasInsertExpressionCompound (')') assoc => group action => ::first
				|| mpmasInsertExpressionSingleTerm	'^' mpmasInsertExpressionSingleTerm  assoc => right   bless => mpmasInsertExpressionCompound
				 | singleTermNonInserter	'^' mpmasInsertExpressionSingleTerm  assoc => right   bless => mpmasInsertExpressionCompound
				 | mpmasInsertExpressionSingleTerm	'^' exponentialTermNonInserter  assoc => right   bless => mpmasInsertExpressionCompound
				 | mpmasInsertExpressionCompound	'^' exponentialTermNonInserter  assoc => right   bless => mpmasInsertExpressionCompound
				 | singleTermNonInserter	'^' mpmasInsertExpressionCompound  assoc => right   bless => mpmasInsertExpressionCompound
				 | mpmasInsertExpressionCompound	'^' mpmasInsertExpressionCompound  assoc => right   bless => mpmasInsertExpressionCompound	
				 
				|| mpmasInsertExpressionSingleTerm	'*' mpmasInsertExpressionSingleTerm    bless => mpmasInsertExpressionCompound
				 | multidivTermNonInserter	'*' mpmasInsertExpressionSingleTerm    bless => mpmasInsertExpressionCompound
				 | mpmasInsertExpressionSingleTerm	'*' multiplicativeTermNonInserter     bless => mpmasInsertExpressionCompound 
				 | mpmasInsertExpressionSingleTerm	'/' mpmasInsertExpressionSingleTerm     bless => mpmasInsertExpressionCompound
				 | multidivTermNonInserter	'/' mpmasInsertExpressionSingleTerm    bless => mpmasInsertExpressionCompound
				 | mpmasInsertExpressionSingleTerm	'/' exponentialTermNonInserter     bless => mpmasInsertExpressionCompound 

				 | mpmasInsertExpressionCompound	'*' multiplicativeTermNonInserter     bless => mpmasInsertExpressionCompound
				 | multidivTermNonInserter	'*' mpmasInsertExpressionCompound     bless => mpmasInsertExpressionCompound
				 | mpmasInsertExpressionCompound	'/' exponentialTermNonInserter     bless => mpmasInsertExpressionCompound
				 | multidivTermNonInserter	'/' mpmasInsertExpressionCompound    bless => mpmasInsertExpressionCompound

				 | mpmasInsertExpressionCompound	'*' mpmasInsertExpressionCompound  bless => mpmasInsertExpressionCompound	
				 | mpmasInsertExpressionCompound	'/' mpmasInsertExpressionCompound  bless => mpmasInsertExpressionCompound	






mpmasInsertExpressionCompound ::= mpmasInsertExpressionSingleTerm action => ::first
				  | ('(') mpmasInsertExpressionCompound (')') assoc => group action => ::first
				|| mpmasInsertExpressionSingleTerm	'^' mpmasInsertExpressionSingleTerm  assoc => right   bless => mpmasInsertExpressionCompound
				 | singleTermNonInserter	'^' mpmasInsertExpressionSingleTerm  assoc => right   bless => mpmasInsertExpressionCompound
				 | mpmasInsertExpressionSingleTerm	'^' exponentialTermNonInserter  assoc => right   bless => mpmasInsertExpressionCompound
				 | mpmasInsertExpressionCompound	'^' exponentialTermNonInserter  assoc => right   bless => mpmasInsertExpressionCompound
				 | singleTermNonInserter	'^' mpmasInsertExpressionCompound  assoc => right   bless => mpmasInsertExpressionCompound
				 | mpmasInsertExpressionCompound	'^' mpmasInsertExpressionCompound  assoc => right   bless => mpmasInsertExpressionCompound	
				 
				|| mpmasInsertExpressionSingleTerm	'*' mpmasInsertExpressionSingleTerm    bless => mpmasInsertExpressionCompound
				 | multidivTermNonInserter	'*' mpmasInsertExpressionSingleTerm    bless => mpmasInsertExpressionCompound
				 | mpmasInsertExpressionSingleTerm	'*' multiplicativeTermNonInserter     bless => mpmasInsertExpressionCompound 
				 | mpmasInsertExpressionSingleTerm	'/' mpmasInsertExpressionSingleTerm     bless => mpmasInsertExpressionCompound
				 | multidivTermNonInserter	'/' mpmasInsertExpressionSingleTerm    bless => mpmasInsertExpressionCompound
				 | mpmasInsertExpressionSingleTerm	'/' exponentialTermNonInserter     bless => mpmasInsertExpressionCompound 

				 | mpmasInsertExpressionCompound	'*' multiplicativeTermNonInserter     bless => mpmasInsertExpressionCompound
				 | multidivTermNonInserter	'*' mpmasInsertExpressionCompound     bless => mpmasInsertExpressionCompound
				 | mpmasInsertExpressionCompound	'/' exponentialTermNonInserter     bless => mpmasInsertExpressionCompound
				 | multidivTermNonInserter	'/' mpmasInsertExpressionCompound    bless => mpmasInsertExpressionCompound

				 | mpmasInsertExpressionCompound	'*' mpmasInsertExpressionCompound  bless => mpmasInsertExpressionCompound	
				 | mpmasInsertExpressionCompound	'/' mpmasInsertExpressionCompound  bless => mpmasInsertExpressionCompound	


				|| mpmasInsertExpressionSingleTerm	'+' mpmasInsertExpressionSingleTerm    bless => mpmasInsertExpressionCompound
				 | anyExpression	'+' mpmasInsertExpressionSingleTerm    bless => mpmasInsertExpressionCompound
				 | mpmasInsertExpressionSingleTerm	'+' anyExpression     bless => mpmasInsertExpressionCompound 
				 | mpmasInsertExpressionSingleTerm	'-' mpmasInsertExpressionSingleTerm     bless => mpmasInsertExpressionCompound
				 | anyExpression	'-' mpmasInsertExpressionSingleTerm    bless => mpmasInsertExpressionCompound
				 | mpmasInsertExpressionSingleTerm	'-' multidivTermNonInserter     bless => mpmasInsertExpressionCompound 

				 | mpmasInsertExpressionCompound	'+' anyExpression     bless => mpmasInsertExpressionCompound
				 | anyExpression			'+' mpmasInsertExpressionCompound     bless => mpmasInsertExpressionCompound
				 | mpmasInsertExpressionCompound	'-' multidivTermNonInserter     bless => mpmasInsertExpressionCompound
				 | anyExpression			'-' mpmasInsertExpressionCompound    bless => mpmasInsertExpressionCompound

				 | mpmasInsertExpressionCompound	'+' mpmasInsertExpressionCompound  bless => mpmasInsertExpressionCompound	
				 | mpmasInsertExpressionCompound	'-' mpmasInsertExpressionCompound  bless => mpmasInsertExpressionCompound	

				 
				 
				 

		
mpmasInsertExpression ::= 	multiplicativeExpression ('*') mpmasInsertSimple bless => mpmasInsertExpression action => mpmasInsertSortMI
						  | multiplicativeExpression ('*') mpmasInsertIndexed bless => mpmasInsertExpression action => mpmasInsertSortMI
						  |	multiplicativeExpression ('*') mpmasInsertSimple ('+') anyExpression bless => mpmasInsertExpression action => mpmasInsertSortMIA
						  | multiplicativeExpression ('*') mpmasInsertIndexed ('+') anyExpression bless => mpmasInsertExpression action => mpmasInsertSortMIA
						  |	anyExpression ('+') multiplicativeExpression ('*') mpmasInsertSimple bless => mpmasInsertExpression action => mpmasInsertSortAMI
						  | anyExpression ('+') multiplicativeExpression ('*') mpmasInsertIndexed bless => mpmasInsertExpression action => mpmasInsertSortAMI
						  |	anyExpression ('+')  mpmasInsertSimple  bless => mpmasInsertExpression action => mpmasInsertSortAI
						  | anyExpression ('+')  mpmasInsertIndexed bless => mpmasInsertExpression action => mpmasInsertSortAI
						  | mpmasInsertSimple ('*') multiplicativeExpression bless => mpmasInsertExpression action => mpmasInsertSortIM
						  | mpmasInsertIndexed ('*') multiplicativeExpression bless => mpmasInsertExpression action => mpmasInsertSortIM
						  | mpmasInsertSimple ('*') multiplicativeExpression  ('+') anyExpression bless => mpmasInsertExpression 
						  | mpmasInsertIndexed ('*') multiplicativeExpression  ('+') anyExpression bless => mpmasInsertExpression 
						  |	anyExpression ('+')  mpmasInsertSimple  ('*') multiplicativeExpression bless => mpmasInsertExpression action => mpmasInsertSortAIM
						  | anyExpression ('+')  mpmasInsertIndexed ('*') multiplicativeExpression bless => mpmasInsertExpression action => mpmasInsertSortAIM
						  |	mpmasInsertSimple  ('+') anyExpression bless => mpmasInsertExpression action => mpmasInsertSortIA
						  | mpmasInsertIndexed  ('+') anyExpression bless => mpmasInsertExpression action => mpmasInsertSortIA
						  |	mpmasInsertSimple   bless => mpmasInsertExpression action => mpmasInsertSortI
						  | mpmasInsertIndexed   bless => mpmasInsertExpression action => mpmasInsertSortI


multiplicativeMpmasInsertExpression ::= 	multiplicativeExpression ('*') mpmasInsertSimple bless => mpmasInsertExpression action => mpmasInsertSortMI
						  | multiplicativeExpression ('*') mpmasInsertIndexed bless => mpmasInsertExpression action => mpmasInsertSortMI
						  | mpmasInsertSimple ('*') multiplicativeExpression  bless => mpmasInsertExpression action => mpmasInsertSortIM
						  | mpmasInsertIndexed ('*') multiplicativeExpression  bless => mpmasInsertExpression action => mpmasInsertSortIM
						  |	mpmasInsertSimple   bless => mpmasInsertExpression action => mpmasInsertSortI
						  | mpmasInsertIndexed   bless => mpmasInsertExpression action => mpmasInsertSortI
	
pureMpmasInsertExpression ::= 
						  	mpmasInsertSimple   bless => mpmasInsertExpression action => mpmasInsertSortI
						  | mpmasInsertIndexed   bless => mpmasInsertExpression action => mpmasInsertSortI	
	
	
mpmasInsertSimple ::= mpmasInsertMain ('.') mpmasInsertSubcatList bless => mpmasInserter action => mpmasInsertJoinName
mpmasInsertIndexed ::= mpmasInsertMain ('.') mpmasInsertSubcatList indexedDecVarAllowed bless => mpmasInserterIndexed action => mpmasInsertJoinName
mpmasInsertMain ::=   'agent'	action => ::first
					| 'markets' action => ::first
					| 'time' action => ::first
					| 'simulationRun' action => ::first
					
mpmasInsertSubcatList ::=  name* separator => <period>  							
							
				
#Mpmas read value definitions

mpmasReaderList ::= mpmasReaderDefinition* separator => <semicolon> proper => 0 bless => mpmasReaderList
mpmasReaderDefinition ::= whatToRead whenToRead (<right arrow>) mpmasReader furtherArguments bless => mpmasReaderDefinition							
whatToRead ::=   'solution' action => ::first
			   | 'value' action => mpmasQlInternalReaderProduct

whenToRead	::= 						action => ::undef
whenToRead	::= ('at') anyExpression	action => ::first

furtherArguments	::= 						action => ::undef
furtherArguments    ::= ('(') expressionList (')') action => ::first



mpmasReader ::= mpmasReaderSimple action => ::first | mpmasReaderIndexed action => ::first
mpmasReaderSimple ::= mpmasReaderMain ('.') mpmasReaderSubcatList bless => mpmasReader action => mpmasInsertJoinName
mpmasReaderIndexed ::= mpmasReaderMain ('.') mpmasReaderSubcatList indexedDecVarAllowed bless => mpmasReaderIndexed action => mpmasInsertJoinName
mpmasReaderMain ::=   'agent'	action => ::first		
mpmasReaderSubcatList ::=  name* separator => <period>  


iteratorDefinitionRestrictedList ::=  iteratorDefinitionRestricted* bless => iteratorDefinitionRestrictedList
iteratorDefinitionRestricted ::= ('{') iteratorAtomic ('in') set ('}') bless => iteratorDefinitionRestricted
							
#Lexemes:


equationStarter ~ <hash> 'equation'
dvariableStarter ~ <hash> 'decision_variable'
assetStarter ~ <hash> 'asset'

decName ~ <the letter x> <one or more word characters>
assetName ~ <one or more word characters>
eqName ~ <one or more word characters>
typeName ~ <one or more word characters>
<the letter x> ~ 'x'
<period> ~ '.'
addop ~ '+' | '-' 
<right arrow> ~ '=>'
<thin right arrow> ~ '->'
<question mark> ~ '?'


<relsign> ~ '==' | '>=' | '<='
<colon> ~ ':'
<semicolon> ~ ';'


RULEDOC

MARPA_PRM_RULES:
# prm files
my $prmShrdRules = <<'PRMSHRDRULES'; 


parameterDefinition ::= (parameterStarter) name iteratorDefinitionList ('=') anyExpression bless => parameterDefinition 
					   | (parameterStarter) name iteratorDefinitionList ('=') stringContentElement bless => parameterDefinition 
					   
setDefinition ::= (setStarter) name iteratorDefinitionList ('=') set bless => setDefinition 

iteratorDefinitionList ::=  iteratorDefinition* bless => iteratorDefinitionList

parameterStarter ~ <hash> 'parameter'
setStarter ~ <hash> 'set'

PRMSHRDRULES

$eqnRules .= $shrdRules. $prmShrdRules . $basicExpressionssAndSets . $subsetConditionRule.$basicStringsAndComments. $infoRules;



MARPA_PRM_RULES:
# prm files
my $prmRules = <<'PRMRULES'; 



:default ::= action => ::array
lexeme default = latm => 1

#Rules
:start ::= prmFile

prmFile ::= prmFileElement* 
prmFileElement ::=   sectionDefinition  action => ::first
					| infoDefinition  action => ::first
					| parameterDefinition action => ::first
					| setDefinition action => ::first
					

# now in PrmShrdRules:
#parameterDefinition ::= (parameterStarter) name iteratorDefinitionList ('=') anyExpression bless => parameterDefinition 
#					   | (parameterStarter) name iteratorDefinitionList ('=') stringContentElement bless => parameterDefinition 
#					   
#setDefinition ::= (setStarter) name iteratorDefinitionList ('=') set bless => setDefinition 
#
	    

stringContentElement ::=     anyExpression bless => Expression
						    | pureString action => ::first
							| stringFunction action => ::first
						   || pureString stringContentElement pureString bless => concatenate
						    | stringContentElement pureString stringContentElement bless => concatenate
							| stringContentElement pureString bless => concatOp
						    | pureString stringContentElement bless => concatOp
						    | stringContentElement ('~') stringContentElement bless => concatOp

iterator	::=   iteratorAtomic action => ::first  
				| indexedParameter action => ::first
				| anyExpression bless => Expression
				| stringContentElement  action => ::first


anyParameter ::= parameter action => ::first
				| indexedParameter action => ::first
				| tableReference action => ::first
				
indexedParameter ::= name indexed bless => indexedParameter
parameter ::= name bless => parameter

#parameterStarter ~ <hash> 'parameter'   # Now in PrmShrdRules
#setStarter ~ <hash> 'set'		 # now in PrmShrdRules

PRMRULES

$prmRules .= $prmShrdRules. $shrdRules . $basicExpressionssAndSets . $subsetConditionRule. $basicStringsAndComments. $infoRules;


MARPA_DAT_RULES:
my $dataRules = <<'DATARULES'; 

:default ::= action => ::array
lexeme default = latm => 1

#Rules
:start ::= dataFile

dataFile ::= dataFileElement* 
dataFileElement ::=   sectionDefinition  action => ::first
					| infoDefinition  action => ::first
					| globalDefinition action => ::first
					| globalSetDefinition action => ::first
					| tableDefinition action  => ::first
					| simrunParameterDefinition action => ::first

globalDefinition ::= (globalStarter) globalName  ('=') anyExpression bless => globalDefinition 
		   | (globalStarter) globalName  ('=') stringContentElement bless => globalDefinition 

simrunParameterDefinition ::= (simrunParameterStarter) globalName  ('=') anyExpression bless => simrunParameterDefinition 
			   || (simrunParameterStarter) globalName  iteratorDefinitionRestrictedList ('=') anyExpression bless => simrunParameterDefinitionIndexed 
					   
globalSetDefinition ::= (listStarter) name ('=') set bless => globalSetDefinition 

	    

stringContentElement ::=     anyExpression bless => Expression
			    | pureString action => ::first
				| stringFunction action => ::first
			   || pureString stringContentElement pureString bless => concatenate
			    | stringContentElement pureString stringContentElement bless => concatenate
				| stringContentElement pureString bless => concatOp
			    | pureString stringContentElement bless => concatOp
			    | stringContentElement ('~') stringContentElement bless => concatOp

tableDefinition ::= (tableStarter) name ('=') ('(') tableformat (',') integer  (')') ('{') stringContentElement  ('}')  bless => tableDefinition
tableDefinition ::= (tableStarter) name ('=') ('(') tableformat (',') integer  (')')  stringContentElement  bless => tableDefinition
tableDefinition ::= (tableStarter) name  ('(') tableformat (',') integer  (')') ('{') stringContentElement  ('}')  bless => tableDefinition
tableDefinition ::= (tableStarter) name  ('(') tableformat (',') integer  (')')  stringContentElement  bless => tableDefinition


#set ::= name bless => set #shrdRules
#		| ('{') expressionListStringsAllowed ('}') action => ::first
#		| setFunction action => ::first
#		| set ('except') set bless => setDifference
#		| subsetCondition action => ::first
#		| tableSetReference action => ::first
#		| ('{') ('}') bless => emptySet
 
#iteratorDefinitionList ::=  iteratorDefinition* bless => iteratorDefinitionList #shrdRules
#iteratorDefinition ::= ('{') iteratorAtomic ('in') set ('}') bless => iteratorDefinition #shrdRules

iteratorDefinitionRestrictedList ::=  iteratorDefinitionRestricted* bless => iteratorDefinitionRestrictedList
iteratorDefinitionRestricted ::= ('{') iteratorAtomic ('in') set ('}') bless => iteratorDefinitionRestricted

iterator	::=   iteratorAtomic action => ::first  
			| globalParameter action => ::first
			| anyExpression bless => Expression
			| stringContentElement  action => ::first

#iteratorAtomic ::= name bless => iterator  #shrdRules

anyParameter ::= globalParameter action => ::first
		| iteratorAtomic action => ::first
		| tableReference action => ::first
				
globalParameter ::= globalName bless => globalParameter				
globalName ~ <any letter that is not x> <zero or more word characters> 
				
integer ~ [0-9]+
tableformat ~  'here' | 'ascii' | 'sql' | 'sparql' | 'spreadsheet' |  'swapped_keys' | 'merge' |'recombine'

tableStarter ~ <hash> 'table'
globalStarter ~ <hash> 'global'
listStarter ~ <hash> 'global_set'
simrunParameterStarter ~ <hash> 'simulationRun_parameter'

name ~ <any letter> <zero or more word characters>



<any letter> ~ [a-zA-Z]			
#<any letter that is not x> ~ [a-wyzA-Z]        #shrdRules
#<zero or more word characters> ~ [\w]*         #shrdRules
#<one or more word characters> ~ [\w]+          #shrdRules



DATARULES

$dataRules .= $shrdRules. $basicExpressionssAndSets . $subsetConditionRule. $basicStringsAndComments. $infoRules;

MARPA_MAS_RULES:
my $masRules = <<'MASRULES'; 

:default ::= action => ::array
lexeme default = latm => 1

#Rules
:start ::= dataFile

dataFile ::= dataFileElement* 
dataFileElement ::=   mpmasParameterDefinition action => ::first
					| mpmasTableDefinitionIterated   action => ::first
					| mpmasTableDefinition  action => ::first
					| ('[') iniSectionHeader (']') action => ::first


iniSectionHeader ::=  headerName+  bless => iniSectionHeader


mpmasParameterDefinition ::=    mpmasParameterName  ('=') anyExpression bless => configEntryDefinition 
					        |   mpmasParameterName  ('=') stringContentElement bless => configEntryDefinition 
			   


mpmasTableDefinition ::=  mpmasTableName ('=') ('(') tableformat   (')') ('{') stringContentElement  ('}') bless => mpmasTableDefinition
mpmasTableDefinition ::=  mpmasTableName ('=') ('(') tableformat   (')')  stringContentElement  bless => mpmasTableDefinition

mpmasTableDefinition ::=  mpmasTableName ('(') tableformat   (')') ('{') stringContentElement  ('}') bless => mpmasTableDefinition
mpmasTableDefinition ::=  mpmasTableName ('(') tableformat   (')')  stringContentElement  bless => mpmasTableDefinition


mpmasTableDefinitionIterated ::=  mpmasTableNameIterated iteratorDefinitionList ('=') ('(') tableformat   (')') ('{') stringContentElement  ('}') bless => mpmasTableDefinitionIterated
mpmasTableDefinitionIterated ::=  mpmasTableNameIterated iteratorDefinitionList ('=') ('(') tableformat   (')')  stringContentElement  bless => mpmasTableDefinitionIterated

mpmasTableDefinitionIterated ::=  mpmasTableNameIterated iteratorDefinitionList ('(') tableformat   (')') ('{') stringContentElement  ('}') bless => mpmasTableDefinitionIterated
mpmasTableDefinitionIterated ::=  mpmasTableNameIterated iteratorDefinitionList ('(') tableformat   (')')  stringContentElement  bless => mpmasTableDefinitionIterated

	    	    

stringContentElement ::=     anyExpression bless => Expression
						    | pureString action => ::first
							| stringFunction action => ::first
						   || pureString stringContentElement pureString bless => concatenate
						    | stringContentElement pureString stringContentElement bless => concatenate
							| stringContentElement pureString bless => concatOp
						    | pureString stringContentElement bless => concatOp
						    | stringContentElement ('~') stringContentElement bless => concatOp
						    
anyParameter ::= globalParameter action => ::first
				 | mpmasParameterName action => ::first
				 | iteratorAtomic action => ::first
globalParameter ::= globalName bless => globalParameter		
				| tableReference action => ::first
globalName ~ <any letter> <zero or more word characters>

set ::= name bless => set
		| ('{') expressionListStringsAllowed ('}') action => ::first
		| setFunction action => ::first
		| tableSetReference action => ::first
		| set ('except') set bless => setDifference
		| subsetCondition action => ::first
							

tableReference ::= columnName ('@') tableName indexed bless => tableReference
tableSetReference ::= columnName ('@') tableName indexed bless => tableSetReference				
   
iteratorDefinitionList ::=  iteratorDefinition+ bless => iteratorDefinitionList
iteratorDefinition ::= ('{') iteratorAtomic ('in') set ('}') bless => iteratorDefinition


indexed		::= ('[') iteratorList (']')  action => ::first
iteratorList ::= iterator* separator => <comma>  bless => index

#stringContent2  ::= stringContentElement+  bless => stringContentList

iterator	::=   iteratorAtomic action => ::first  
				| anyExpression bless => Expression
				| stringContentElement  action => ::first
				
iteratorAtomic ::= name bless => iterator 
				

#Lexemes:
headerName ~ <one or more word characters>
tableName ~ <one or more word characters>
columnName ~ <one or more word characters>
name ~ <any letter that is not x> <zero or more word characters> 

<any letter> ~ [a-zA-Z]
<any letter that is not x> ~ [a-wyzA-Z]
<zero or more word characters> ~ [\w]*
<one or more word characters> ~ [\w]+


				
#mpmasTableName ~ 'PRICES' | 'ASSET_ENDOWMENTS' | 'HOUSEHOLD_DYNAMICS' | 'HOUSEHOLD_MEMBERS' | 'HOUSEHOLD_MEMBER_TYPES'
#mpmasParameterName ~ 'INTEREST_SHDEP' 

#mpmasTableNameIterated ~ 'PRICES' | 'INITIAL_PRICE_EXPECTATIONS'
		
tableformat ~  'here' | 'ascii' | 'sql' | 'sparql' | 'spreadsheet' | 'swapped_keys' | 'merge'|'recombine'



MASRULES

$masRules .= $basicExpressionssAndSets . $subsetConditionRule. $basicStringsAndComments;

#Importing valid names for mpmas parameters and tables from MpmasQLRegistry.pm
$masRules .= "mpmasTableName ~ '" . join("' | '", keys %MpmasQLRegistry::mpmas_tables)."'\n";
$masRules .= "mpmasParameterName ~ '" . join("' | '", keys %MpmasQLRegistry::mpmas_parameters)."'\n";
$masRules .= "mpmasTableNameIterated ~ '" . join("' | '", map {  substr( $_, 1, -1)   } keys %MpmasQLRegistry::mpmas_simrun_variation)."'\n"; #Note substr to remove underscores at both sides

MARPA_CFG_RULES:
my $cfgRules = <<'CFGRULES'; 

:default ::= action => ::array
lexeme default = latm => 1

#Rules
:start ::= cfgFile

cfgFile ::= cfgFileElement* 
cfgFileElement ::=   ('[') iniSectionHeader (']') action => ::first
					| cfgentryDefinition action => ::first
					| cfgentrySetDefinition action => ::first
					
iniSectionHeader ::=  headerName+  bless => iniSectionHeader


cfgentryDefinition ::=    cfgEntryName  ('=') anyExpression bless => configEntryDefinition 
					   |  cfgEntryName  ('=') stringContentElement bless => configEntryDefinition 
			   
cfgentrySetDefinition ::=  cfgSetName ('=') set bless => configListDefinition 

	    

stringContentElement ::=     anyExpression bless => Expression
						    | pureString action => ::first
							| stringFunction action => ::first
						   || pureString stringContentElement pureString bless => concatenate
						    | stringContentElement pureString stringContentElement bless => concatenate
							| stringContentElement pureString bless => concatOp
						    | pureString stringContentElement bless => concatOp
						    | stringContentElement ('~') stringContentElement bless => concatOp

anyParameter ::= globalParameter action => ::first
				 | tableReference  action => ::first
globalParameter ::= globalName bless => globalParameter				
globalName ~ <any letter> <zero or more word characters>
				

set ::= name bless => set
		| ('{') expressionListStringsAllowed ('}') action => ::first
		| setFunction action => ::first
		| tableSetReference action => ::first
		| set ('except') set bless => setDifference
		| subsetCondition action => ::first
							

tableReference ::= columnName ('@') tableName indexed bless => tableReference
tableSetReference ::= columnName ('@') tableName indexed bless => tableSetReference				
   

iteratorDefinition ::= ('{') iteratorAtomic ('in') set ('}') bless => iteratorDefinition



indexed		::= ('[') iteratorList (']')  action => ::first
iteratorList ::= iterator* separator => <comma>  bless => index

#stringContent2  ::= stringContentElement+  bless => stringContentList

iterator	::=   iteratorAtomic action => ::first  
				| anyExpression bless => Expression
				| stringContentElement  action => ::first
				
iteratorAtomic ::= name bless => iterator 
				

#Lexemes:
headerName ~ <one or more word characters>				
tableName ~ <one or more word characters>
columnName ~ <one or more word characters>
name ~ <any letter that is not x> <zero or more word characters> 

<any letter> ~ [a-zA-Z]
<any letter that is not x> ~ [a-wyzA-WYZ]
<zero or more word characters> ~ [\w]*
<one or more word characters> ~ [\w]+

#cfgEntryName ~ 'MULTIPERIOD' | 'NSOIL'
#cfgSetName ~ 'HHNUTRIENTS' | 'THRESHOLDS' | 'EXTRA_HHMEMBER_CHARACTERISTICS'

CFGRULES

$cfgRules .= $basicStringsAndComments. $subsetConditionRule . $basicExpressionssAndSets;

$cfgRules .= "cfgEntryName ~ '" . join("' | '", keys %MpmasQLRegistry::cfg_entries)."'\n";
$cfgRules .= "cfgSetName ~ '" . join("' | '", keys %MpmasQLRegistry::cfg_lists)."'\n";

MARPA_INI_RULES:
my $iniRules = <<'INIRULES'; 

:default ::= action => ::array
lexeme default = latm => 1

#Rules
:start ::= iniFile

iniFile ::= iniFileElement* 
iniFileElement ::=   ('[') iniSectionHeader (']') action => ::first
					| iniEntryDefinition action => ::first
					| iniTableDefinition action => ::first
					| iniSetDefinition	action => ::first

iniEntryDefinition ::=    name  ('=') anyExpression bless => iniEntryDefinition 
					   |  name  ('=') stringContentElement bless => iniEntryDefinition 
	   
	   
iniSetDefinition ::=    iniSetName  ('=') set bless => iniSetDefinition 

iniTableDefinition ::=  iniTableName ('=') ('(') tableformat (')') ('{') stringContentElement  ('}') bless => iniTableDefinition
iniTableDefinition ::=  iniTableName ('=') ('(') tableformat   (')')  stringContentElement  bless => iniTableDefinition
iniTableDefinition ::=  iniTableName ('=') ('(') 'set'   (')')  set bless => iniTableDefinition
iniTableDefinition ::=  iniTableName ('=') ('(') 'list'   (')') ('{') ('[') barewordList (']') ('}') bless => iniTableDefinition



iniTableDefinition ::=  iniTableName ('(') tableformat   (')') ('{') stringContentElement  ('}') bless => iniTableDefinition
iniTableDefinition ::=  iniTableName ('(') tableformat   (')')  stringContentElement  bless => iniTableDefinition
iniTableDefinition ::=  iniTableName ('(') 'set'   (')')  set bless => iniTableDefinition
iniTableDefinition ::=  iniTableName ('(') 'list'   (')') ('{') ('[') barewordList (']') ('}') bless => iniTableDefinition




stringContentElement ::=     anyExpression bless => Expression
						    | pureString action => ::first
							| stringFunction action => ::first
						   || pureString stringContentElement pureString bless => concatenate
						    | stringContentElement pureString stringContentElement bless => concatenate
							| stringContentElement pureString bless => concatOp
						    | pureString stringContentElement bless => concatOp
						    | stringContentElement ('~') stringContentElement bless => concatOp

barewordList ::= scenarioName+ bless => barewordList

anyParameter ::= iniParameter action => ::first

iniParameter ::= name bless => iniParameter				
		
#iniTableName ~ 'SCENDEF' | 'SCENLIST' | 'RHSLIST'  | 'RHSDEF' | 'RHS_SOILTAB' | 'COMMON' | 'PARAMETER_SCENDEF' | 'PARAMETER_SCENLIST' 


				
iniSetName ~ 			'DBGMILPS' | 'USE_ONLY_AGENTS' | 'SKIP_AGENTS'
				 

set ::=  ('{') expressionListStringsAllowed ('}') action => ::first
		| setFunction action => ::first
		
iniSectionHeader ::=  headerName+  bless => iniSectionHeader
			
				

#Lexemes:
headerName ~ <one or more word characters>				

scenarioName ~ <one or more word characters>
name ~ <any letter> <zero or more word characters>

tableformat ::= 'here'  action => ::first
				| 'ascii'  action => ::first
				| 'sql'  action => ::first
				| 'sparql'  action => ::first
				| 'transform_assets'  action => ::first
				| 'spreadsheet'  action => ::first


<any letter> ~ [a-zA-Z]
<zero or more word characters> ~ [\w]*
<one or more word characters> ~ [\w]+

INIRULES

$iniRules .= $basicStringsAndComments . $basicExpressionssAndSets;
$iniRules .= "iniTableName ~ '" . join("' | '", keys %{$MpmasQl3EqnElements::iniTableDefinition::keys_of_INI_tables})."'\n";

MARPA_SCENARIO_RULES:
my $scenarioValueRules = <<'SCENARIORULES';
:start ::= valueDefinition

valueDefinition ::=   anyExpression  action => ::first
					| stringContentElement action => ::first

stringContentElement ::=     anyExpression bless => Expression
						    | pureString action => ::first
							| stringFunction action => ::first
						   || pureString stringContentElement pureString bless => concatenate
						    | stringContentElement pureString stringContentElement bless => concatenate
							| stringContentElement pureString bless => concatOp
						    | pureString stringContentElement bless => concatOp
						    | stringContentElement ('~') stringContentElement bless => concatOp

anyParameter ::= globalParameter action => ::first
				 | tableReference  action => ::first
globalParameter ::= globalName bless => globalParameter				
globalName ~ <any letter> <zero or more word characters>
				

set ::= name bless => set
		| ('{') expressionListStringsAllowed ('}') action => ::first
		| setFunction action => ::first
		| tableSetReference action => ::first
		| set ('except') set bless => setDifference
		| subsetCondition action => ::first
							

tableReference ::= columnName ('@') tableName indexed bless => tableReference
tableSetReference ::= columnName ('@') tableName indexed bless => tableSetReference		


iteratorDefinition ::= ('{') iteratorAtomic ('in') set ('}') bless => iteratorDefinition


indexed		::= ('[') iteratorList (']')  action => ::first
iteratorList ::= iterator* separator => <comma>  bless => index

#stringContent2  ::= stringContentElement+  bless => stringContentList

iterator	::=   iteratorAtomic action => ::first  
				| anyExpression bless => Expression
				| stringContentElement  action => ::first
				
iteratorAtomic ::= name bless => iterator 
				

#Lexemes:
tableName ~ <one or more word characters>
columnName ~ <one or more word characters>
name ~ <any letter that is not x> <zero or more word characters> 

<any letter> ~ [a-zA-Z]
<any letter that is not x> ~ [a-wyzA-WYZ]
<zero or more word characters> ~ [\w]*
<one or more word characters> ~ [\w]+


SCENARIORULES


$scenarioValueRules .= $basicExpressionssAndSets . $subsetConditionRule. $basicStringsAndComments;

my $scenarioSetRules = <<'SCENARIOSETRULES';
:start ::= valueDefinition

valueDefinition ::=   set action => ::first

set ::= name bless => set
		| ('{') expressionListStringsAllowed ('}') action => ::first
		| setFunction action => ::first
		| tableSetReference action => ::first
		| set ('except') set bless => setDifference
		| subsetCondition action => ::first

stringContentElement ::=     anyExpression bless => Expression
						    | pureString action => ::first
							| stringFunction action => ::first
						   || pureString stringContentElement pureString bless => concatenate
						    | stringContentElement pureString stringContentElement bless => concatenate
							| stringContentElement pureString bless => concatOp
						    | pureString stringContentElement bless => concatOp
						    | stringContentElement ('~') stringContentElement bless => concatOp

anyParameter ::= globalParameter action => ::first
				 | tableReference  action => ::first
globalParameter ::= globalName bless => globalParameter				
globalName ~ <any letter> <zero or more word characters>
				
tableReference ::= columnName ('@') tableName indexed bless => tableReference
tableSetReference ::= columnName ('@') tableName indexed bless => tableSetReference		


iteratorDefinition ::= ('{') iteratorAtomic ('in') set ('}') bless => iteratorDefinition


indexed		::= ('[') iteratorList (']')  action => ::first
iteratorList ::= iterator* separator => <comma>  bless => index

#stringContent2  ::= stringContentElement+  bless => stringContentList

iterator	::=   iteratorAtomic action => ::first  
				| anyExpression bless => Expression
				| stringContentElement  action => ::first
				
iteratorAtomic ::= name bless => iterator 
				

#Lexemes:
tableName ~ <one or more word characters>
columnName ~ <one or more word characters>
name ~ <any letter that is not x> <zero or more word characters> 

<any letter> ~ [a-zA-Z]
<any letter that is not x> ~ [a-wyzA-WYZ]
<zero or more word characters> ~ [\w]*
<one or more word characters> ~ [\w]+

SCENARIOSETRULES

$scenarioSetRules .= $basicExpressionssAndSets . $subsetConditionRule. $basicStringsAndComments;



my $grammarEqn = Marpa::R2::Scanless::G->new(
	{   
		bless_package => 'MpmasQl3EqnElements',
		action_object => 'MpmasQl3EqnActions',
		source        => \$eqnRules,
	}   
); 
my $grammarPrm = Marpa::R2::Scanless::G->new(
	{   
		bless_package => 'MpmasQl3EqnElements',
		action_object => 'MpmasQl3EqnActions',
		source        => \$prmRules,
	}   
); 
my $grammarData = Marpa::R2::Scanless::G->new(
	{   
		bless_package => 'MpmasQl3EqnElements',
		action_object => 'MpmasQl3EqnActions',
		source        => \$dataRules,
	}   
); 
my $grammarMas = Marpa::R2::Scanless::G->new(
	{   
		bless_package => 'MpmasQl3EqnElements',
		action_object => 'MpmasQl3EqnActions',
		source        => \$masRules,
	}   
); 
my $grammarCfg = Marpa::R2::Scanless::G->new(
	{   
		bless_package => 'MpmasQl3EqnElements',
		action_object => 'MpmasQl3EqnActions',
		source        => \$cfgRules,
	}   
); 
my $grammarIni = Marpa::R2::Scanless::G->new(
	{   
		bless_package => 'MpmasQl3EqnElements',
		action_object => 'MpmasQl3EqnActions',
		source        => \$iniRules,
	}
	); 
my $grammarScenValue = Marpa::R2::Scanless::G->new(
	{   
		bless_package => 'MpmasQl3EqnElements',
		action_object => 'MpmasQl3EqnActions',
		source        => \$scenarioValueRules,
	}
	); 
my $grammarScenSet = Marpa::R2::Scanless::G->new(
	{   
		bless_package => 'MpmasQl3EqnElements',
		action_object => 'MpmasQl3EqnActions',
		source        => \$scenarioSetRules,
	}
	); 		
	
	
	
##new, creates a new instance by reading a input files
sub new_model {
	my ($class, $filenameIni,  $setstrings, $verbosityflags, $singlemode, $iniOnly) = @_;
	croak ("Error: new called from an object reference\n") if (ref($class)); 
	$setstrings = {} unless (defined $setstrings);
	
	# Make object
	my $self = {};	
	$self->{CONVERSION}->{mperiodIterator} = 't';
	
	my $temp = Hash::Merge::merge(dclone(\%MpmasQLRegistry::cfg_entries), dclone(\%MpmasQLRegistry::cfg_lists));
	$self->{BASECONFIG} = Hash::Merge::merge(dclone(\%MpmasQLRegistry::mpmas_parameters), $temp);
	$self->{BASECONFIG}->{MPMASQL3} = 1;
	$self->{BASECONFIG}->{Groupings}->{activity} = {};
	$self->{BASECONFIG}->{Groupings}->{constraint} = {};
	
	$self->{CHANGEABLE} = {};
	$self->{CHANGED} = {};
	
	bless $self, $class;
	
	if ($iniOnly) {
		my $sing = (($self->{INIHASH}->{STANDALONE} == 1) || $singlemode);

		if (not defined $self->{INIHASH}->{PREFIX}) {
			my ($vol, $dirs, $fn) = File::Spec->splitpath($filenameIni);
			$fn =~ s/\.ini$//;
			$self->{INIHASH}->{PREFIX} = $fn;
		}

		$self->{INIHASH}->{OUTDIR} = "./" unless (defined $self->{INIHASH}->{OUTDIR});
		$self->new_ini($filenameIni, $setstrings, $verbosityflags->{VERBOSE_READINI});
		return $self;
	}
	
	
	$self->{AST_configuration} = [];
	$self->{AST_mas_param} = [];
	$self->{AST_mas_tables} = [];
	$self->{AST_data} = [];
	$self->{AST_tables} = [];
		
	
	if ($filenameIni  =~ /\.mpm$/) {
		$self->{INIHASH}->{STANDALONE} = 1;
		
		my ($vol, $dirs, $fn) = File::Spec->splitpath($filenameIni);
		$fn =~ s/\.mpm$//;
		$self->{INIHASH}->{PREFIX} = $fn;
		$self->{INIHASH}->{OUTDIR} = "./";
		

		$self->{BASECONFIG}->{CONTYPEORDER} = $MpmasQLRegistry::CONSTRAINT_TYPES;
		$self->{BASECONFIG}->{ACTTYPEORDER} = $MpmasQLRegistry::ACTIVITY_TYPES;
		
		if ( -e File::Spec->catpath($vol, $dirs, $fn.".dat")){
			print "Model data file:\t\t\t". File::Spec->catpath($vol, $dirs, $fn.".dat")."\n";
			$self->new_data(File::Spec->catpath($vol, $dirs, $fn.".dat"), $verbosityflags->{VERBOSE_READDATA});
		}
		my $filenamePrm = "";
		if ( -e File::Spec->catpath($vol, $dirs, $fn.".prm")){
			print "Decision model parameter file:\t\t\t". File::Spec->catpath($vol, $dirs, $fn.".prm")."\n";
			$filenamePrm = File::Spec->catpath($vol, $dirs, $fn.".prm");;
		}
		
		
		print "Decision model file:\t\t\t". $filenameIni."\n";
		$self->new_mpm_prm($filenameIni, $filenamePrm, $self->{BASECONFIG}, $verbosityflags->{VERBOSE_CLASS});
		
		
		
		
	}
	
	else {

		#Read and process ini file		
		$self->new_ini($filenameIni, $setstrings, $verbosityflags->{VERBOSE_READINI});

		my $sing = (($self->{INIHASH}->{STANDALONE} == 1) || $singlemode);

		if (not defined $self->{INIHASH}->{PREFIX}) {
			my ($vol, $dirs, $fn) = File::Spec->splitpath($filenameIni);
			$fn =~ s/\.ini$//;
			$self->{INIHASH}->{PREFIX} = $fn;
		}

        if ($sing) {
            if( $self->{INIHASH}->{RUNINDIR} ) {
                    $self->{INIHASH}->{RUNINDIR} =~ s/\/+$//;   #remove trailing / to avoid doubling of / later on 
                    $self->{INIHASH}->{RUNINDIR} .="/";
            }
        
		    $self->{INIHASH}->{OUTDIR} = $self->{INIHASH}->{RUNINDIR} ."/" if (not defined $self->{INIHASH}->{OUTDIR} and  $self->{INIHASH}->{RUNINDIR});
		    $self->{INIHASH}->{OUTDIR} = "./" unless (defined $self->{INIHASH}->{OUTDIR});
		    
		    
		    if( $self->{INIHASH}->{RUNOUTDIR} ) {
                    $self->{INIHASH}->{RUNOUTDIR} =~ s/\/+$//;    #remove trailing / to avoid doubling of / later on 
                    $self->{INIHASH}->{RUNOUTDIR} .="/";
            }
		    
		} 
		else {
		 	if (defined $self->{INIHASH}->{RUNINDIR}) {
        		 $self->{INIHASH}->{RUNINDIR} =~ s/input\/dat\/*$//;
         		 $self->{INIHASH}->{RUNINDIR} =~ s/\/+$//; #remove trailing / to avoid doubling of / later on 
         		 
    		}
    	    if (defined $self->{INIHASH}->{RUNOUTDIR}) {
        		 $self->{INIHASH}->{RUNOUTDIR} =~ s/out\/*$//;
         		 $self->{INIHASH}->{RUNOUTDIR} =~ s/\/+$//; #remove trailing / to avoid doubling of / later on 
                 $self->{INIHASH}->{RUNOUTDIR} .="/" if ($self->{INIHASH}->{RUNOUTDIR});
    		}
    		
    		
    		if ($self->{INIHASH}->{RUNINDIR}) {
    		
        		 $self->{INIHASH}->{RUNINDIR} .="/";
	             if (not defined $self->{INIHASH}->{OUTDIR}  ){
	                $self->{INIHASH}->{OUTDIR} = $self->{INIHASH}->{RUNINDIR}."input/dat/" ;
	        
	             }
    		}
		    else {
    		    $self->{INIHASH}->{OUTDIR} = "./input/dat/" unless (defined $self->{INIHASH}->{OUTDIR});
	        }	
		
		
		}

		if(defined $self->{INIHASH}->{CONFIGURATION}) {
			#Read other model files and create Abstract syntax trees
			print "\nModel configuration file:\t\t". $self->{INIHASH}->{CONFIGURATION}."\n";
			$self->new_cfg($self->{INIHASH}->{CONFIGURATION}, $verbosityflags->{VERBOSE_READCFG});
		}
		elsif ($sing) {
			#nothing to do
		}
		else {
			print STDERR "Error: You forgot to specify a CONFIGURATION file in $filenameIni" and exit(1);
		}

		if(defined $self->{INIHASH}->{DATA}) {
			print "Model data file:\t\t\t". $self->{INIHASH}->{DATA}."\n";
			$self->new_data($self->{INIHASH}->{DATA}, $verbosityflags->{VERBOSE_READDATA});
		}
		elsif ($sing) {

			print STDERR "Info: No specific model DATA file in $filenameIni";		}
		else {
			print STDERR "Error: You forgot to specify a DATA file in $filenameIni" and exit(1);
		}
		if(defined $self->{INIHASH}->{MAS_PARAMETERS}) {

			print "Mpmas parameters file:\t\t\t". $self->{INIHASH}->{MAS_PARAMETERS}."\n";
			$self->new_mas_param($self->{INIHASH}->{MAS_PARAMETERS}, $verbosityflags->{VERBOSE_READMAS});
		}
		elsif ($sing) {
			#nothing to do	
		}
		else {
			print STDERR "Error: You forgot to specify a MAS_PARAMETERS file in $filenameIni" and exit(1);
		}
		
				
		$self->{BASECONFIG}->{CONTYPEORDER} = $MpmasQLRegistry::CONSTRAINT_TYPES;
		$self->{BASECONFIG}->{ACTTYPEORDER} = $MpmasQLRegistry::ACTIVITY_TYPES;
		
		print STDERR "Error: You forgot to specify a DECISION_MODEL file in $filenameIni" and exit(1) unless (exists $self->{INIHASH}->{DECISION_MODEL});
		print "Decision model file:\t\t\t". $self->{INIHASH}->{DECISION_MODEL}."\n";

		print "Decision model parameter file:\t\t". $self->{INIHASH}->{DECISION_PARAMETERS}."\n" if (defined $self->{INIHASH}->{DECISION_PARAMETERS});
		
		$self->new_mpm_prm($self->{INIHASH}->{DECISION_MODEL}, $self->{INIHASH}->{DECISION_PARAMETERS}, $self->{BASECONFIG}, $verbosityflags->{VERBOSE_CLASS});
		
		



		
	}

	#return $self;	
	return $self;	
}
sub new_ini {
	my ($self, $filenameIni,  $setstrings, $verbose) = @_;

	$verbose = 0 unless (defined $verbose);
	
	
### Read the ini-file	
	my $resultHash = $self->parse_file($filenameIni, $grammarIni, $verbose);
	
	$self->{INIHASH};
	$self->{INITABLEDEFS};

	#print Dumper($resultHash);

	for my $i (@$$resultHash) {
		if (ref $i eq 'MpmasQl3EqnElements::iniEntryDefinition')
		{ 	$i->transform($self) ;
		}
		elsif (ref $i eq 'MpmasQl3EqnElements::iniSetDefinition')
		{  $i->transform($self) ;
		}		
		elsif (ref $i eq 'MpmasQl3EqnElements::iniTableDefinition')
		{   #$i->_compatibility_make_inihash($self) ;
			$self->{INITABLEDEFS}->{$i->name()} = $i;
		}		
	}

	foreach my $k (keys %$setstrings) {
		$self->{INIHASH}->{$k} = $setstrings->{$k};
	}

	my $inihash = $self->{INIHASH};

	if ( $verbose ) {
			print "\nConversion control settings:\n";
			print nice_hash_dump($inihash);
			print nice_hash_dump($self->{INITABLEDEFS});
	}
	#print STDERR "Error: You forgot to specify a CONFIGURATION file in $filenameIni" and exit(1) unless (exists $inihash->{CONFIGURATION});
	#print STDERR "Error: You forgot to specify a DATA file in $filenameIni" and exit(1) unless (exists $inihash->{DATA});
	#print STDERR "Error: You forgot to specify a DECISION_MODEL file in $filenameIni" and exit(1) unless (exists $inihash->{DECISION_MODEL});
	#print STDERR "Error: You forgot to specify a DECISION_PARAMETERS file in $filenameIni" and exit(1) unless (exists $inihash->{DECISION_PARAMETERS});
	#print STDERR "Error: You forgot to specify a MAS_PARAMETERS file in $filenameIni" and exit(1) unless (exists $inihash->{MAS_PARAMETERS});

}
sub new_cfg {
	my ($self, $filenameCfg, $verbose) = @_;
	
	my $resultHash = $self->parse_file($filenameCfg, $grammarCfg, $verbose);

	$self->{AST_configuration} = [];

	for my $i (@$$resultHash) {
		if (ref $i eq 'MpmasQl3EqnElements::configEntryDefinition')
		{ push @{ $self->{AST_configuration} }, $i;
		  $self->{CHANGEABLE}->{$i->name} = $i;	
		}
		elsif (ref $i eq 'MpmasQl3EqnElements::configListDefinition')
		{  push @{ $self->{AST_configuration} }, $i;
		   $self->{CHANGEABLE}->{$i->name} = $i;
		}
	}
	
#	if ( $verbose) {
#		print "\nModel configuration:\n";
#		#print nice_hash_dump($baseconfigs);
#	}
	
}
sub new_data {
	my ($self, $filenameData, $verbose) = @_;
	
	my $resultHash = $self->parse_file($filenameData, $grammarData, $verbose);

	#$self->{AST_data} = []; ##now done in new_model to avoid overwriting
	#$self->{AST_tables} = [];

	for my $i (@$$resultHash) {
		if (ref $i eq 'MpmasQl3EqnElements::globalDefinition')
		{ push @{ $self->{AST_data} }, $i;
		  $self->{CHANGEABLE}->{$i->name} = $i;
		}
		elsif (ref $i eq 'MpmasQl3EqnElements::globalSetDefinition')
		{ push @{ $self->{AST_data} }, $i;
		  $self->{CHANGEABLE}->{$i->name} = $i;
		}
		elsif (ref $i eq 'MpmasQl3EqnElements::simrunParameterDefinition')
		{ push @{ $self->{AST_data} }, $i;
		}
		elsif (ref $i eq 'MpmasQl3EqnElements::simrunParameterDefinitionIndexed')
		{ push @{ $self->{AST_data} }, $i;
		}
		elsif (ref $i eq 'MpmasQl3EqnElements::tableDefinition')
		{  #push @{ $self->{AST_tables} }, $i;
		   push @{ $self->{AST_data} }, $i;
		   $self->{CHANGEABLE}->{$i->name} = $i;	
		}
	}
	
#	if ( $verbose) {
#		print "\nModel configuration:\n";
#		#print nice_hash_dump($baseconfigs);
#	}	
}
sub new_mas_param {
	my ($self, $filenameData, $verbose) = @_;
	
	my $resultHash = $self->parse_file($filenameData, $grammarMas, $verbose);

	#$self->{AST_mas_param} = []; ##now done in new_model to avoid overwriting
	#$self->{AST_mas_tables} = [];

	for my $i (@$$resultHash) {
		if (ref $i eq 'MpmasQl3EqnElements::configEntryDefinition')
		{ push @{ $self->{AST_configuration} }, $i;
		  $self->{CHANGEABLE}->{$i->name} = $i;
		}
		elsif (ref $i eq 'MpmasQl3EqnElements::mpmasTableDefinition' or ref $i eq 'MpmasQl3EqnElements::mpmasTableDefinitionIterated')
		{  push @{ $self->{AST_mas_tables} }, $i;
		   $self->{CHANGEABLE}->{$i->name} = $i;
		}
	}
	
	if ( $verbose) {
		print "\nModel configuration:\n";
		print Dumper($self->{AST_configuration});
		print Dumper($self->{AST_mas_tables});
	}	
}

sub inihash {
	return $_[0]->{INIHASH};
}

sub transform_scenario_list {
	my ($self, $dbh) = @_;
	
	my $scenlist = [("_")]; 
	if (exists $self->{INITABLEDEFS}->{SCENLIST}) {
		
		my $x;
		eval { 
			$x = $self->{INITABLEDEFS}->{SCENLIST}->transform($self, $dbh);
		};
		print STDERR "Error when loading SCENLIST:\n".MpmasQl3EqnElements::shortError($@) and exit(1) if $@;	

		#$scenlist = [$self->{INITABLES}->{SCENLIST}->query([],0)] ;
		$scenlist = [$x->query([],0)] ;
	}
	return $scenlist;
}

sub transform_scenario_tables {
	my ($self, $dbh, $restricted_list, $accept_only_defined) = @_;
	my $scenlist;
	
	if (defined $restricted_list and scalar @$restricted_list) {
		$scenlist = $restricted_list;
	}
	else {
	 	$scenlist = $self->transform_scenario_list($dbh);
	}
#	my $scenlist = [("_")]; 
#	if (exists $self->{INITABLEDEFS}->{SCENLIST}) {
#		
#		my $x;
#		eval { 
#			$x = $self->{INITABLEDEFS}->{SCENLIST}->transform($self, $dbh);
#		};
#		print STDERR "Error when loading SCENLIST:\n".MpmasQl3EqnElements::shortError($@) and exit(1) if $@;	
#
#		#$scenlist = [$self->{INITABLES}->{SCENLIST}->query([],0)] ;
#		$scenlist = [$x->query([],0)] ;
#	}
	
	my $scendef;
	if (exists $self->{INITABLEDEFS}->{SCENDEF}) {
		eval {
			$scendef = $self->{INITABLEDEFS}->{SCENDEF}->transform($self, $dbh);
		};
		print STDERR "Error when loading SCENDEF:\n".MpmasQl3EqnElements::shortError($@) and exit(1) if $@;	

	}
	my $scencommon;
	if (exists  $self->{INITABLEDEFS}->{COMMON}) {
		eval {
			$scencommon = $self->{INITABLEDEFS}->{COMMON}->transform($self, $dbh);
		};
		print STDERR "Error when loading COMMON:\n".MpmasQl3EqnElements::shortError($@) and exit(1) if $@;	

	}
	if (defined $scencommon) {
		for my $c (  $scencommon->query([],0)) {
			my $v = $scencommon->query([$c],2);

			unless (defined	$self->{CHANGEABLE}->{$c} )
			{
				croak ("Error in COMMON: Variable $c is not a global variable, table, configuration entry, or MPMAS parameter mentioned in the .dat or .mas file.\n");
			}
			my $type = ref($self->{CHANGEABLE}->{$c} );
			my $hash;		
			if ($type eq 'MpmasQl3EqnElements::globalSetDefinition' or $type eq 'MpmasQl3EqnElements::configListDefinition') {
				$hash = $self->parse_string($v,$grammarScenSet, "COMMON: ".$c);
			}
			else {
				$hash = $self->parse_string($v,$grammarScenValue, "COMMON: ".$c);
			}
			#print Dumper($hash);
			#$scencommon->set_column_value([$c],2, $$hash );
			$self->{CHANGEABLE}->{$c}->set_content($$hash);
		}
	}
	if (defined $scendef) {
		#for my $s (  $scendef->query([],0)) {
		for my $s ( @$scenlist ) {
			if ( scalar ($scendef->query([$s],0) ) < 1) {
			
						print STDERR "Error: Scenario $s not defined in SCENDEF and ONLY_DEFINED_SCENARIOS = 1\n" and exit(1) if $accept_only_defined;
						print STDERR "Warning: Scenario $s not defined in SCENDEF. Using cfg-files as they are!\n";

			} 
			for my $c (  $scendef->query([$s],0)) {
				
				my $v = $scendef->query([$s,$c],3);

				unless (defined	$self->{CHANGEABLE}->{$c} )
				{
					print STDERR "Error in SCENDEF: Variable $c is not a global variable, table, configuration entry, or MPMAS parameter mentioned in the .dat or .mas file.\n";
					exit(1);
				}
				my $type = ref($self->{CHANGEABLE}->{$c} );
				my $hash;		
				if ($type eq 'MpmasQl3EqnElements::globalSetDefinition' or $type eq 'MpmasQl3EqnElements::configListDefinition') {
					$hash = $self->parse_string($v,$grammarScenSet, "SCENDEF: ".$c);
				}
				else {
					$hash = $self->parse_string($v,$grammarScenValue, "SCENDEF: ".$c);
				}
				#$scendef->set_column_value([$s,$c],3, $$hash );
				$self->{CHANGED}->{$c}->{$s} = $$hash;
#				print Dumper($scendef->query([$s,$c],3));
			}
		}
	}
	return ($scenlist, $scendef, $scencommon);
}
sub transform_parameter_variation_list {
	my ($self, $dbh) = @_;
	my $paramscenlist = [("_")]; 
	if (exists $self->{INITABLEDEFS}->{PARAMETER_SCENLIST}) {
		my $x;
		eval {
			$x = $self->{INITABLEDEFS}->{PARAMETER_SCENLIST}->transform($self, $dbh);
		};
		print STDERR "Error when loading PARAMETER_SCENLIST:\n".MpmasQl3EqnElements::shortError($@) and exit(1) if $@;	

		$paramscenlist = [$x->query([],0)] ;
	}
	return $paramscenlist;
}


sub transform_parameter_variation_tables {
	my ($self, $dbh) = @_;
	
	my $paramscenlist = $self->transform_parameter_variation_list($dbh);
	
#	my $paramscenlist = [("_")]; 
#	if (exists $self->{INITABLEDEFS}->{PARAMETER_SCENLIST}) {
#		my $x;
#		eval {
#			$x = $self->{INITABLEDEFS}->{PARAMETER_SCENLIST}->transform($self, $dbh);
#		};
#		print STDERR "Error when loading PARAMETER_SCENLIST:\n".MpmasQl3EqnElements::shortError($@) and exit(1) if $@;	
#
#		$paramscenlist = [$x->query([],0)] ;
#	}
	
	my $paramscendef;
	if (exists $self->{INITABLEDEFS}->{PARAMETER_SCENDEF}) {
		eval {
			$paramscendef = $self->{INITABLEDEFS}->{PARAMETER_SCENDEF}->transform($self, $dbh);
		};
		print STDERR "Error when loading PARAMETER_SCENDEF:\n".MpmasQl3EqnElements::shortError($@) and exit(1) if $@;	
	}
	
	if (defined $paramscendef) {
		#for my $s (  $scendef->query([],0)) {
		for my $s ( @$paramscenlist ) {
			if ( scalar ($paramscendef->query([$s],0) ) < 1) {
				print STDERR "Warning: Parameter scenario $s not defined in PARAMETER_SCENDEF. Using cfg-files as they are!\n";
			} 
			for my $c (  $paramscendef->query([$s],0)) {
				
				my $v = $paramscendef->query([$s,$c],3);
				
				unless ( Scalar::Util::looks_like_number( $v) or exists $MpmasQLRegistry::mpmas_simrun_variation{$c})
				{
					croak ("Error in PARAMETER_SCENDEF:  The value $v assigned to variable $c for parameter scenario $s is not numeric.\n");
				}
			}	
		}
	}
	return ($paramscenlist, $paramscendef);
}


sub transform_rhs_tables {
	my ($self, $dbh) = @_;
	
	my $rhslist = [("_")]; 
	if (exists $self->{INITABLEDEFS}->{RHSLIST}) {
		eval {
			$self->{INITABLEDEFS}->{RHSLIST}->transform($self, $dbh);
		};
		print STDERR "Error when loading RHSLIST:\n".MpmasQl3EqnElements::shortError($@) and exit(1) if $@;	

		$rhslist = [$self->{INITABLES}->{RHSLIST}->query([],0)] ;
	}
	
	my $rhsdef;
	if (exists $self->{INITABLEDEFS}->{RHSDEF}) {
		eval {
			$rhsdef = $self->{INITABLEDEFS}->{RHSDEF}->transform($self, $dbh);
		};
		print STDERR "Error when loading RHSDEF:\n".MpmasQl3EqnElements::shortError($@) and exit(1) if $@;	

	}

	return ($rhslist, $rhsdef);
}

sub new {
	my ($class, $filenameEqn, $filenamePrm, $baseconfigs, $verbose) = @_;
	$verbose = 0 unless (defined $verbose);
	
	croak ("Error: new called from an object reference\n") if (ref($class)); 
	
	#Create parser instance
	my $recognizer=  Marpa::R2::Scanless::R->new( { grammar => $grammarEqn	} );
	my $PrmRecognizer=  Marpa::R2::Scanless::R->new( { grammar => $grammarPrm	} );


	#Open input file and slurp into string
	my $eqnString;
	{
		do { local $/ = undef;
			open (my $infile, "<", $filenameEqn) or die $! ."\n" . $filenameEqn."\n";
			$eqnString = <$infile>;
			close ($infile); 
		}
	}
	
	#Open input file and slurp into string
	my $prmString;
	{
		do { local $/ = undef;
			open (my $infile2, "<", $filenamePrm) or die $! ."\n" . $filenamePrm."\n";
			$prmString = <$infile2>;
			close ($infile2); 
		}
	}


	#Parse input string to abstract syntax trees (AST)
	eval {  local $SIG{__WARN__} = sub {};   $recognizer->read( \$eqnString ); 1 };

	if ($@) {
		my $progress_report = $recognizer->show_progress( 0, -1 ) if $verbose;
		my $rep = "$@";
		my $s = index $rep, "*";

		my $p = index $rep, "Marpa::R2 exception";
		my $report = substr($rep, $s, $p);


		#print $progress_report;
		print STDERR "Error while parsing decision model in $filenameEqn\n";
		print STDERR $report;
		print STDERR $progress_report if $verbose;
		
		exit(1);
	}
	my $resultHash = $recognizer->value();
	if ( not defined $resultHash ) {
		die "$filenameEqn could not be parsed due to syntax error\n";
	}
	
	eval { local $SIG{__WARN__} = sub {};    $PrmRecognizer->read( \$prmString ); 1 };

	if ($@) {
		my $progress_report = $PrmRecognizer->show_progress( 0, -1 ) if $verbose;
		
		my $rep = "$@";
		my $s = index $rep, "*";

		my $p = index $rep, "Marpa::R2 exception";
		my $report = substr($rep, $s, $p);

		
		$report .= "\n";
		
	
		print STDERR "Error while parsing decision model parameters in $filenamePrm\n";
		print STDERR $report;
		print $progress_report if $verbose;
		exit(1);
	}
	my $PrmResultHash = $PrmRecognizer->value();
	if ( not defined $PrmResultHash ) {
		print STDERR "$filenamePrm could not be parsed due to syntax error\n\n";
		exit(1);
	}
	#	print Dumper($PrmResultHash);

	
	# Make object
	my $self = {};


	#split Decision model ASTs by types of elements
	my @decisionVariableDefinitions;
	my @equationDefinitions;
	my @assetDefinitions;
	
	my $eqOrderResolved = 0;
	my $decOrderResolved = 0;

	for my $i (@$$resultHash) {
		if (ref $i eq 'MpmasQl3EqnElements::equationDefinition')
		{ push @equationDefinitions, $i;
		}
		elsif (ref $i eq 'MpmasQl3EqnElements::decisionVariableDefinition')
		{ push @decisionVariableDefinitions, $i;
		}
		elsif (ref $i eq 'MpmasQl3EqnElements::assetDefinition')
		{ push @assetDefinitions, $i;
		}
		elsif (ref $i eq 'MpmasQl3EqnElements::equationOrderDefinition')
		{ 	$i->transform($baseconfigs) if (defined $baseconfigs);#Complement constraint order string in $baseconfigs
			$eqOrderResolved = 1;
		}
		elsif (ref $i eq 'MpmasQl3EqnElements::decisionVariableOrderDefinition')
		{  $i->transform($baseconfigs) if (defined $baseconfigs);#Complement activityorder string in $baseconfigs
			$decOrderResolved = 1;
		}		
	}
	
	unless ($eqOrderResolved) {
		if (exists $baseconfigs->{CONTYPEORDER} ) {
			$baseconfigs->{CONTYPEORDER} =~ s/###/default/;
		}
		else {
			  $baseconfigs->{CONTYPEORDER} = "[ default, standard]";
		}
		
	} 
	unless ($decOrderResolved) {
		if (exists $baseconfigs->{ACTTYPEORDER} ) {
			$baseconfigs->{ACTTYPEORDER} =~ s/###/default/;
		}
		else {
			  $baseconfigs->{ACTTYPEORDER} = "[ default, standard ]";
		}
	} 

	$self->{parameterAndSetDefinitions} = $$PrmResultHash;
	$self->{decisionVariableDefinitions} = \@decisionVariableDefinitions;
	$self->{equationDefinitions} = \@equationDefinitions;
	$self->{assetDefinitions} = \@assetDefinitions;
	
	bless $self, $class;
	return $self;
}
sub new_mpm_prm {
	my ($self, $filenameEqn, $filenamePrm, $baseconfigs, $verbose) = @_;
	$verbose = 0 unless (defined $verbose);
	
	
	#Create parser instance
	my $recognizer=  Marpa::R2::Scanless::R->new( { grammar => $grammarEqn	} );
	my $PrmRecognizer=  Marpa::R2::Scanless::R->new( { grammar => $grammarPrm	} );


	#Open input file and slurp into string
	my $eqnString;
	{
		do { local $/ = undef;
			open (my $infile, "<", $filenameEqn) or die $! ."\n" . $filenameEqn."\n";
			$eqnString = <$infile>;
			close ($infile); 
		}
	}
	
	#Open input file and slurp into string
	my $prmString;
	if ( $filenamePrm) {
		do { local $/ = undef;
			open (my $infile2, "<", $filenamePrm) or die $! ."\n" . $filenamePrm."\n";
			$prmString = <$infile2>;
			close ($infile2); 
		}
	}


	#Parse input string to abstract syntax trees (AST)
	eval {  local $SIG{__WARN__} = sub {};   $recognizer->read( \$eqnString ); 1 };

	if ($@) {
		my $progress_report = $recognizer->show_progress( 0, -1 ) if $verbose;
		my $rep = "$@";
		my $s = index $rep, "*";

		my $p = index $rep, "Marpa::R2 exception";
		my $report = substr($rep, $s, $p);


		#print $progress_report;
		print STDERR "Error while parsing decision model in $filenameEqn\n";
		print STDERR $report;
		print STDERR $progress_report if $verbose;
		
		exit(1);
	}
	my $resultHash = $recognizer->value();
	if ( not defined $resultHash ) {
		die "$filenameEqn could not be parsed due to syntax error\n";
	}
	my $PrmResultHash;
	$self->{parameterAndSetDefinitions} = [];
	
	if ( $filenamePrm) {
		eval { local $SIG{__WARN__} = sub {};    $PrmRecognizer->read( \$prmString ); 1 };

		if ($@) {
			my $progress_report = $PrmRecognizer->show_progress( 0, -1 ) if $verbose;
			
			my $rep = "$@";
			my $s = index $rep, "*";

			my $p = index $rep, "Marpa::R2 exception";
			my $report = substr($rep, $s, $p);

			
			$report .= "\n";
			
		
			print STDERR "Error while parsing decision model parameters in $filenamePrm\n";
			print STDERR $report;
			print $progress_report if $verbose;
			exit(1);
		}
		$PrmResultHash = $PrmRecognizer->value();
		if ( not defined $PrmResultHash ) {
			print STDERR "$filenamePrm could not be parsed due to syntax error\n";
			exit(1);
		}
		$self->{parameterAndSetDefinitions} = $$PrmResultHash;
	}
	#	print Dumper($PrmResultHash);

	#print "1:", Dumper($baseconfigs->{CONTYPEORDER});

	#split Decision model ASTs by types of elements
	my @decisionVariableDefinitions;
	my @equationDefinitions;
	my @assetDefinitions;
	
	my $eqOrderResolved = 0;
	my $decOrderResolved = 0;

	for my $i (@$$resultHash) {
		if (ref $i eq 'MpmasQl3EqnElements::equationDefinition')
		{ push @equationDefinitions, $i;
		}
		elsif (ref $i eq 'MpmasQl3EqnElements::decisionVariableDefinition')
		{ push @decisionVariableDefinitions, $i;
		}
		elsif (ref $i eq 'MpmasQl3EqnElements::assetDefinition')
		{ push @assetDefinitions, $i;
		}
		elsif (ref $i eq 'MpmasQl3EqnElements::parameterDefinition')
		{ push @{ $self->{parameterAndSetDefinitions} }, $i;
		#		  print "Pushed $i->[0]\n";
		}
		elsif (ref $i eq 'MpmasQl3EqnElements::setDefinition')
		{ push @{ $self->{parameterAndSetDefinitions} }, $i;
		  #print "Pushed $i->[0]\n";
		}
		elsif (ref $i eq 'MpmasQl3EqnElements::equationOrderDefinition')
		{ 	$i->transform($baseconfigs) if (defined $baseconfigs);#Complement constraint order string in $baseconfigs
			$eqOrderResolved = 1;
		}
		elsif (ref $i eq 'MpmasQl3EqnElements::decisionVariableOrderDefinition')
		{  $i->transform($baseconfigs) if (defined $baseconfigs);#Complement activityorder string in $baseconfigs
			$decOrderResolved = 1;
		}
				
	}
	#print "2:", Dumper($baseconfigs->{CONTYPEORDER});
	unless ($eqOrderResolved) {
		if (exists $baseconfigs->{CONTYPEORDER} ) {
			$baseconfigs->{CONTYPEORDER} =~ s/###/default/;
			$baseconfigs->{CONTYPEORDER} = [ split (/\s*,\s*/, $baseconfigs->{CONTYPEORDER})];
		}
		else {
			  $baseconfigs->{CONTYPEORDER} = [ ("default", "standard")];
		}
		
	} 
	#print "3:", Dumper($baseconfigs->{CONTYPEORDER});
	unless ($decOrderResolved) {
		if (exists $baseconfigs->{ACTTYPEORDER} ) {
			$baseconfigs->{ACTTYPEORDER} =~ s/###/default/;
			$baseconfigs->{ACTTYPEORDER} = [ split (/\s*,\s*/, $baseconfigs->{ACTTYPEORDER})];
		}
		else {
			  $baseconfigs->{ACTTYPEORDER} = [("default", "standard") ];
		}
	} 

	$self->{decisionVariableDefinitions} = \@decisionVariableDefinitions;
	$self->{equationDefinitions} = \@equationDefinitions;
	$self->{assetDefinitions} = \@assetDefinitions;

}
sub create_sets_and_parameters2 {
	my ($self, $dbgParameters) = @_;
	delete $self->{PARAMETERS};
	delete $self->{SETS};
	delete $self->{ASSETS};
	$self->{ASSETS} = SimpleObjectRegistry->create(); # Only to make sure we get a proper error message when trying to use an asset reference during set/parameter creation
	$self->create_sets_and_parameters($self, $dbgParameters);
}
sub create_sets_and_parameters {
	my ($self, $database, $dbgParameters) = @_;
	my $mu = MpmasInputfile->getMemUsageObj();
	print "Timings for .prm sets and parameters:\n" if $logTime;
	my $lasttime = time;
	for my $i (@{$self->{parameterAndSetDefinitions}} ) {
		
		unless(  ref($i) ) {
			print STDERR "This is not a reference: (". $i."\n";
			exit(1);
		}
		unless(  ref($i) &&  UNIVERSAL::can($i,'isa')  ) {
			print STDERR "This is an unblessed reference: (". ref($i)."\n" .Dumper($i);
			exit(1);
		}
		
		$i->transform($database);	
		print $i->[0], ": " , (time - $lasttime), "\n" if $logTime;
		$lasttime=time if $logTime;
		
		$mu->record('after '. $i->[0] ) if logMem;
		
		#Output results if requested
		my $vn = $i->name();
	    
	    if ( exists $dbgParameters->{$vn }  ) {

			if (ref $i eq 'MpmasQl3EqnElements::parameterDefinition') {

				my $v = $database->{PARAMETERS}->{$vn};
				if (ref($v) eq 'IndexedTable') {
					print "\n\n$vn:\n";
					$v->printme_with_header_sorted();
				}
				else {
					print "$vn:".Dumper($v);
				}
				print "---\n";
			}
			elsif (ref $i eq 'MpmasQl3EqnElements::setDefinition') {
				my $v = $database->{SETS}->{$vn};
				if (ref($v) eq 'IndexedTable') {
					print "\n\n$vn:\n";
					$v->printme_with_header_sorted();
				}
				else {
					print "$vn:".Dumper($v);
				}
				print "---\n";
			}


	  }
	}
}
sub create_model_elements2 {
	my ($self, $milplist, $debug_act_list, $parallelElems, $parallelInst,$parallelInstThreshold) = @_;
	delete $self->{ASSETS};
	$self->create_model_elements($self, $milplist, $debug_act_list, $parallelElems, $parallelInst,$parallelInstThreshold);
}
sub create_model_elements {
	my ($self, $database, $milplist, $debug_act_list, $parallelElems, $parallelInst,$parallelInstThreshold) = @_;
	my $AssetRegistry = SimpleObjectRegistry->create();
	$database->{ASSETS} = $AssetRegistry;
	
	my $mu = MpmasInputfile->getMemUsageObj();
	
    $MpmasQlModelElementAbstract::default_standard_milp = $milplist->[0];
	#print "MSM:", $MpmasQlModelElementAbstract::default_standard_milp , "\n";
	
	my $lasttime=time;
	print "Timings for MIP elements:\n" if $logTime;
	for my $i (       @{$self->{assetDefinitions}}    ){
		my @as = $i->transform($database, $milplist);
		$mu->record('after transforming  '. $i->[0] ) if logMem;
		
		$AssetRegistry->add_objects(@as);
	    $mu->record('after adding  '. $i->[0] ) if logMem;
		
		print $i->[0], ": " , (time - $lasttime), "\n" if $logTime;
		$lasttime=time if $logTime;
	}


	#create decision variables
	my $ActivityRegistry = SimpleObjectRegistry->create();
	#my $ActivityRegistry2 = SimpleObjectRegistry->create();
	my $MultiperiodReaderRegistry = [];
	my $MultiperiodInserterRegistry = [];
	
	if ($parallelElems) {
		my $iter = Parallel::Iterator::iterate( 
			{  adaptive => 1, 
				workers => $parallelElems}
				,
			sub { 
					my ( $id, $job ) = @_;
					return [ $job->transform($database, $milplist, $parallelInst,$parallelInstThreshold) ];
			}
			, \@{$self->{decisionVariableDefinitions} }  
		);
        
		while ( my ( $index, $value ) = $iter->() ) {
			$ActivityRegistry->add_objects(@{$value});
		}
	}
	else {	
#	    for my $i (@{$self->{decisionVariableDefinitions}}  ){
#			my ($ao)  = $i->transform_basics($database, $milplist,$parallelInst,$parallelInstThreshold);
#			print $i->[0], ": " , (time - $lasttime), "\n" if $logTime;
#
	#		$lasttime=time if $logTime;
	#		$ActivityRegistry2->add_objects(@$ao);
	#	}
	    
	
	
	
	
		for my $i (@{$self->{decisionVariableDefinitions}}  ){
			my ($ao, $readers, $inserters)  = $i->transform($database, $milplist,$parallelInst,$parallelInstThreshold);
			print $i->[0], ": " , (time - $lasttime), "\n" if $logTime;
		    $mu->record('after transforming  '. $i->[0] ) if logMem;
			
			for my $iFunc ( 0..$#{$inserters}) {
				for my $iInfo ( @{$inserters->[$iFunc] } ) {
    				unless (defined $MultiperiodInserterRegistry->[$iFunc]) {
    				    $MultiperiodInserterRegistry->[$iFunc] = [];
    				}
					push @{ $MultiperiodInserterRegistry->[$iFunc] }, $iInfo;
				}
			}
			
			for my $rFunc ( 0.. $#{$readers}) {
				for my $rInfo ( @{$readers->[$rFunc] } ) {
    				unless (defined $MultiperiodReaderRegistry->[$rFunc]) {
    				    $MultiperiodReaderRegistry->[$rFunc] = [];
    				}
					push @{ $MultiperiodReaderRegistry->[$rFunc] }, $rInfo;
				}
			}
		    $mu->record('after inserters/readers  '. $i->[0] ) if logMem;
			
			$lasttime=time if $logTime;
			$ActivityRegistry->add_objects_from_ref($ao);
		    $mu->record('after adding  '. $i->[0] ) if logMem;
		}
	}
	
	$ActivityRegistry->save_attribute_table_as_ascii("debug_activity_list.tab", "name", "unit")	if ($debug_act_list);
	
	#create constraints
	my $ConstraintRegistry = SimpleObjectRegistry->create();
		
	if ($parallelElems) {
		my $iter = Parallel::Iterator::iterate( 
			{  adaptive => 1, 
				workers => $parallelElems}
				,
			sub { 
					my ( $id, $job ) = @_;
					return [ $job->transform($database, $ActivityRegistry, $milplist, $parallelInst,$parallelInstThreshold) ];
			}
			, \@{$self->{equationDefinitions} }  
		);
    
    
		while ( my ( $index, $value ) = $iter->() ) {
			$ConstraintRegistry->add_objects(@{$value});
		}
	}
	else {			
		for my $i (@{$self->{equationDefinitions}}){
			my ($co, $inserters) = $i->transform($database, $ActivityRegistry, $milplist, $parallelInst, $parallelInstThreshold);
		    $mu->record('after transforming  '. $i->[0] ) if logMem;
			
			$ConstraintRegistry->add_objects_from_ref($co);
		    $mu->record('after adding  '. $i->[0] ) if logMem;
			
			for my $iFunc ( 0.. $#{$inserters}) {
				for my $iInfo ( @{$inserters->[$iFunc] } ) {
					push @{ $MultiperiodInserterRegistry->[$iFunc] }, $iInfo;
				}
			}
		    $mu->record('after inserters/readers  '. $i->[0] ) if logMem;
			
			print $i->[0], ": " , (time - $lasttime), "\n" if $logTime;
			$lasttime=time if $logTime;
		}
	}
	#print "Registry:\n",Dumper($MultiperiodInserterRegistry);
	#$ConstraintRegistry->save_attribute_table_as_ascii("debug_constraint_list.tab", "name", "unit")	if ($debug_con_list);

	if ($verbose) {
		for my $i (sort {$a cmp $b} $ActivityRegistry->object_list() ) {

			print $i->id() ."\n";
			for my $k (sort {$a cmp $b} keys %$i) {
				print "\t".$k."\t".$i->attr($k)."\n" if($k ne 'others' and $k ne 'subelements'  and $k ne 'id');
			}
			for my $k (sort {$a cmp $b} keys %{$i->{others}} ) {
				print "\tcoefficient> ".$k."\t".$i->coeff($k)."\n";
			}
			for my $j (sort {$a cmp $b} $i->subelements() ) {
				for my $k (sort {$a cmp $b} $i->subelement_fields($j) ) {
					print "\t".$j."> ".$k."\t".$i->subelement_field($j,$k)."\n";
				}
			}
		}
		for my $i (sort {$a cmp $b} $ConstraintRegistry->object_list() ) {

			print $i->id() ."\n";
			for my $k (sort {$a cmp $b} keys %$i) {
				print "\t".$k."\t".$i->attr($k)."\n" if($k ne 'others' and $k ne 'subelements'  and $k ne 'id');
			}
			for my $j ($i->subelements() ) {
				for my $k ($i->subelement_fields($j) ) {
					print "\t".$j.">".$k."\t".$i->subelement_field($j,$k)."\n";
				}
			}
		}
		for my $i (sort {$a cmp $b} $AssetRegistry->object_list() ) {

			print $i->id() ."\n";
			for my $k (sort {$a cmp $b} keys %$i) {
				print "\t".$k."\t".$i->attr($k)."\n" if($k ne 'others' and $k ne 'subelements'  and $k ne 'id');
			}
			for my $j (sort {$a cmp $b} $i->subelements() ) {
				for my $k (sort {$a cmp $b} $i->subelement_fields($j) ) {
					print "\t".$j.">".$k."\t".$i->subelement_field($j,$k)."\n";
				}
			}
		}
	}
	
	return ($AssetRegistry, $ActivityRegistry, $ConstraintRegistry, $MultiperiodInserterRegistry, $MultiperiodReaderRegistry);
}
sub parse_string {
	my ($self, $string, $grammar, $what, $verbose) = @_;
	my $recognizer=  Marpa::R2::Scanless::R->new( { grammar => $grammar	} );
	
	eval {  local $SIG{__WARN__} = sub {};   $recognizer->read( \$string ); 1 };

	if ($@) {
		my $progress_report = $recognizer->show_progress( 0, -1 ) if $verbose;
		my $rep = "$@";
		my $s = index $rep, "*";

		my $p = index $rep, "Marpa::R2 exception";
		my $report = substr($rep, $s, $p);


		#print $progress_report;
		print STDERR "Error while parsing $what = $string \n";
		print STDERR $report;
		print STDERR $progress_report if $verbose;
		
		exit(1);
	}
	my $resultHash = $recognizer->value();
	if ( not defined $resultHash ) {
		die "String '$string' could not be parsed due to syntax error\n\n";
	}
	return $resultHash;
}
	
sub parse_file {
	my ($self, $filename, $grammar, $verbose) = @_;
	my $recognizer=  Marpa::R2::Scanless::R->new( { grammar => $grammar	} );
	
	#Open input file and slurp into string
	my $inString;
	{
		do { local $/ = undef;
			open (my $infile, "<", $filename) or croak( $! ."\n" . $filename."\n");
			$inString = <$infile>;
			close ($infile); 
		}
	}

	eval {  local $SIG{__WARN__} = sub {};   $recognizer->read( \$inString ); 1 };

	if ($@) {
		my $progress_report = $recognizer->show_progress( 0, -1 ) if $verbose;
		my $rep = "$@";
		my $s = index $rep, "*";

		my $p = index $rep, "Marpa::R2 exception";
		my $report = substr($rep, $s, $p);


		#print $progress_report;
		print STDERR "Error while parsing $filename\n";
		print STDERR $report;
		print STDERR $progress_report if $verbose;
		
		exit(1);
	}
	my $resultHash = $recognizer->value();
	if ( not defined $resultHash ) {
		die "$filename could not be parsed due to syntax error\n\n";
	}
	return $resultHash;
}
sub create_globals_and_configs_old {
	my ($self, $scenario, $dbh, $mpmasoff, $verbose, $parallelElems) = @_;

	my $needdbh = defined $dbh;
	
	delete $self->{GLOBALS};
	delete $self->{GLOBAL_SETS};
	delete $self->{CONFIG};
	delete $self->{TABLES};
	delete $self->{MPMAS_TABLES};
	delete $self->{SIMRUN_PARAMETERS};
	$self->{simrun_parameter_count} = 0;
	
	$self->{TABLES} = SimpleObjectRegistry->create();
	$self->{CONFIG} = dclone($self->{BASECONFIG});
	$self->{CONFIG}->{MPMASCHECKSOFF}  = $mpmasoff;
	
	$self->{SIMRUN_PARAMETERS}= {};


	#globals, simrun parameters 
	for my $i (@{$self->{AST_data} } ) {
		$i->transform($self, $scenario);
	}
	#configuration
	for my $i (@{$self->{AST_configuration} } ) {
		$i->transform($self, $scenario);
	}
	
	#user tables
	if( $parallelElems) {
		
		##need to disconnect parent and reconnect in each thread separately
		
		$dbh->disconnect() if (defined $needdbh);
		
		
		my @independent;
		my @dependent;
		
		for my $i (@{$self->{AST_tables}} ) {
				if (MpmasQLTableDefinition4->dependent_type($i->type())) {
					push @dependent, $i;
					#print "Dependent table ", $i->name, " identified\n";
				}
				else {
					push @independent , $i;
				}
		}
		
		my $iter = Parallel::Iterator::iterate( 
			{  adaptive => 1, 
				workers => $parallelElems}
				,
			sub { 
					my ( $id, $job ) = @_;
					my $dbh2 = $self->new_db_connection() if $needdbh;
					my @temp = $job->transform($self, $scenario, $dbh2, 1);
					$dbh2->disconnect() if (defined $needdbh);
					return \@temp;
			}
			, \@independent  
		);
        
		while ( my ( $index, $value ) = $iter->() ) {
				
			$self->{TABLES}->add_objects(@{$value});
			#print "Independent table: ", $_->id(),"\n" foreach @{$value};
		}
		
		$dbh = $self->new_db_connection() if $needdbh;
		
		for my $i (@dependent ) {
			#print "Dependent table: ", $i->name(),"\n";
			$i->transform($self, $scenario, $dbh);
		}
		
		
	}
	else {		
		for my $i (@{$self->{AST_tables} } ) {
			$i->transform($self, $scenario, $dbh);
		}
	}
	#mpmas tables
	if( $parallelElems) {	
		
		$dbh->disconnect() if (defined $needdbh);
		
		my $iter = Parallel::Iterator::iterate( 
			{  adaptive => 1, 
				workers => $parallelElems}
				,
			sub { 
					my ( $id, $job ) = @_;
					my $dbh2 = $self->new_db_connection() if $needdbh;
					my $temp = [ $job->transform($self, $scenario, $dbh2, 1) ];
					$dbh2->disconnect() if (defined $needdbh);

					return $temp;
			}
			, \@{$self->{AST_mas_tables} }
		);
        
		while ( my ( $index, $value ) = $iter->() ) {
			for (@{$value}) {
				$self->{MPMAS_TABLES}->{$_->id} = $_;
			}
		}
		$dbh = $self->new_db_connection() if $needdbh;

	}
	else {		
		for my $i (@{$self->{AST_mas_tables} } ) {
			$i->transform($self, $scenario, $dbh);
		}
	}
	#print "CONFIG 1:",Dumper(	$self->{CONFIG} ) if ($verbose);
	#print "MPMAS_TABLES 1:", Dumper(	$self->{MPMAS_TABLES} ) if ($verbose);

	return $dbh;	
}

sub create_globals_and_configs {
	my ($self, $scenario, $dbh, $mpmasoff, $verbose, $parallelElems) = @_;

	#my $needdbh = defined $dbh;
	my $mu = MpmasInputfile->getMemUsageObj();
	delete $self->{GLOBALS};
	delete $self->{GLOBAL_SETS};
	delete $self->{CONFIG};
	delete $self->{TABLES};
	delete $self->{MPMAS_TABLES};
	delete $self->{SIMRUN_PARAMETERS};
	$self->{simrun_parameter_count} = 0;
	
	$self->{TABLES} = SimpleObjectRegistry->create();
	$self->{CONFIG} = dclone($self->{BASECONFIG});
	$self->{CONFIG}->{MPMASCHECKSOFF}  = $mpmasoff;
	
	$self->{SIMRUN_PARAMETERS}= {};

	my $lasttime = time;
	#globals, simrun parameters , tables
	print "Timings for .dat entries:\n" if $logTime;
	for my $i (@{$self->{AST_data} } ) {## includes AST_tables now
		$i->transform($self, $scenario, $dbh);
			print $i->[0], ": " , (time - $lasttime), "\n" if $logTime;
			$lasttime=time if $logTime;
			$mu->record('after '. $i->[0] ) if logMem;
	}
	#configuration
	print "Timings for .cfg and .mas entries:\n" if $logTime;
	for my $i (@{$self->{AST_configuration} } ) {
		$i->transform($self, $scenario);
					print $i->[0], ": " , (time - $lasttime), "\n" if $logTime;
			$lasttime=time if $logTime;
			$mu->record('after '. $i->[0] ) if logMem;
	}
	#for my $i (@{$self->{AST_tables} } ) { ## AST_Tables now part of data
	#		$i->transform($self, $dbh, $scenario);
	#}
	print "Timings for .mas tables:\n" if $logTime;
	for my $i (@{$self->{AST_mas_tables} } ) {
		$i->transform($self, $scenario, $dbh);
		print $i->[0], ": " , (time - $lasttime), "\n" if $logTime;
		$lasttime=time if $logTime;
		$mu->record('after '. $i->[0] ) if logMem;
	}
	
	
	return $dbh;	
}



sub config_entry {
	return $_[0]->{CONFIG}->{$_[1]};
}

sub new_doc {
	my ($class, $filenameIni,  $setstrings, $verbosityflags) = @_;
	croak ("Error: new called from an object reference\n") if (ref($class)); 
	$setstrings = {} unless (defined $setstrings);
	
	# Make object
	my $self = {};	
	$self->{CONVERSION}->{mperiodIterator} = 't';
	
	my $temp = Hash::Merge::merge(dclone(\%MpmasQLRegistry::cfg_entries), dclone(\%MpmasQLRegistry::cfg_lists));
	$self->{BASECONFIG} = Hash::Merge::merge(dclone(\%MpmasQLRegistry::mpmas_parameters), $temp);
	$self->{BASECONFIG}->{MPMASQL3} = 1;
	$self->{BASECONFIG}->{Groupings}->{activity} = {};
	$self->{BASECONFIG}->{Groupings}->{constraint} = {};
	
	
	bless $self, $class;
	
	
	#Read and process ini file
	$self->new_ini($filenameIni, $setstrings, $verbosityflags->{VERBOSE_READINI});


	$self->{CHANGEABLE} = {};
	$self->{CHANGED} = {};

	#Read other model files and create Abstract syntax trees
#	print "\nModel configuration file:\t\t". $self->{INIHASH}->{CONFIGURATION}."\n";
#	$self->new_cfg($self->{INIHASH}->{CONFIGURATION}, $verbosityflags->{VERBOSE_READCFG});

#	print "Model data file:\t\t\t". $self->{INIHASH}->{DATA}."\n";
#	$self->new_data($self->{INIHASH}->{DATA}, $verbosityflags->{VERBOSE_READDATA});


#	print "Mpmas parameters file:\t\t\t". $self->{INIHASH}->{MAS_PARAMETERS}."\n";
#	$self->new_mas_param($self->{INIHASH}->{MAS_PARAMETERS}, $verbosityflags->{VERBOSE_READMAS});

	$self->{BASECONFIG}->{CONTYPEORDER} = $MpmasQLRegistry::CONSTRAINT_TYPES;
	$self->{BASECONFIG}->{ACTTYPEORDER} = $MpmasQLRegistry::ACTIVITY_TYPES;


	print "Decision model parameter file:\t\t". $self->{INIHASH}->{DECISION_PARAMETERS}."\n";
	print "Decision model file:\t\t\t". $self->{INIHASH}->{DECISION_MODEL}."\n";
	$self->new_mpm_prm_for_doc($self->{INIHASH}->{DECISION_MODEL}, $self->{INIHASH}->{DECISION_PARAMETERS}, $self->{BASECONFIG}, $verbosityflags->{VERBOSE_CLASS});

	#return $self;	
	return $self;	
}
sub new_mpm_prm_for_doc {
	my ($self, $filenameEqn, $filenamePrm, $baseconfigs, $verbose) = @_;
	$verbose = 0 unless (defined $verbose);
	
	
	#Create parser instance
	my $recognizer=  Marpa::R2::Scanless::R->new( { grammar => $grammarEqn	} );
	my $PrmRecognizer=  Marpa::R2::Scanless::R->new( { grammar => $grammarPrm	} );


	#Open input file and slurp into string
	my $eqnString;
	{
		do { local $/ = undef;
			open (my $infile, "<", $filenameEqn) or die $! ."\n" . $filenameEqn."\n";
			$eqnString = <$infile>;
			close ($infile); 
		}
	}
	
	#Open input file and slurp into string
	my $prmString;
	{
		do { local $/ = undef;
			open (my $infile2, "<", $filenamePrm) or die $! ."\n" . $filenamePrm."\n";
			$prmString = <$infile2>;
			close ($infile2); 
		}
	}


	#Parse input string to abstract syntax trees (AST)
	eval {  local $SIG{__WARN__} = sub {};   $recognizer->read( \$eqnString ); 1 };

	if ($@) {
		my $progress_report = $recognizer->show_progress( 0, -1 ) if $verbose;
		my $rep = "$@";
		my $s = index $rep, "*";

		my $p = index $rep, "Marpa::R2 exception";
		my $report = substr($rep, $s, $p);


		#print $progress_report;
		print STDERR "Error while parsing decision model in $filenameEqn\n";
		print STDERR $report;
		print STDERR $progress_report if $verbose;
		
		exit(1);
	}
	my $resultHash = $recognizer->value();
	if ( not defined $resultHash ) {
		die "$filenameEqn could not be parsed due to syntax error\n";
	}
	
	eval { local $SIG{__WARN__} = sub {};    $PrmRecognizer->read( \$prmString ); 1 };

	if ($@) {
		my $progress_report = $PrmRecognizer->show_progress( 0, -1 ) if $verbose;
		
		my $rep = "$@";
		my $s = index $rep, "*";

		my $p = index $rep, "Marpa::R2 exception";
		my $report = substr($rep, $s, $p);

		
		$report .= "\n";
		
	
		print STDERR "Error while parsing decision model parameters in $filenamePrm\n";
		print STDERR $report;
		print $progress_report if $verbose;
		exit(1);
	}
	my $PrmResultHash = $PrmRecognizer->value();
	if ( not defined $PrmResultHash ) {
		print STDERR "$filenamePrm could not be parsed due to syntax error\n";
		exit(1);
	}
	#	print Dumper($PrmResultHash);

	#print "1:", Dumper($baseconfigs->{CONTYPEORDER});

	

	$self->{parameterAndSetDefinitions} = $$PrmResultHash;
	$self->{mpmContentDefinitions} = $$resultHash;
	

}
sub make_doc {
	my ($self, $filename) = @_;
	my $out;
	open ($out , ">", $filename) or (print STDERR "Error when trying to open $filename:\n$!\n" and exit(1));
	
	print $out "\\begin{document}\n\\usepackage{amsmath}";
	
	for my $i (@{$self->{mpmContentDefinitions}}  ){
		my $latexString = $i->to_latex_string();
		print $out $latexString;
	}
	print $out "\\end{document}";
	
	close($out);
}

sub new_db_connection {
	my ($self) = @_;
	my $dbh;
	$dbh = DBI->connect("dbi:".$self->inihash()->{DBTYPE}.":". $self->inihash()->{DB}, $self->inihash()->{DBUSER}, $self->inihash()->{DBPWD}, { RaiseError => 1, AutoCommit => 1 }) or die $!;
			#print "Successfully connected to " . $self->inihash()->{DB} . " as ". $self->inihash()->{DBUSER} . "\n"; 
			$dbh->do("SET NAMES utf8");
		
	return $dbh;
}

my $oldcode = <<OLDCODE;
OLD_mpmasInsertExpressionCompoundMultiplicativeOld ::= 	

				 ('(') mpmasInsertExpressionCompound (')') assoc => group action => ::first
			   ||	pureMpmasInsertExpression	mpmasInsertExpressionOperatorE pureMpmasInsertExpression assoc => right   bless => mpmasInsertExpressionCompound
				|   ('(') mpmasInsertExpression (')') mpmasInsertExpressionOperatorE  pureMpmasInsertExpression  assoc => right   bless => mpmasInsertExpressionCompound
				|   pureMpmasInsertExpression mpmasInsertExpressionOperatorE ('(') mpmasInsertExpression (')')   assoc => right   bless => mpmasInsertExpressionCompound
			    |   ('(') mpmasInsertExpression (')')  mpmasInsertExpressionOperatorE ('(') mpmasInsertExpression (')')    assoc => right   bless => mpmasInsertExpressionCompound
				|   exponentiableExpression	mpmasInsertExpressionOperatorE pureMpmasInsertExpression assoc => right   bless => mpmasInsertExpressionCompound
				|   exponentiableExpression mpmasInsertExpressionOperatorE ('(') mpmasInsertExpression (')')   assoc => right   bless => mpmasInsertExpressionCompound
				|   pureMpmasInsertExpression	mpmasInsertExpressionOperatorE exponentiableExpression assoc => right   bless => mpmasInsertExpressionCompound
				|   ('(') mpmasInsertExpression (')') mpmasInsertExpressionOperatorE  exponentiableExpression  assoc => right   bless => mpmasInsertExpressionCompound

			    |    mpmasInsertExpressionCompoundMultiplicative  mpmasInsertExpressionOperatorE ('(') mpmasInsertExpression (')')    	   assoc => right   bless => mpmasInsertExpressionCompound
				|    mpmasInsertExpressionCompoundMultiplicative	 mpmasInsertExpressionOperatorE pureMpmasInsertExpression     assoc => right   bless => mpmasInsertExpressionCompound
		        |   ('(') mpmasInsertExpression (')')   mpmasInsertExpressionOperatorE   mpmasInsertExpressionCompoundMultiplicative    assoc => right   bless => mpmasInsertExpressionCompound
				|   pureMpmasInsertExpression	mpmasInsertExpressionOperatorE   mpmasInsertExpressionCompoundMultiplicative      assoc => right   bless => mpmasInsertExpressionCompound
				|    mpmasInsertExpressionCompoundMultiplicative 	mpmasInsertExpressionOperatorE exponentiableExpression     assoc => right   bless => mpmasInsertExpressionCompound
				|   exponentiableExpression	mpmasInsertExpressionOperatorE  mpmasInsertExpressionCompoundMultiplicative           assoc => right   bless => mpmasInsertExpressionCompound
			    |   mpmasInsertExpressionCompoundMultiplicative 	mpmasInsertExpressionOperatorE  mpmasInsertExpressionCompoundMultiplicative      assoc => right   bless => mpmasInsertExpressionCompound

				 
			   ||	pureMpmasInsertExpression	mpmasInsertExpressionOperatorM pureMpmasInsertExpression bless => mpmasInsertExpressionCompound
				|   ('(') mpmasInsertExpression (')') mpmasInsertExpressionOperatorM  pureMpmasInsertExpression  bless => mpmasInsertExpressionCompound
				|   pureMpmasInsertExpression mpmasInsertExpressionOperatorM ('(') mpmasInsertExpression (')')   bless => mpmasInsertExpressionCompound
			   	|   ('(') mpmasInsertExpression (')')  mpmasInsertExpressionOperatorM ('(') mpmasInsertExpression (')')    bless => mpmasInsertExpressionCompound
				|   multiplicativeExpression	mpmasInsertExpressionOperatorM pureMpmasInsertExpression   bless => mpmasInsertExpressionCompound
				|   pureMpmasInsertExpression	mpmasInsertExpressionOperatorM multiplicativeExpression    bless => mpmasInsertExpressionCompound
				|   ('(') mpmasInsertExpression (')') mpmasInsertExpressionOperatorM  multiplicativeExpression     bless => mpmasInsertExpressionCompound
				|   multiplicativeExpression mpmasInsertExpressionOperatorM ('(') mpmasInsertExpression (')')      bless => mpmasInsertExpressionCompound
			    	|   mpmasInsertExpressionCompoundMultiplicative  mpmasInsertExpressionOperatorM ('(') mpmasInsertExpression (')')    	bless => mpmasInsertExpressionCompound
				|   mpmasInsertExpressionCompoundMultiplicative	mpmasInsertExpressionOperatorM pureMpmasInsertExpression     bless => mpmasInsertExpressionCompound
				|   mpmasInsertExpressionCompoundMultiplicative	mpmasInsertExpressionOperatorM multiplicativeExpression       bless => mpmasInsertExpressionCompound
				|   multiplicativeExpression	mpmasInsertExpressionOperatorM mpmasInsertExpressionCompoundMultiplicative          bless => mpmasInsertExpressionCompound							
		        	|   ('(') mpmasInsertExpression (')')   mpmasInsertExpressionOperatorM   mpmasInsertExpressionCompoundMultiplicative     bless => mpmasInsertExpressionCompound
				|   multiplicativeMpmasInsertExpression	mpmasInsertExpressionOperatorM   mpmasInsertExpressionCompoundMultiplicative     bless => mpmasInsertExpressionCompound
			    	|   mpmasInsertExpressionCompoundMultiplicative	mpmasInsertExpressionOperatorM mpmasInsertExpressionCompoundMultiplicative           bless => mpmasInsertExpressionCompound
	
				|  pureMpmasInsertExpression mpmasInsertExpressionOperatorD pureMpmasInsertExpression bless => mpmasInsertExpressionCompound
				|   ('(') mpmasInsertExpression (')') mpmasInsertExpressionOperatorD  pureMpmasInsertExpression  bless => mpmasInsertExpressionCompound
				|   pureMpmasInsertExpression mpmasInsertExpressionOperatorD ('(') mpmasInsertExpression (')')   bless => mpmasInsertExpressionCompound
			   	|   ('(') mpmasInsertExpression (')')  mpmasInsertExpressionOperatorD ('(') mpmasInsertExpression (')')    bless => mpmasInsertExpressionCompound
				|   multiplicativeExpression	mpmasInsertExpressionOperatorD pureMpmasInsertExpression   bless => mpmasInsertExpressionCompound
				|   ('(') mpmasInsertExpression (')') mpmasInsertExpressionOperatorD  singleTermForInserter     bless => mpmasInsertExpressionCompound
				|   multiplicativeExpression mpmasInsertExpressionOperatorD ('(') mpmasInsertExpression (')')      bless => mpmasInsertExpressionCompound
			    	|   mpmasInsertExpressionCompoundMultiplicative  mpmasInsertExpressionOperatorD ('(') mpmasInsertExpression (')')    	bless => mpmasInsertExpressionCompound
				|   mpmasInsertExpressionCompoundMultiplicative	mpmasInsertExpressionOperatorD pureMpmasInsertExpression     bless => mpmasInsertExpressionCompound
				|   mpmasInsertExpressionCompoundMultiplicative	mpmasInsertExpressionOperatorD singleTermForInserter       bless => mpmasInsertExpressionCompound
				|   mpmasInsertExpressionCompoundMultiplicative  mpmasInsertExpressionOperatorD ('(') mpmasInsertExpressionCompound (')')    	bless => mpmasInsertExpressionCompound
				|   pureMpmasInsertExpression  mpmasInsertExpressionOperatorD ('(') mpmasInsertExpressionCompound (')')    	bless => mpmasInsertExpressionCompound
				|   multiplicativeExpression  mpmasInsertExpressionOperatorD ('(') mpmasInsertExpressionCompound (')')    	bless => mpmasInsertExpressionCompound
				|   ('(') mpmasInsertExpression (')')  mpmasInsertExpressionOperatorD ('(') mpmasInsertExpressionCompound (')')    	bless => mpmasInsertExpressionCompound
				|   ('(') mpmasInsertExpressionCompound (')')  mpmasInsertExpressionOperatorD ('(') mpmasInsertExpressionCompound (')')    	bless => mpmasInsertExpressionCompound






OLD_mpmasInsertExpressionCompound ::= 								 
			('(') mpmasInsertExpressionCompound (')') assoc => group action => ::first
		   ||	pureMpmasInsertExpression	mpmasInsertExpressionOperatorE pureMpmasInsertExpression assoc => right   bless => mpmasInsertExpressionCompound
			|   ('(') mpmasInsertExpression (')') mpmasInsertExpressionOperatorE  pureMpmasInsertExpression  assoc => right   bless => mpmasInsertExpressionCompound
			|   pureMpmasInsertExpression mpmasInsertExpressionOperatorE ('(') mpmasInsertExpression (')')   assoc => right   bless => mpmasInsertExpressionCompound
		    |   ('(') mpmasInsertExpression (')')  mpmasInsertExpressionOperatorE ('(') mpmasInsertExpression (')')    assoc => right   bless => mpmasInsertExpressionCompound
			|   exponentiableExpression	mpmasInsertExpressionOperatorE pureMpmasInsertExpression assoc => right   bless => mpmasInsertExpressionCompound
			|   exponentiableExpression mpmasInsertExpressionOperatorE ('(') mpmasInsertExpression (')')   assoc => right   bless => mpmasInsertExpressionCompound
			|   pureMpmasInsertExpression	mpmasInsertExpressionOperatorE exponentiableExpression assoc => right   bless => mpmasInsertExpressionCompound
			|   ('(') mpmasInsertExpression (')') mpmasInsertExpressionOperatorE  exponentiableExpression  assoc => right   bless => mpmasInsertExpressionCompound

		    |    mpmasInsertExpressionCompound  mpmasInsertExpressionOperatorE ('(') mpmasInsertExpression (')')    	   assoc => right   bless => mpmasInsertExpressionCompound
			|    mpmasInsertExpressionCompound	 mpmasInsertExpressionOperatorE pureMpmasInsertExpression     assoc => right   bless => mpmasInsertExpressionCompound
	        |   ('(') mpmasInsertExpression (')')   mpmasInsertExpressionOperatorE   mpmasInsertExpressionCompound    assoc => right   bless => mpmasInsertExpressionCompound
			|   pureMpmasInsertExpression	mpmasInsertExpressionOperatorE   mpmasInsertExpressionCompound      assoc => right   bless => mpmasInsertExpressionCompound
			|    mpmasInsertExpressionCompound 	mpmasInsertExpressionOperatorE exponentiableExpression     assoc => right   bless => mpmasInsertExpressionCompound
			|   exponentiableExpression	mpmasInsertExpressionOperatorE  mpmasInsertExpressionCompound           assoc => right   bless => mpmasInsertExpressionCompound
		    |   mpmasInsertExpressionCompound 	mpmasInsertExpressionOperatorE  mpmasInsertExpressionCompound      assoc => right   bless => mpmasInsertExpressionCompound


		   ||   mpmasInsertExpressionCompound	mpmasInsertExpressionOperatorM multiplicativeExpression       bless => mpmasInsertExpressionCompound
			|   multiplicativeExpression	mpmasInsertExpressionOperatorM mpmasInsertExpressionCompound          bless => mpmasInsertExpressionCompound							
			|   multiplicativeExpression	mpmasInsertExpressionOperatorM pureMpmasInsertExpression   bless => mpmasInsertExpressionCompound
			|   pureMpmasInsertExpression	mpmasInsertExpressionOperatorM multiplicativeExpression    bless => mpmasInsertExpressionCompound
			|   mpmasInsertExpressionCompound	mpmasInsertExpressionOperatorD singleTermForInserter       bless => mpmasInsertExpressionCompound
			|   multiplicativeExpression	mpmasInsertExpressionOperatorD pureMpmasInsertExpression   bless => mpmasInsertExpressionCompound
			|   pureMpmasInsertExpression	mpmasInsertExpressionOperatorD singleTermForInserter    bless => mpmasInsertExpressionCompound 
			|   mpmasInsertExpressionCompound	mpmasInsertExpressionOperatorD ('(') mpmasInsertExpressionCompound (')')       bless => mpmasInsertExpressionCompound
			|   multiplicativeExpression	mpmasInsertExpressionOperatorD ('(') mpmasInsertExpressionCompound (')')   bless => mpmasInsertExpressionCompound
			|   pureMpmasInsertExpression	mpmasInsertExpressionOperatorD ('(') mpmasInsertExpressionCompound (')')    bless => mpmasInsertExpressionCompound  
			 
			 
			 
			 
		   ||	pureMpmasInsertExpression	mpmasInsertExpressionOperatorM pureMpmasInsertExpression bless => mpmasInsertExpressionCompound
			|   ('(') mpmasInsertExpression (')') mpmasInsertExpressionOperatorM  pureMpmasInsertExpression  bless => mpmasInsertExpressionCompound
			|   pureMpmasInsertExpression mpmasInsertExpressionOperatorM ('(') mpmasInsertExpression (')')   bless => mpmasInsertExpressionCompound
		    	|   ('(') mpmasInsertExpression (')')  mpmasInsertExpressionOperatorM ('(') mpmasInsertExpression (')')    bless => mpmasInsertExpressionCompound

			|   ('(') mpmasInsertExpression (')') mpmasInsertExpressionOperatorM  multiplicativeExpression     bless => mpmasInsertExpressionCompound
			|   multiplicativeExpression mpmasInsertExpressionOperatorM ('(') mpmasInsertExpression (')')      bless => mpmasInsertExpressionCompound
		    	|   mpmasInsertExpressionCompound  mpmasInsertExpressionOperatorM ('(') mpmasInsertExpression (')')    	bless => mpmasInsertExpressionCompound
			|   mpmasInsertExpressionCompound	mpmasInsertExpressionOperatorM pureMpmasInsertExpression     bless => mpmasInsertExpressionCompound
	        	|   ('(') mpmasInsertExpression (')')   mpmasInsertExpressionOperatorM   mpmasInsertExpressionCompound     bless => mpmasInsertExpressionCompound
			|   pureMpmasInsertExpression	mpmasInsertExpressionOperatorM   mpmasInsertExpressionCompound     bless => mpmasInsertExpressionCompound
		    	|   mpmasInsertExpressionCompound	mpmasInsertExpressionOperatorM mpmasInsertExpressionCompound           bless => mpmasInsertExpressionCompound

			|pureMpmasInsertExpression	mpmasInsertExpressionOperatorD pureMpmasInsertExpression bless => mpmasInsertExpressionCompound
			|   ('(') mpmasInsertExpression (')') mpmasInsertExpressionOperatorD  pureMpmasInsertExpression  bless => mpmasInsertExpressionCompound
			|   pureMpmasInsertExpression mpmasInsertExpressionOperatorD ('(') mpmasInsertExpression (')')   bless => mpmasInsertExpressionCompound
		    	|   ('(') mpmasInsertExpression (')')  mpmasInsertExpressionOperatorD ('(') mpmasInsertExpression (')')    bless => mpmasInsertExpressionCompound

			|   ('(') mpmasInsertExpression (')') mpmasInsertExpressionOperatorD  singleTermForInserter     bless => mpmasInsertExpressionCompound
			|   multiplicativeExpression mpmasInsertExpressionOperatorD ('(') mpmasInsertExpression (')')      bless => mpmasInsertExpressionCompound
		    	|   mpmasInsertExpressionCompound  mpmasInsertExpressionOperatorD ('(') mpmasInsertExpression (')')    	bless => mpmasInsertExpressionCompound
			|   mpmasInsertExpressionCompound	mpmasInsertExpressionOperatorD pureMpmasInsertExpression     bless => mpmasInsertExpressionCompound


			|   ('(') mpmasInsertExpression (')') mpmasInsertExpressionOperatorD    ('(') mpmasInsertExpressionCompound (')')   bless => mpmasInsertExpressionCompound
			|   multiplicativeExpression mpmasInsertExpressionOperatorD ('(') mpmasInsertExpressionCompound (')')      bless => mpmasInsertExpressionCompound
		    	|   mpmasInsertExpressionCompound  mpmasInsertExpressionOperatorD ('(') mpmasInsertExpressionCompound (')')    	bless => mpmasInsertExpressionCompound
		  	|   pureMpmasInsertExpression  mpmasInsertExpressionOperatorD ('(') mpmasInsertExpressionCompound (')')    	bless => mpmasInsertExpressionCompound	




		   ||	mpmasInsertExpressionCompound	mpmasInsertExpressionOperatorA anyExpression       bless => mpmasInsertExpressionCompound
			|   anyExpression	mpmasInsertExpressionOperatorA mpmasInsertExpressionCompound          bless => mpmasInsertExpressionCompound
			|   anyExpression	mpmasInsertExpressionOperatorA pureMpmasInsertExpression   bless => mpmasInsertExpressionCompound
			|   pureMpmasInsertExpression	mpmasInsertExpressionOperatorA anyExpression    bless => mpmasInsertExpressionCompound
			
			|   mpmasInsertExpressionCompound	mpmasInsertExpressionOperatorS singleTermForInserter       bless => mpmasInsertExpressionCompound
			|   anyExpression	mpmasInsertExpressionOperatorS pureMpmasInsertExpression   bless => mpmasInsertExpressionCompound
			|   mpmasInsertExpressionCompound	mpmasInsertExpressionOperatorS ('(') mpmasInsertExpressionCompound (')')       bless => mpmasInsertExpressionCompound
			|   anyExpression	mpmasInsertExpressionOperatorS ('(') mpmasInsertExpressionCompound (')')    bless => mpmasInsertExpressionCompound

		   
		   ||	pureMpmasInsertExpression	mpmasInsertExpressionOperatorA pureMpmasInsertExpression bless => mpmasInsertExpressionCompound
			|   ('(') mpmasInsertExpression (')') mpmasInsertExpressionOperatorA  pureMpmasInsertExpression  bless => mpmasInsertExpressionCompound
			|   pureMpmasInsertExpression mpmasInsertExpressionOperatorA ('(') mpmasInsertExpression (')')   bless => mpmasInsertExpressionCompound
		    	|   ('(') mpmasInsertExpression (')')  mpmasInsertExpressionOperatorA ('(') mpmasInsertExpression (')')    bless => mpmasInsertExpressionCompound
		    
			|   ('(') mpmasInsertExpression (')') mpmasInsertExpressionOperatorA  anyExpression     bless => mpmasInsertExpressionCompound
			|   anyExpression mpmasInsertExpressionOperatorA ('(') mpmasInsertExpression (')')      bless => mpmasInsertExpressionCompound
			
		    	|   mpmasInsertExpressionCompound  mpmasInsertExpressionOperatorA ('(') mpmasInsertExpression (')')    	bless => mpmasInsertExpressionCompound
			|   mpmasInsertExpressionCompound	mpmasInsertExpressionOperatorA pureMpmasInsertExpression     bless => mpmasInsertExpressionCompound
	        	|   ('(') mpmasInsertExpression (')')   mpmasInsertExpressionOperatorA   mpmasInsertExpressionCompound     bless => mpmasInsertExpressionCompound
			|   pureMpmasInsertExpression	mpmasInsertExpressionOperatorA   mpmasInsertExpressionCompound     bless => mpmasInsertExpressionCompound
		    	|   mpmasInsertExpressionCompound	mpmasInsertExpressionOperatorA mpmasInsertExpressionCompound           bless => mpmasInsertExpressionCompound


			|	pureMpmasInsertExpression	mpmasInsertExpressionOperatorS pureMpmasInsertExpression bless => mpmasInsertExpressionCompound
			|   ('(') mpmasInsertExpression (')') mpmasInsertExpressionOperatorS  pureMpmasInsertExpression  bless => mpmasInsertExpressionCompound
			|   pureMpmasInsertExpression mpmasInsertExpressionOperatorS ('(') mpmasInsertExpression (')')   bless => mpmasInsertExpressionCompound
		    	|   ('(') mpmasInsertExpression (')')  mpmasInsertExpressionOperatorS ('(') mpmasInsertExpression (')')    bless => mpmasInsertExpressionCompound
		    
			|   ('(') mpmasInsertExpression (')') mpmasInsertExpressionOperatorS  singleTermForInserter     bless => mpmasInsertExpressionCompound
			|   anyExpression mpmasInsertExpressionOperatorS ('(') mpmasInsertExpression (')')      bless => mpmasInsertExpressionCompound
			
		    	|   mpmasInsertExpressionCompound  mpmasInsertExpressionOperatorS ('(') mpmasInsertExpression (')')    	bless => mpmasInsertExpressionCompound
			|   mpmasInsertExpressionCompound	mpmasInsertExpressionOperatorS pureMpmasInsertExpression     bless => mpmasInsertExpressionCompound
			|   pureMpmasInsertExpression	mpmasInsertExpressionOperatorS   singleTermForInserter     bless => mpmasInsertExpressionCompound
		    	|   mpmasInsertExpressionCompound	mpmasInsertExpressionOperatorS singleTermForInserter           bless => mpmasInsertExpressionCompound

			|   pureMpmasInsertExpression	mpmasInsertExpressionOperatorS   ('(') mpmasInsertExpressionCompound (')')     bless => mpmasInsertExpressionCompound
		    	|   mpmasInsertExpressionCompound	mpmasInsertExpressionOperatorS ('(') mpmasInsertExpressionCompound (')')           bless => mpmasInsertExpressionCompound
			|   ('(') mpmasInsertExpression (')') mpmasInsertExpressionOperatorS  ('(') mpmasInsertExpressionCompound (')')     bless => mpmasInsertExpressionCompound
			|   anyExpression mpmasInsertExpressionOperatorS ('(') mpmasInsertExpressionCompound (')')      bless => mpmasInsertExpressionCompound
			



							
mpmasInsertExpressionOperatorM ::= 	'*'  action => ::first
mpmasInsertExpressionOperatorD ::=	'/'  action => ::first

mpmasInsertExpressionOperatorS ::= 	'-'  action => ::first
mpmasInsertExpressionOperatorA ::=      '+'  action => ::first
		
mpmasInsertExpressionOperatorE ::= 	'^'  action => ::first
										



OLDCODE
1;




















