############### ### ALF API ### ############### sub ALF_ObjectMatch { local($object,$type,$name,$value) = @_; ### returns true if $type matches type($object) or rule($object), $name matches name($object), and $value matches value($object). Returns false otherwise print("# ALF Data Info: trying to match type \47$type\47, name \47$name\47, and value \47$value\47 against candidate:\t",&ALF_ObjectInfoText($object),"\n") if ($ALF_Debug > 1); local $typematch = $type? ( &StringMatch($type,$ALF_Type{$object}) && ($ALF_Debug < 2 || print("# ALF Data Info:\ttype of object $object matches \47$type\47\n")) || &ALF_SyntaxMatch($type,$ALF_Type{$object},$ALF_Parent{$object}) && ($ALF_Debug < 2 || print("# ALF Data Info:\tsyntax rule for object $object matches \47$type\47\n")) ) : 1; local $namematch = defined($name)? ( ($name eq '0')? !$ALF_Name{$object} # object must not have a name && ($ALF_Debug < 2 || print("# ALF Data Info:\tname \47",$ALF_Name{$object},"\47 of object $object is false\n")) : ($name eq '1')? $ALF_Name{$object} # object must have a name && ($ALF_Debug < 2 || print("# ALF Data Info:\tname \47",$ALF_Name{$object},"\47 of object $object is true\n")) : &StringMatch($name,$ALF_Name{$object}) # object must have a matching name && ($ALF_Debug < 2 || print("# ALF Data Info:\tname \47",$ALF_Name{$object},"\47 of object $object matches \47$name\47\n")) ) : 1; local $valuematch = defined($value)? ( &StringMatch($value,$ALF_Value{$object}) && ($ALF_Debug < 2 || print("# ALF Data Info:\tvalue \47",$ALF_Value{$object},"\47 of object $object matches string \47$value\47\n")) # try string match || &ALF_LexicalMatch('number',$value) && &ALF_LexicalMatch('number',$ALF_Value{$object}) && ($value == $ALF_Value{$object}) && ($ALF_Debug < 2 || print("# ALF Data Info:\tvalue \47",$ALF_Value{$object},"\47 of object $object matches number \47$value\47\n")) # try numerical match || &ArraySize($ALF_Value{$object}) && &StringMatch($value,&Array($ALF_Value{$object})) && ($ALF_Debug < 2 || print("# ALF Data Info:\tvalue set (",join(' ',&Array($ALF_Value{$object})),") of object $object matches string \47$value\47\n")) # try multivalue match ) : 1; $typematch && $namematch && $valuematch; } sub ALF_ObjectQualifierMatch { local($object,%qualifier) = @_; ### returns true if annotations of $object match key-value pairs in %qualifier local @keys = keys %qualifier; print("# ALF Data Info: trying to match qualifiers (",join(' ',%qualifier),") against candidate ",&ALF_ObjectInfoText($object),"\n") if (($ALF_Debug > 1) && ($#keys >= 0)); #print("ALF_ObjectQualifierMatch:\t",&ALF_ObjectInfoText($object),"\tqualifiers=(",join(' ',%qualifier),")\n"); local $match = 1; foreach $key (@keys) { local ($key1,@key2) = (split(/\./,$key)); local $index = 0; local $qualifier = $object; while ($key2[$index] && $match) { #print("ALF_ObjectQualifierMatch: key1=$key1\n"); $qualifier = &ALF_FindMatchingObject($qualifier,$key1); $match = $match && $qualifier; $key1 = $key2[$index]; $index += 1; } #print("ALF_ObjectQualifierMatch: qualifier{$key1}=",$qualifier{$key},"\n"); local $qualifier = &ALF_FindMatchingObject($qualifier,$key1,0,$qualifier{$key}); $match = $match && $qualifier; #print("ALF_ObjectQualifierMatch: match=$match\n"); last unless $match; } $match; } sub ALF_FindMatchingObjects { local($parent,$type,$name,$value,%qualifier) = @_; ### examines children($parent) and returns a list of those children (possibly none) for which $type, $name, $value and %qualifier match local @found; foreach $child (&Array($ALF_Children{$parent})) { if (&ALF_ObjectMatch($child,$type,$name,$value) && &ALF_ObjectQualifierMatch($child,%qualifier)) { $found[$#found+1] = $child; print("# ALF Data Info:\tfound object:\t",&ALF_ObjectInfoText($child, keys %qualifier),"\n") if ($ALF_Debug > 1); } } @found; } sub ALF_FindMatchingObject { local($parent,$type,$name,$value,%qualifier) = @_; ### examines children($parent) and returns the first child (possibly none) for which $type, $name, $value and %qualifier match local $found; foreach $child (&Array($ALF_Children{$parent})) { if (&ALF_ObjectMatch($child,$type,$name,$value) && &ALF_ObjectQualifierMatch($child,%qualifier)) { $found = $child; print("# ALF Data Info:\tfound object:\t",&ALF_ObjectInfoText($child, keys %qualifier),"\n") if ($ALF_Debug > 1); } last if $found; } $found; } sub ALF_FindAncestor { local($object,$type,$name,$value,%qualifier) = @_; ### examines parent(object), parent(parent(object)) etc. until parent found (or not) for which $type, $name, $value and %qualifier match local $found; local $parent = $object; until (! $parent || $found) { $parent = $ALF_Parent{$parent}; $found = &ALF_ObjectMatch($parent,$type,$name,$value) && &ALF_ObjectQualifierMatch($parent,%qualifier); } $found? $parent : undef; } sub ALF_DefineBus { local($object,$index1,$index2) = @_; ### attaches $index1,$index2 to $object. Returns true $ALF_1stIndex{$object} = $index1 if defined($index1); $ALF_2ndIndex{$object} = $index2 if defined($index2); 1; } sub ALF_DefineTableFormat { local($table) = @_; ### defines arrayformat, keys, keytable, and keyoffset for value($table). Returns true local $header = &ALF_FindMatchingObject($ALF_Parent{$table},'HEADER'); if ($header) { local @keys = &Array($ALF_Children{$header}); local $keytable_0 = &ALF_FindMatchingObject($keys[0],'TABLE'); local $keyformat = $ALF_ArrayFormat{$ALF_Value{$keytable_0}}; local $array = $ALF_Value{$table}; local $actual = &ArraySize($array); $ALF_ArrayFormat{$array} = ($keyformat)? $keyformat : ($#keys > 0)? &ArraySize($ALF_Value{$keytable_0}) : 0; local (%keyid,%keytable,%keyoffset); $keyoffset{$keys[0]} = 1; local $tablesize; for $i (0..$#keys) { local $key = $keys[$i]; local $name = $ALF_Name{$key}; $keyid{$key} = &UpperCase($name? $name : $ALF_Type{$key}); local $keytable_i = &ALF_FindMatchingObject($key,'TABLE'); $keytable{$key} = $ALF_Value{$keytable_i}; $keyoffset{$key} = $keyoffset{$keys[$i-1]}*$tablesize if ($i>0); $tablesize = &ArraySize($ALF_Value{$keytable_i}); if ($i == $#keys) { local $expected = $keyoffset{$key}*$tablesize; print ("# ALF Data Error:\tinvalid number of entries in table $table (expected = $expected, actual = $actual): ",&ALF_ObjectInfoText($table),"\n") unless ($expected == $actual); } } $ALF_Keys{$array} = &CreateArray(@keys); $ALF_KeyId{$array} = &CreateAssoc(%keyid); $ALF_KeyTable{$array} = &CreateAssoc(%keytable); $ALF_KeyOffset{$array} = &CreateAssoc(%keyoffset); } 1; } sub ALF_DefineEquationFormat { local($equation) = @_; local $header = &ALF_FindMatchingObject($ALF_Parent{$equation},'HEADER'); if ($header) { local @keys = &Array($ALF_Children{$header}); local (%keytable,%keyid); foreach $key (@keys) { local $name = $ALF_Name{$key}; $keyid{$key} = &UpperCase($name? $name : $ALF_Type{$key}); local $keytable = &ALF_FindMatchingObject($key,'TABLE'); $keytable{$key} = $ALF_Value{$keytable} if $keytable; } local $array = $ALF_Value{$equation}; $ALF_Keys{$array} = &CreateArray(@keys); $ALF_KeyId{$array} = &CreateAssoc(%keyid); $ALF_KeyTable{$array} = &CreateAssoc(%keytable); } 1; } sub ALF_SyntaxMatch { local ($rule,$type,$parent) = @_; ### returns true if $rule matches type($parent).$type or rule(type($parent)).$type or type($parent).identifier or $type. Returns false otherwise $type = &UpperCase($type); local $parent_type = &UpperCase($ALF_Type{$parent}); local $context_type = join('.',$parent_type,$type); local $metacontext_type = join('.',&UpperCase($ALF_SyntaxRule{$parent_type}),$type); local $context_metatype = join('.',$parent_type,'identifier'); print("# ALF Syntax Info:\tevaluating rule \47$rule\47 for \47$type\47 or \47$context_type\47 or \47$metacontext_type\47 or \47$context_metatype\47\n") if ($ALF_Debug > 1); $ALF_SyntaxRule{$context_type}? &StringMatch($rule,$ALF_SyntaxRule{$context_type}) : $ALF_SyntaxRule{$metacontext_type}? &StringMatch($rule,$ALF_SyntaxRule{$metacontext_type}) : $ALF_SyntaxRule{$context_metatype}? &StringMatch($rule,$ALF_SyntaxRule{$context_metatype}) : &StringMatch($rule,$ALF_SyntaxRule{$type}); } sub ALF_DefineKeywordRule { local($object) = @_; ### creates the database representation for a rule embodied in $object with type($object)=KEYWORD. Returns true local $keyname = &UpperCase($ALF_Name{$object}); local $keyval = &LowerCase($ALF_Value{$object}); local $context = &ALF_FindMatchingObject($object,'CONTEXT'); if ($context) { local $contextval = $ALF_Value{$context}; local @cval = &ArraySize($contextval)? &Array($contextval) : ($contextval); foreach $cval (@cval) { local $key = &UpperCase($cval)."\.$keyname"; local $existing = $ALF_SyntaxRule{$key}; if (defined($existing)) { if ($existing ne $keyval) { print("# ALF Syntax Warning:\trule \47$key\47 will be changed from \47$existing\47 to \47$keyval\47\n"); } else { print("# ALF Syntax Info:\trule \47$key\47 = \47$existing\47 will be reaffirmed\n") if $ALF_Debug; } } $ALF_SyntaxRule{$key} = $keyval; print("# ALF Syntax Info:\tdefined rule \47$key\47 = \47$keyval\47 based on KEYWORD declaration\n") if $ALF_Debug; } } else { local $existing = $ALF_SyntaxRule{$keyname}; if (defined($existing)) { if ($existing ne $keyval) { print("# ALF Syntax Warning:\trule \47$keyname\47 will be changed from \47$existing\47 to \47$keyval\47\n"); } else { print("# ALF Syntax Info:\trule \47$keyname\47 = \47$existing\47 will be reaffirmed\n") if $ALF_Debug; } } $ALF_SyntaxRule{$keyname} = $keyval; print("# ALF Syntax Info:\tdefined rule \47$keyname\47 = \47$keyval\47 based on KEYWORD declaration\n") if $ALF_Debug; } 1; } sub ALF_DefineTemplateRule { local($template) = @_; ### creates the database representation for a rule embodied in $template with type($template)=TEMPLATE. Returns true local $key = &UpperCase($ALF_Name{$template}); $ALF_SyntaxRule{$key} = 'template_instantiation'; print("# ALF Syntax Info:\tdefined rule \47$key\47 = \47template\_instantiation\47 based on TEMPLATE declaration $template ",&ALF_ObjectInfoText($template),"\n") if $ALF_Debug; $ALF_AssignmentList{$template} = &ALF_AppendPlaceholderList(&CreateArray(),$template); $ALF_Reference{$key} = $template; 1; } sub ALF_AppendPlaceholderList { local($array,$object) = @_; ### looks for any placeholder in $object, appends and returns $array local ($parent,$type,$name,$value,$children) = &ALF_ObjectInfo($object); local @index = (); foreach $index (&ALF_BusInfo($object)) { $index =~ s/[\[\[]//g; foreach $item(split(/\:/,$index)) { $index[$#index+1] = $item; } } foreach $item ($type,$name,$value,@index) { &ALF_AddNewPlaceholder($array,$item); } if ($children) { foreach $child (&Array($children)) { &ALF_AppendPlaceholderList($array,$child); } } elsif (defined($value) && &ArraySize($value)) { $ALF_ArrayCopy{$value} = 1; foreach $item (&Array($value)) { &ALF_AddNewPlaceholder($array,$item); } } $array; } sub ALF_AddNewPlaceholder { local($array,$item) = @_; ### adds $item to $array if $item is a placeholder and not already member of $array. Returns false otherwise local $new; &ALF_LexicalMatch('placeholder_identifier',$item) && $item =~ s/[\<\>]//g && ($new = &UpperCase($item)) && ! defined(&FindArrayKey($array,$new)) && &AppendArray($array,$new) && $new; } sub ALF_DefineReferenceRule { local ($object,$rule) = @_; ### creates the database representation for a rule embodied in $object with type(parent($object))=instantiation. Returns true local $type = &UpperCase($ALF_Type{$object}); local $reference = $ALF_Reference{$type}; foreach $item (&Array($ALF_AssignmentList{$reference})) { local $key = $type."\.$item"; print("# ALF Syntax Info:\tdefined rule \47$key\47 = \47$rule\47 based on instantiation of reference $reference with ",&ALF_ObjectInfoText($reference),"\n") if $ALF_Debug; $ALF_SyntaxRule{$key} = $rule; } 1; } sub ALF_DefineDynamicTemplateRule { local ($object) = @_; ### creates the database representation for a rule embodied in $object with type(parent($object))=instantiation. Returns true local $type = &UpperCase($ALF_Type{$object}); local $reference = $ALF_Reference{$type}; foreach $item (&Array($ALF_AssignmentList{$reference})) { local $key = "HEADER\.$item"; print("# ALF Syntax Info:\tdefined rule \47$key\47 = \47dynamic_template_instantiation_item\47 based on instantiation of reference $reference with ",&ALF_ObjectInfoText($reference),"\n") if $ALF_Debug; $ALF_SyntaxRule{$key} = 'dynamic_template_instantiation_item'; } 1; } sub ALF_ExpandRange { local($value) = @_; ### returns a list of values based on $value, where $value is a pointer to either a range or a list of values. Example: result for (7 : 4) is (7 6 5 4), result for (1 2 3) is (1 2 3) local @values; local @val = &Array($value); if ($val[1] eq ':' && $#val==2) { if ($val[2] < $val[0]) { for $i (reverse $val[2]..$val[0]) { $values[$#values+1] = $i; } } else { for $i ($val[0]..$val[2]) { $values[$#values+1] = $i; } } } else { @values = @val; } #print("GetRangeValues:\t(@values)\n"); @values; } sub ALF_FindMatchingPattern { local($expression,$pattern) = @_; ### returns true if matching $pattern is found in $expression local $found = 0; foreach $item(split(/\s+/,$expression)) { if (&ALF_LexicalMatch('indexed_identifier',$item)) { foreach $subitem (split(/[\[:\]]/,$item)) { $found = &StringMatch($subitem,$pattern); #print("\tsubitem=$subitem\tfound=$found\n"); last if $found; } } elsif (&ALF_LexicalMatch('atomic_identifier',$item)) { $found = &StringMatch($item,$pattern); #print("\titem=$item\tfound=$found\n"); } last if $found; } $found; } sub ALF_DefineMemberList { local ($object) = @_; ### creates and returns a pointer to memberlist($object) local $index = $ALF_1stIndex{$object}; $name = &UpperCase($ALF_Name{$object}); $index =~ s/[\[\]]//g; local ($left,$right) = split(/\:/,$index); local @index = &ALF_ExpandRange(&CreateArray($left,':',$right)); local $member = &ALF_FindMatchingObject($object,'MEMBERS'); local @member = &Array($ALF_Value{$member}); print("# ALF Data Error:\tobject $object ",&ALF_ObjectInfoText($object)," has subscript out of range. Indices=(@index), Members=(@member)\n") unless ($#member == $#index); local %member; for $i (0..$#index) { $member{$name.'['.$index[$i].']'} = $member[$i]; } print("ALF Data Info: object $object has memberlist (",join(' ',%member),")\n") if $ALF_Debug; $ALF_MemberList{$object} = &CreateAssoc(%member); } ### control statement ### sub ALF_CreateControlStatement { local($parent,$trigger,%assignment) = @_; local $statement = &ALF_CreateObject($parent,'@',"( $trigger )"); foreach $key (keys %assignment) { &ALF_CreateObject($statement,$key,undef,$assignment{$key}) if length($key); } $statement; } ### general expression semantics ### sub ALF_FindItem { local(*expression,$wanted) = @_; local $found; foreach $item (@expression) { local ($data) = &ALF_ExpressionData($item); $found = &StringMatch($data,$wanted); last if $found; } $found; } ### arithmetic model identification ### sub ALF_IsFullArithmeticModel { local($object,$bodytype,@modeltypes) = @_; local $header = &ALF_FindMatchingObject($object,'HEADER'); local $body = &ALF_FindMatchingObject($object,$bodytype); $header && $body && (!defined(@modeltypes) || &StringMatch($ALF_Type{$object},@modeltypes)); } sub ALF_ArithmeticModelMatch { local($array,$array2,$bodytype) = @_; local @keys = &Array($ALF_Keys{$array}); local @keys2 = &Array($ALF_Keys{$array2}) if $array2; local $match = 0; if ($array2 && ($#keys==$#keys2) && (&ArraySize($array)==&ArraySize($array2))) { $match = 1; for $i (0..$#keys) { last unless $match; local $key = $keys[$i]; local $key2 = $keys2[$i]; $match = $match && &StringMatch($ALF_Type{$key},$ALF_Type{$key2}) &&( &StringMatch($bodytype,'TABLE') && &AssocVal($ALF_KeyOffset{$array},$key) == &AssocVal($ALF_KeyOffset{$array2},$key2) || &StringMatch($bodytype,'EQUATION') && &AssocVal($ALF_KeyId{$array},$key) eq &AssocVal($ALF_KeyId{$array2},$key2) ); } } $match; } sub ALF_FindArithmeticModelTableTemplates { local($arithmetic_models,$template_list) = @_; local %arithmetic_model_template; foreach $object (&Array($arithmetic_models)) { local $array = $ALF_Value{&ALF_FindMatchingObject($object,'TABLE')}; local $key = &FindArrayKey($template_list,$object); unless (defined($key)) { local $match = 0; foreach $object2 (&Array($template_list)) { local $array2 = $ALF_Value{&ALF_FindMatchingObject($object2,'TABLE')}; $match = $object2 if &ALF_ArithmeticModelMatch($array,$array2,'TABLE'); last if $match; } if ($match) { $arithmetic_model_template{$object} = $match; } else { &AppendArray($template_list,$object); } } } %arithmetic_model_template; } ############################################ ### little helpers for data substitution ### ############################################ sub ALF_DefineReplacement { local($reference,$object,$open,$close) = @_; ### creates and returns an associative array with keys based on assignment($reference) and values based on children($object). Adds prefix $open and postfix $close to each key local %replacement; foreach $item (&Array($ALF_AssignmentList{$reference})) { local $map = &ALF_FindMatchingObject($object,$item); $replacement{$open.$item.$close} = $ALF_Value{$map}; } print("# ALF Data Info:\treplacement for items in $reference based on $object:\t",join(' ',%replacement),"\n") if $ALF_Debug; %replacement; } sub ALF_ReplaceItem { local ($item,%replacement) = @_; ### returns a replacement of $item containing any matching value in %replacement, else returns original $item &ALF_LexicalMatch('identifier',$item)? &ALF_ReplaceIdentifier($item,%replacement) : &ALF_LexicalMatch('index',$item)? &ALF_ReplaceIndex($item,%replacement) : &ALF_Replace($item,%replacement); } sub ALF_ReplaceIdentifier { local($identifier,%replacement) = @_; ### returns a replacement of $identifier containing any matching value in %replacement, else returns original $identifier local $replacement; if (&ALF_LexicalMatch('indexed_identifier',$identifier)) { local ($atomic_identifier,$index) = split(/\[/,$item); $replacement = &ALF_Replace($atomic_identifier,%replacement).&ALF_ReplaceIndex($index,%replacement); } else { $replacement = &ALF_Replace($identifier,%replacement); } $replacement; } sub ALF_ReplaceIndex { local($index,%replacement) = @_; ### returns a replacement of $index containing any matching value in %replacement, else returns original $index $index =~ s/[\[\]]//g; local ($left,$right) = split(/\:/,$index); $left = &ALF_Replace($left, %replacement); $right = &ALF_Replace($right,%replacement) if defined($right); defined($right)? '['.$left.':'.$right.']' : '['.$left.']'; } sub ALF_Replace { local ($item,%replacement) = @_; ### returns case-insensitive $replacement{$item}, else returns $item local $replacement = $replacement{&UpperCase($item)}; defined($replacement)? $replacement : $item; } ########################## ### object replication ### ########################## sub ALF_CopyObject { local($original,$newparent,%case_sensitive_replacement) = @_; ### creates and returns a copy of $original, where parent(copy) will be $newparent. Items defined by %replacement (e.g. name(copy), value(copy)), if any, will be replaced. local %replacement; foreach $key (keys %case_sensitive_replacement) { $replacement{&UpperCase($key)} = $case_sensitive_replacement{$key}; } local ($parent,$type,$name,$value,$children) = &ALF_ObjectInfo($original); # define type for copy local $newtype = &ALF_Replace($type,%replacement); # define name for copy local @name; foreach $item (split(/\s+/,$name)) { $name[$#name+1] = &ALF_ReplaceItem($item,%replacement); } local $newname = join(' ',@name); # define value for copy local $newvalue; if (defined($value) && $ALF_ArrayCopy{$value} && &ArraySize($value)) { local @value; foreach $item (&Array($value)) { local $newitem = &ALF_Replace($item,%replacement); local $newsize = &ArraySize($newitem); if ($newsize) { for $i (0..$newsize-1) { $value[$#value+1] = &ArrayVal($newitem,$i); } } else { $value[$#value+1] = $newitem; } } $newvalue = &CreateArray(@value); } elsif (defined($value)) { $newvalue = &ALF_ReplaceItem($value,%replacement); } # copy relevant associative array entries $ALF_ArrayFormat{$newvalue} = $ALF_ArrayFormat{$value}; $ALF_ArrayCopy{$newvalue} = $ALF_ArrayCopy{$value}; # define index1, index2 for copy local @newindex; foreach $index (&ALF_BusInfo($original)) { $newindex[$#newindex+1] = &ALF_ReplaceIndex($index,%replacement); } # create copy of original local $copy = ($newparent eq $ALF_Parent{$original}) ? &ALF_InsertObject($original,$newtype,$newname,$newvalue) : &ALF_CreateObject($newparent,$newtype,$newname,$newvalue); print("# ALF Data Info:\tobject $copy is copy of object $original:\t",&ALF_ObjectInfoText($original),"\n") if $ALF_Debug; &ALF_DefineBus($copy,@newindex); $ALF_Original{$copy} = $original; # copy relevant associative array entries $ALF_Expression{$copy} = $ALF_Expression{$original}; $ALF_Hidden{$copy} = $ALF_Hidden{$original}; $ALF_Unlink{$copy} = $ALF_Unlink{$original}; # create copy of original's children if ($children) { $ALF_Children{$copy} = &CreateArray(); foreach $child (&Array($children)) { &ALF_CopyObject($child,$copy,%replacement); } } &ALF_DefineTableFormat($copy) if $ALF_Keys{$value}; $copy; } ############################## ### template_instantiation ### ############################## sub ALF_FlattenTemplateInstantiation { local ($object) = @_; ### replaces $object with a set of objects defined in reference($object), where type(reference($object))=TEMPLATE. Returns the set of objects print("# ALF Message:\tflattening template instantiation:\t",&ALF_ObjectInfoText($object),"\n"); local $type = &UpperCase($ALF_Type{$object}); local $reference = $ALF_Reference{$type}; print("# ALF Data Info:\treference for object $object:\t",&ALF_ObjectInfoText($reference),"\n") if $ALF_Debug; local %replacement = &ALF_DefineReplacement($reference,$object,'<','>'); local @new; foreach $child (&Array($ALF_Children{$reference})) { $new[$#new+1] = &ALF_CopyObject($child,$ALF_Parent{$object},%replacement); } @new; } ############# ### GROUP ### ############# sub ALF_ExpandGroups { local($object,$which,$groups,%replacement) = @_; ### recursively creates copies of $object based on a list of objects of type GROUP, where $groups is a pointer to the list, $which is a pointer to a member of the list. Items in %replacement will be replaced in the copy. Returns true. local $objectname = $ALF_Name{$object}; local $group = &ArrayVal($groups,$which); local $groupname = $ALF_Name{$group}; local $groupvalue = $ALF_Value{$group}; #print("ExpandGroups:\tobject=$object\tobjectname=$objectname\tgroup=$group\tgroupname=$groupname\treplacement=(",join(' ',%replacement),")\n"); if ($which < 0) { local @test = keys %replacement; if ($test[0]) { #foreach $key (keys %replacement) { local $val=$replacement{$key}; print("ExpandGroups:\treplacing $key with $val\n"); } local $copy = &ALF_CopyObject($object,$ALF_Parent{$object},%replacement); $ALF_Hidden{$copy} = 0; } } elsif (&ALF_FindMatchingPattern($objectname,$groupname)) { $ALF_Hidden{$object} = 1; #print("ExpandGroups:\tidentified group named $groupname in object named $objectname\n"); foreach $value (&ALF_ExpandRange($groupvalue)) { $replacement{&UpperCase($groupname)} = $value; &ALF_ExpandGroups($object,$which-1,$groups,%replacement); } } else { &ALF_ExpandGroups($object,$which-1,$groups,%replacement); } 1; } ################ ### PINGROUP ### ################ sub ALF_ReplacePingroupReference { local ($object,@pingroups) = @_; ### recursively replaces name and/or value of object based on memberlist(pingroup), where @pingroup is a list of objects of type PINGROUP local $newname = $ALF_Name{$object}; local $newvalue = $ALF_Value{$object}; foreach $pingroup (@pingroups) { local %member = &Assoc($ALF_MemberList{$pingroup}); local @name; foreach $item (split(/\s+/,$newname)) { $name[$#name+1] = &ALF_Replace($item,%member); } $newname = join(' ',@name); local @value; foreach $item (split(/\s+/,$newvalue)) { $value[$#value+1] = &ALF_Replace($item,%member); } $newvalue = join(' ',@value); #print("ALF_ReplacePingroupReference:\t",&ALF_ObjectInfoText($object),"\tpingroup=$pingroup\tnewname=$newname\tnewvalue=$newvalue\n"); } if ($newname ne $ALF_Name{$object}) { print ("# ALF Data Info:\tObject $object gets new name $newname based on pingroup reference\n") if $ALF_Debug; $ALF_Name{$object} = $newname; } if ($newvalue ne $ALF_Value{$object}) { print ("# ALF Data Info:\tObject $object gets new value $newvalue based on pingroup reference\n") if $ALF_Debug; $ALF_Value{$object} = $newvalue; } foreach $child (&Array($ALF_Children{$object})) { &ALF_ReplacePingroupReference($child,@pingroups); } 1; } ############### ### INCLUDE ### ############### sub ALF_ProcessIncludedFile { local ($object) = @_; local $file = &Unquote($ALF_Name{$object}); local $environment = $ALF_Parent{$object}; if (-r $file) { $ALF_Hidden{$object} = 'compiled'; local $firsttoken = $#ALF_ParserData + 1; $ALF_FirstLine{$environment} = &ALF_CurrentLineNumber($firsttoken); $ALF_ParserData[$firsttoken] = undef; local $save = $ALF_CurrentDataBase; $ALF_CurrentDataBase = $environment; &FileIn($file,'ALF_ReadLexical'); &ALF_CreateData($environment); $ALF_CurrentDataBase = $save; } else { print("# ALF Data Error:\tnon-readable file specified:\t",&ALF_ObjectInfoText($object),"\n"); } 1; } ######### ######### sub ALF_FlattenObject { local ($object) = @_; foreach $child (&ALF_FindMatchingObjects($object,'template_instantiation')) { $ALF_Hidden{$child} = 1; &ALF_FlattenTemplateInstantiation($child); } local $groups = &CreateArray(&ALF_FindMatchingObjects($ALF_Parent{$object},'GROUP')); &ALF_ExpandGroups($object,&ArraySize($groups)-1,$groups); foreach $child (&ALF_FindMatchingObjects($object,'template'),&ALF_FindMatchingObjects($object,'group')) { $ALF_Hidden{$child} = 1; } local @pingroups = &ALF_FindMatchingObjects($object,'PINGROUP'); foreach $pingroup(@pingroups) { &ALF_DefineMemberList($pingroup); } foreach $child (&Array($ALF_Children{$object})) { &ALF_ReplacePingroupReference($child,@pingroups); local $type = $ALF_Type{$child}; &ALF_FlattenObject($child) if (&StringMatch($ALF_SyntaxRule{$type},'library_specific_object') || &StringMatch($type,'TEMPLATE')); } } sub ALF_CheckReferences { local($object,$ancestor,@semantics) = @_; local $type = $ALF_Type{$object}; local $value = $ALF_Value{$object}; if (&ALF_LexicalMatch('identifier',$value)) { # local $semantics = &ALF_SearchForObject($root,'ALF_ObjectMatch','SEMANTICS',$type); # local $reftype = &ALF_FindMatchingObject($semantics,'REFERENCETYPE'); local $reftype; foreach $semantics (@semantics) { if (&StringMatch($ALF_Name{$semantics},$type)) { $reftype = &ALF_FindMatchingObject($semantics,'REFERENCETYPE'); last; } } if ($reftype) { local $reftypeval = $ALF_Value{$reftype}; local @reftypevalue = &ArraySize($reftypeval)? &Array($reftypeval) : ($reftypeval); local $reference; foreach $reftypevalue (@reftypevalue) { $reference = &ALF_SearchForObject($ancestor,'ALF_ObjectMatch',$reftypevalue,$value); if (defined($reference)) { $ALF_Link{$object} = $reference; print("# ALF Data Info:\tfound reference for object $object:\t",&ALF_ObjectInfoText($reference),"\n") if $ALF_Debug; last; } } } } else { foreach $child (&Array($ALF_Children{$object})) { &ALF_CheckReferences($child,$ancestor,@semantics); } } } sub ALF_HasReferenceType { local($object) = @_; &StringMatch($ALF_Type{$object},'SEMANTICS') && &ALF_FindMatchingObject($object,'REFERENCETYPE'); } sub ALF_LinkObjects { local($rule_container,$object_container,@object_types) = @_; local $semantics = &CreateArray(); &ALF_SearchForObjects($semantics,$rule_container,'ALF_HasReferenceType'); foreach $object_type (@object_types) { foreach $object (&ALF_FindMatchingObjects($object_container,$object_type)) { &ALF_CheckReferences($object,$object,&Array($semantics)); } } } 1;