Skip to content
Snippets Groups Projects
Commit 3d88a29d authored by Zizhe Wang's avatar Zizhe Wang
Browse files

add component to transfer feature models

parent ff5bc4c4
Branches
No related tags found
No related merge requests found
from anytree import Node, RenderTree
import json
from parse_modelica import parse_model
# Class to represent and manipulate the feature model tree
class FeatureModel:
def __init__(self, root_name):
self.root = Node(root_name) # Initialize the root node of the tree
# Method to add a component and its parameters to the tree
def add_component(self, component_type, component_name, parameters):
# Create a node for the component
component_node = Node(f"{component_type} ({component_name})", parent=self.root)
# Create nodes for each parameter and its value
for param_name, param_value in parameters.items():
Node(f"{param_name}={param_value}", parent=component_node)
# Method to display the tree structure in the console
def display(self):
for pre, fill, node in RenderTree(self.root):
print("%s%s" % (pre, node.name))
# Method to convert the tree to a dictionary for JSON serialization
def to_dict(self, node=None):
if node is None:
node = self.root
result = {"name": node.name, "children": [self.to_dict(child) for child in node.children]}
return result
# Method to save the tree to a JSON file
def save_to_json(self, file_path):
with open(file_path, 'w') as file:
json.dump(self.to_dict(), file, indent=4)
if __name__ == "__main__":
# Parse the Modelica file and extract components
components = parse_model('SimpleHeatingSystem.mo')
# Create a feature model and add the extracted components
feature_model = FeatureModel("SimpleHeatingSystem")
for component_type, component_name, parameters in components:
feature_model.add_component(component_type, component_name, parameters)
# Display and save the feature tree
feature_model.display()
feature_model.save_to_json('feature_model.json')
\ No newline at end of file
/*
[The "BSD licence"]
Copyright (c) 2012 Tom Everett
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// $antlr-format alignTrailingComments true, columnLimit 150, minEmptyLines 1, maxEmptyLinesToKeep 1, reflowComments false, useTab false
// $antlr-format allowShortRulesOnASingleLine false, allowShortBlocksOnASingleLine true, alignSemicolons hanging, alignColons hanging
grammar modelica;
stored_definition
: ('within' (name)? ';')* (('final')? class_definition ';')* EOF
;
class_definition
: ('encapsulated')? class_prefixes class_specifier
;
class_specifier
: long_class_specifier
| short_class_specifier
| der_class_specifier
;
class_prefixes
: ('partial')? (
'class'
| 'model'
| ('operator')? 'record'
| 'block'
| ('expandable')? 'connector'
| 'type'
| 'package'
| (('pure' | 'impure'))? ('operator')? 'function'
| 'operator'
)
;
long_class_specifier
: IDENT string_comment composition 'end' IDENT
| 'extends' IDENT (class_modification)? string_comment composition 'end' IDENT
;
short_class_specifier
: IDENT '=' base_prefix name (array_subscripts)? (class_modification)? comment
| IDENT '=' 'enumeration' '(' ((enum_list)? | ':') ')' comment
;
der_class_specifier
: IDENT '=' 'der' '(' name ',' IDENT (',' IDENT)* ')' comment
;
base_prefix
: type_prefix
;
enum_list
: enumeration_literal (',' enumeration_literal)*
;
enumeration_literal
: IDENT comment
;
composition
: element_list (
'public' element_list
| 'protected' element_list
| equation_section
| algorithm_section
)* ('external' (language_specification)? (external_function_call)? (annotation)? ';')? (
annotation ';'
)?
;
language_specification
: STRING
;
external_function_call
: (component_reference '=')? IDENT '(' (expression_list)? ')'
;
element_list
: (element ';')*
;
element
: import_clause
| extends_clause
| ('redeclare')? ('final')? ('inner')? ('outer')? (
(class_definition | component_clause)
| 'replaceable' (class_definition | component_clause) (constraining_clause comment)?
)
;
import_clause
: 'import' (IDENT '=' name | name '.*' | name '.{' import_list '}' | name) comment
;
import_list
: IDENT (',' IDENT)*
;
extends_clause
: 'extends' name (class_modification)? (annotation)?
;
constraining_clause
: 'constrainedby' name (class_modification)?
;
component_clause
: type_prefix type_specifier (array_subscripts)? component_list
;
type_prefix
: ('flow' | 'stream')? ('discrete' | 'parameter' | 'constant')? ('input' | 'output')?
;
type_specifier
: name
;
component_list
: component_declaration (',' component_declaration)*
;
component_declaration
: declaration (condition_attribute)? comment
;
condition_attribute
: 'if' expression
;
declaration
: IDENT (array_subscripts)? (modification)?
;
modification
: class_modification ('=' expression)?
| '=' expression
| ':=' expression
;
class_modification
: '(' (argument_list)? ')'
;
argument_list
: argument (',' argument)*
;
argument
: element_modification_or_replaceable
| element_redeclaration
;
element_modification_or_replaceable
: ('each')? ('final')? (element_modification | element_replaceable)
;
element_modification
: name (modification)? string_comment
;
element_redeclaration
: 'redeclare' ('each')? ('final')? (
(short_class_definition | component_clause1)
| element_replaceable
)
;
element_replaceable
: 'replaceable' (short_class_definition | component_clause1) (constraining_clause)?
;
component_clause1
: type_prefix type_specifier component_declaration1
;
component_declaration1
: declaration comment
;
short_class_definition
: class_prefixes short_class_specifier
;
equation_section
: ('initial')? 'equation' (equation ';')*
;
algorithm_section
: ('initial')? 'algorithm' (statement ';')*
;
equation
: (
simple_expression '=' expression
| if_equation
| for_equation
| connect_clause
| when_equation
| name function_call_args
) comment
;
statement
: (
component_reference (':=' expression | function_call_args)
| '(' output_expression_list ')' ':=' component_reference function_call_args
| 'break'
| 'return'
| if_statement
| for_statement
| while_statement
| when_statement
) comment
;
if_equation
: 'if' expression 'then' (equation ';')* ('elseif' expression 'then' (equation ';')*)* (
'else' (equation ';')*
)? 'end' 'if'
;
if_statement
: 'if' expression 'then' (statement ';')* ('elseif' expression 'then' (statement ';')*)* (
'else' (statement ';')*
)? 'end' 'if'
;
for_equation
: 'for' for_indices 'loop' (equation ';')* 'end' 'for'
;
for_statement
: 'for' for_indices 'loop' (statement ';')* 'end' 'for'
;
for_indices
: for_index (',' for_index)*
;
for_index
: IDENT ('in' expression)?
;
while_statement
: 'while' expression 'loop' (statement ';')* 'end' 'while'
;
when_equation
: 'when' expression 'then' (equation ';')* ('elsewhen' expression 'then' (equation ';')*)* 'end' 'when'
;
when_statement
: 'when' expression 'then' (statement ';')* ('elsewhen' expression 'then' (statement ';')*)* 'end' 'when'
;
connect_clause
: 'connect' '(' component_reference ',' component_reference ')'
;
expression
: simple_expression
| 'if' expression 'then' expression ('elseif' expression 'then' expression)* 'else' expression
;
simple_expression
: logical_expression (':' logical_expression (':' logical_expression)?)?
;
logical_expression
: logical_term ('or' logical_term)*
;
logical_term
: logical_factor ('and' logical_factor)*
;
logical_factor
: ('not')? relation
;
relation
: arithmetic_expression (rel_op arithmetic_expression)?
;
rel_op
: '<'
| '<='
| '>'
| '>='
| '=='
| '<>'
;
arithmetic_expression
: (add_op)? term (add_op term)*
;
add_op
: '+'
| '-'
| '.+'
| '.-'
;
term
: factor (mul_op factor)*
;
mul_op
: '*'
| '/'
| '.*'
| './'
;
factor
: primary (('^' | '.^') primary)?
;
primary
: UNSIGNED_NUMBER
| STRING
| 'false'
| 'true'
| (name | 'der' | 'initial') function_call_args
| component_reference
| '(' output_expression_list ')'
| '[' expression_list (';' expression_list)* ']'
| '{' function_arguments '}'
| 'end'
;
name
: ('.')? IDENT ('.' IDENT)*
;
component_reference
: ('.')? IDENT (array_subscripts)? ('.' IDENT (array_subscripts)?)*
;
function_call_args
: '(' (function_arguments)? ')'
;
function_arguments
: function_argument (',' function_arguments | 'for' for_indices)?
| named_arguments
;
named_arguments
: named_argument (',' named_arguments)?
;
named_argument
: IDENT '=' function_argument
;
function_argument
: 'function' name '(' (named_arguments)? ')'
| expression
;
output_expression_list
: (expression)? (',' (expression)?)*
;
expression_list
: expression (',' expression)*
;
array_subscripts
: '[' subscript_ (',' subscript_)* ']'
;
subscript_
: ':'
| expression
;
comment
: string_comment (annotation)?
;
string_comment
: (STRING ('+' STRING)*)?
;
annotation
: 'annotation' class_modification
;
IDENT
: NONDIGIT (DIGIT | NONDIGIT)*
| Q_IDENT
;
fragment Q_IDENT
: '\'' (Q_CHAR | S_ESCAPE) (Q_CHAR | S_ESCAPE)* '\''
;
fragment S_CHAR
: ~ ["\\]
;
fragment NONDIGIT
: '_'
| 'a' .. 'z'
| 'A' .. 'Z'
;
STRING
: '"' (S_CHAR | S_ESCAPE)* '"'
;
fragment Q_CHAR
: NONDIGIT
| DIGIT
| '!'
| '#'
| '$'
| '%'
| '&'
| '('
| ')'
| '*'
| '+'
| ','
| '-'
| '.'
| '/'
| ':'
| ';'
| '<'
| '>'
| '='
| '?'
| '@'
| '['
| ']'
| '^'
| '{'
| '}'
| '|'
| '~'
;
fragment S_ESCAPE
: '\\' ('’' | '\'' | '"' | '?' | '\\' | 'a' | 'b' | 'f' | 'n' | 'r' | 't' | 'v')
;
fragment DIGIT
: '0' .. '9'
;
fragment UNSIGNED_INTEGER
: DIGIT (DIGIT)*
;
UNSIGNED_NUMBER
: UNSIGNED_INTEGER ('.' (UNSIGNED_INTEGER)?)? (('e' | 'E') ('+' | '-')? UNSIGNED_INTEGER)?
;
WS
: [ \r\n\t]+ -> channel (HIDDEN)
;
COMMENT
: '/*' .*? '*/' -> channel (HIDDEN)
;
LINE_COMMENT
: '//' ~[\r\n]* -> channel (HIDDEN)
;
\ No newline at end of file
# This parses a Modelica model to extract its components (variables and parameters) and their parameters.
# It uses the ANTLR-generated lexer and parser to build a parse tree and then walks the tree to extract relevant information.
import sys
import os
from antlr4 import *
# Import lexer, parser, and listener generated by ANTLR for Modelica grammar.
from modelicaLexer import modelicaLexer
from modelicaParser import modelicaParser
from modelicaListener import modelicaListener
# Listener class to extract components and their parameters from the parse tree
class ModelicaFeatureExtractor(modelicaListener):
def __init__(self):
self.components = [] # List to store extracted components
# Method called when entering a component clause in the parse tree
def enterComponent_clause(self, ctx: modelicaParser.Component_clauseContext):
# Extract the component type and name
type_prefix = ctx.type_prefix().getText() if ctx.type_prefix() else ""
component_type = type_prefix + " " + ctx.type_specifier().getText()
print(f"Component type: {component_type}")
# Iterate over each component declaration in the component list
for component in ctx.component_list().component_declaration():
component_name = component.declaration().IDENT().getText()
# print(f"Component name: {component_name}") ## uncomment for debugging
parameters = {} # Dictionary to store parameters and their values
# Check if there are any modifications (initial values or other modifications)
if component.declaration().modification() is not None:
modification = component.declaration().modification()
param_value = self.get_modification_value(modification)
if param_value is not None:
parameters[component_name] = param_value # Store the parameter value
# print(f"Param: {component_name} = {param_value}") uncomment for debugging
# Add the component to the list
self.components.append((component_type, component_name, parameters))
# Helper method to extract the value from a modification context
def get_modification_value(self, modification_ctx):
if modification_ctx is None:
return None
if modification_ctx.expression(): # Direct value assignment
return modification_ctx.expression().getText()
elif modification_ctx.class_modification():
class_mod = modification_ctx.class_modification() # Class modification
if class_mod.argument_list() is not None:
values = []
for argument in class_mod.argument_list().argument():
if hasattr(argument, 'element_modification'):
element_mod = argument.element_modification()
param_name = element_mod.name().getText()
param_value = self.get_modification_value(element_mod.modification())
values.append(f"{param_name}={param_value}")
return "({})".format(", ".join(values))
return None
# Function to parse a Modelica file and extract components
def parse_model(file_name):
input_stream = FileStream(file_name, encoding='utf-8') # Read the file
lexer = modelicaLexer(input_stream) # Tokenize the input
stream = CommonTokenStream(lexer) # Create a token stream
parser = modelicaParser(stream) # Create a parser
tree = parser.stored_definition() # Parse the input into a parse tree
extractor = ModelicaFeatureExtractor() # Create a listener
walker = ParseTreeWalker() # Create a parse tree walker
walker.walk(extractor, tree) # Walk the parse tree with the listener
return extractor.components # Return the extracted components
if __name__ == "__main__":
file_name = 'SimpleHeatingSystem.mo'
components = parse_model(file_name) # Parse the file and extract components
for component in components:
print(component) # Print the extracted components
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment