function model = mttFetchInterfaceDefinition(filename) mttAssert(exist(filename)==2,... ['File "',filename,'" not found']) ; mttNotify([' ...processing ',filename]) ; mttWriteNewLine ; model.representation = 'cr' ; model.source = mttCutText(filename,'_cr.txt') ; content = mttReadFile(filename) ; statements = mttExtractStatements(content) ; number_of_statements = length(statements) ; crs = [] ; next = 0 ; parsing = 1 ; while parsing next = next + 1 ; statement = statements{next} ; [keyword,line] = mttSeparateText(statement) ; switch keyword case 'cr', cr_name = mttCutText(line,'[') ; mttValidateName(cr_name) ; if ~isempty(crs) mttAssert(~ismember(cr_name,crs),... ['"cr ',cr_name,'" has already been declared']) ; end cr_parameter_list = mttExtractText(line,'[',']') ; [cr_parameters,cr_defaults] = mttGetParameters(cr_parameter_list) ; [cr,next] = fetch_cr(statements,next,cr_name,cr_parameters,cr_defaults) ; mttCheckInterfaceDeclarations(cr) ; mttCheckStateDeclarations(cr) ; model = setfield(model,'item',cr_name,cr) ; if isempty(crs) crs = {cr_name} ; else crs = [crs,{cr_name}] ; end case '{', error('Unexpected "{" found') ; case '}', error('Unexpected "}" found') ; otherwise, error(['Unrecognised top-level keyword "',keyword,'"']) ; end if next==number_of_statements parsing = 0 ; end end function [cr,next] = fetch_cr(statements,next,cr_name,cr_parameters,cr_defaults) unit_name = 'cr' ; here = [cr_name,'/',unit_name] ; cr = [] ; number_of_statements = length(statements) ; cr.sympar = cr_parameters ; cr.numpar = [] ; cr.input = [] ; cr.state = [] ; cr.sympar_default = cr_defaults ; cr.numpar_default = [] ; cr.input_default = [] ; cr.state_default = [] ; op_counter = 0 ; interface_declared = 0 ; open = 0 ; parsing = 1 ; while parsing next = next + 1 ; statement = statements{next} ; [keyword,line] = mttSeparateText(statement) ; switch keyword case 'interface', mttAssert(open,... ['"interface" declaration must be contained inside {...} in ',here]) ; mttAssert(~interface_declared,... '"interface" declaration must be unique') ; mttAssert(isempty(line),... ['Unexpected text after "interface" declaration in ',here]) ; [interface,next] = fetch_interface(statements,next,cr_name) ; cr.interface = interface ; interface_declared = 1 ; case 'operator', mttAssert(interface_declared,... ['"operator" declaration must follow "interface" in ',here]) ; mttAssert(open,... ['"operator" declaration must be contained inside {...} in ',here]) ; op_counter = op_counter + 1 ; [operator,next] = fetch_operator(statements,next,cr,cr_name) ; if ~isfield(operator,'content') operator.content = [] ; end cr.operator(op_counter) = operator ; case 'input', mttAssert(open,... ['"input" declarations must be contained inside {...} in ',here]) ; input_parameter_list = line ; [input_parameters,input_defaults] = mttGetParameters(input_parameter_list) ; cr = mttAppend(cr,'input',input_parameters) ; cr = mttAppend(cr,'input_default',input_defaults) ; case 'numpar', mttAssert(open,... ['"numpar" declarations must be contained inside {...} in ',here]) ; numerical_parameter_list = line ; [numerical_parameters,numerical_defaults] = mttGetParameters(numerical_parameter_list) ; cr = mttAppend(cr,'numpar',numerical_parameters) ; cr = mttAppend(cr,'numpar_default',numerical_defaults) ; case 'state', mttAssert(open,... ['"state" declarations must be contained inside {...} in ',here]) ; state_parameter_list = line ; [state_parameters,state_defaults] = mttGetParameters(state_parameter_list) ; cr = mttAppend(cr,'state',state_parameters) ; cr = mttAppend(cr,'state_default',state_defaults) ; case '{', mttAssert(~open,['Unmatched "{" in ',here]) ; open = 1 ; case '}', mttAssert(open,['Unmatched "}" in ',here]) ; open = 0 ; otherwise, error(['Unrecognised keyword "',keyword,'" in ',here]) ; end mttAssert(~(open & (next==number_of_statements)),... ['Missing "}" in ',here]) ; if (~open) | (next==number_of_statements) parsing = 0 ; end end interface_ports = mttGetFieldNames(cr.interface,'port') ; interface_ports_with_state = [] ; counter = 0 ; for i = 1:length(interface_ports) port_name = interface_ports{i} ; interface_port = getfield(cr.interface,'port',port_name) ; if interface_port.is_effort_state | interface_port.is_flow_state counter = counter + 1 ; interface_ports_with_state{counter} = port_name ; end end mttAssert(op_counter>0,... ['No operator defined in ',here]) ; assigned_ports = [] ; for i = 1:length(cr.operator) if i==1 operator_names{1} = cr.operator(i).name ; else operator_name = cr.operator(i).name ; mttAssert(~ismember(operator_name,operator_names),... ['Repeated operator name "',operator_name,'" in ',here]) ; operator_names{i} = operator_name ; end newly_assigned_ports = mttGetFieldNames(cr.operator(i),'assign') ; if isempty(assigned_ports) assigned_ports = newly_assigned_ports ; else if ~isempty(newly_assigned_ports) assigned_ports = [assigned_ports, newly_assigned_ports] ; end end end for i = 1:length(interface_ports_with_state) interface_port = interface_ports_with_state{i} ; mttAssert(ismember(interface_port,assigned_ports),... ['Missing "set" declaration for port "',interface_port,'" in ',here]) ; end function [interface,next] = fetch_interface(statements,next,cr_name) global mtt_environment unit_name = 'interface' ; here = [cr_name,'/',unit_name] ; domain_names = mttGetFieldNames(mtt_environment,'domain') ; interface = [] ; number_of_statements = length(statements) ; counter = 0 ; constraint = [] ; open = 0 ; parsing = 1 ; while parsing next = next + 1 ; statement = statements{next} ; [keyword,line] = mttSeparateText(statement) ; switch keyword case 'port', ports = mttGetItemList(line) ; for n = 1:length(ports) identifier = mttCutText(ports{n},'[') ; qualifier = mttExtractText(ports{n},'[',']') ; [name.domain,name.domain_item] = mttCutText(qualifier,'::') ; name.port = identifier ; mttValidateName(name.port) ; if isempty(name.domain) | isempty(mtt_environment) interface = setfield(interface,'port',name.port,'domain',[]) ; interface = setfield(interface,'port',name.port,'domain_item',[]) ; interface = setfield(interface,'port',name.port,'was_generic',1) ; else mttAssert(ismember(name.domain,domain_names),... ['Unrecognised domain "',name.domain,'"']) ; dom = getfield(mtt_environment,'domain',name.domain,'dom') ; item = getfield(mtt_environment,'domain',name.domain,'item') ; if isempty(item) public_domain = getfield(mtt_environment,'public_domain',{dom}) ; item_names = mttGetFieldNames(public_domain,'item') ; mttAssert(ismember(name.domain_item,item_names),... ['Item "',name.domain_item,'" not found in public domain "',name.domain,'"']) ; item_name = name.domain_item ; else mttAssert(isempty(name.domain_item),... ['Item unspecified in public domain "',name.domain,'"']) ; item_name = item ; end interface = setfield(interface,'port',name.port,'domain',dom) ; interface = setfield(interface,'port',name.port,'domain_item',item_name) ; interface = setfield(interface,'port',name.port,'was_generic',0) ; end interface = setfield(interface,'port',name.port,'is_effort_state',0) ; interface = setfield(interface,'port',name.port,'is_flow_state',0) ; interface = setfield(interface,'port',name.port,'assign',[]) ; end case {'assert','prefer'}, counter = counter + 1 ; constraint{counter} = statement ; case '{', mttAssert(~open,['Unmatched "{" in ',here]) ; open = 1 ; case '}', mttAssert(open,['Unmatched "}" in ',here]) ; open = 0 ; otherwise, error(['Unrecognised_keyword "',keyword,'" in ',here]) ; end mttAssert(~(open & (next==number_of_statements)),... ['Missing "}" in ',here]) ; if (~open) | (next==number_of_statements) parsing = 0 ; end end interface_ports = mttGetFieldNames(interface,'port') ; number_of_constraints = length(constraint) ; for i = 1:number_of_constraints [keyword,assignment] = mttSeparateText(constraint{i}) ; [namelist,definition] = mttCutText(assignment,'=>') ; mttAssert(~isempty(keyword),... ['Rule "',constraint{i},'" has no context in cr ',cr_name]) ; if ~isempty(namelist) first = 1 ; last = length(namelist) ; if namelist([first,last])=='[]' ports = mttGetItemList(mttExtractText(namelist,'[',']')) ; else ports = {namelist} ; end end mttAssert(~isempty(ports),... ['Rule "',constraint{i},'" has no association in cr ',cr_name]) ; mttAssert(~isempty(definition),... ['Rule "',constraint{i},'" not defined in cr ',cr_name]) ; for j = 1:length(ports) port_name = ports{j} ; mttValidateName(port_name) ; other_ports = [] ; counter = 0 ; for k = 1:length(ports) if j~=k counter = counter + 1 ; other_ports{counter} = ports{k} ; end end mttAssert(ismember(port_name,interface_ports),... ['Unreferenced port "',port_name,'" in cr ',cr_name]) ; port = getfield(interface,'port',port_name) ; switch definition case 'effort_state', mttAssert(mttIsEqual(port.is_flow_state,0),... ['Attempt to overwrite state assignment at port "',port_name,'" in ',here]) ; port.is_effort_state = 1 ; case 'flow_state', mttAssert(mttIsEqual(port.is_effort_state,0),... ['Attempt to overwrite state assignment at port "',port_name,'" in ',here]) ; port.is_flow_state = 1 ; otherwise, rule_number = 1 + mttGetFieldLength(port,'causality') ; port.causality(rule_number).rule = keyword ; port.causality(rule_number).def = definition ; port.causality(rule_number).with = other_ports ; port.causality(rule_number).applied = 0 ; end interface = setfield(interface,'port',port_name,port) ; end end function [operator,next] = fetch_operator(statements,next,cr,cr_name) unit_name = 'operator' ; here = [cr_name,'/',unit_name] ; interface = [] ; number_of_statements = length(statements) ; statement = statements{next} ; [keyword,line] = mttSeparateText(statement) ; operator = mttGetOperatorContext(line,cr,cr_name) ; operator.content = [] ; operator.var = [] ; operator.var_default = [] ; operator.struct = [] ; operator.set = [] ; counter = 0 ; open = 0 ; parsing = 1 ; while parsing next = next + 1 ; statement = statements{next} ; [keyword,line] = mttSeparateText(statement) ; switch keyword case '{', mttAssert(~open,['Unmatched "{" in ',here]) ; open = 1 ; case '}', mttAssert(open,['Unmatched "}" in ',here]) ; open = 0 ; case 'set', mttAssert(open,... ['"set" declarations must be contained inside {...} in ',here]) ; operator = mttAppend(operator,'set',{line}) ; case 'var', mttAssert(open,... ['"var" declarations must be contained inside {...} in ',here]) ; variable_list = line ; [variables,defaults] = mttGetParameters(variable_list) ; operator = mttAppend(operator,'var',variables) ; operator = mttAppend(operator,'var_default',defaults) ; case 'struct', mttAssert(open,... ['"struct" declarations must be contained inside {...} in ',here]) ; [struct_name,variable_list] = mttSeparateText(line) ; [variables,defaults] = mttGetParameters(variable_list) ; mttAssert(mttIsEmptyCellArray(defaults),... ['"struct" declarations cannot have default values in ',here]) ; operator.struct = mttAppend(operator.struct,struct_name,variables) ; otherwise, counter = counter + 1 ; operator.content{counter} = statement ; end mttAssert(~(open & (next==number_of_statements)),... ['Missing "}" in ',here]) ; if (~open) | (next==number_of_statements) parsing = 0 ; end end cr_ports = mttGetFieldNames(cr.interface,'port') ; for i = 1:length(operator.var) current_var = operator.var{i} ; mttAssert(~ismember(current_var,cr.numpar),... ['Variable "',current_var,'" redeclares CR numerical parameter in ',cr_name]) ; mttAssert(~ismember(current_var,cr.sympar),... ['Variable "',current_var,'" redeclares CR parameter in ',cr_name]) ; mttAssert(~ismember(current_var,cr_ports),... ['Variable "',current_var,'" redeclares CR port in ',cr_name]) ; end operator = mttParseOperatorEquations(operator,cr,cr_name) ; function context = mttGetOperatorContext(line,cr,cr_name) index = sort([findstr(line,'|'),findstr(line,'<'),findstr(line,'>')]) ; assignment = findstr(line,':=') ; mttAssert(length(assignment)==1,... ['Operator declaration must contain a unique ":=" assignment in cr ',cr_name]) ; mttAssert(length(index)>0,... ['Operator declaration without ports in cr ',cr_name]) ; left_side = index(index<assignment) ; right_side = index(index>assignment) ; mttAssert(length(left_side)>0,... ['Operator declaration without input ports in cr ',cr_name]) ; mttAssert(length(right_side)>0,... ['Operator declaration without output ports in cr ',cr_name]) ; mttAssert(mod(length(left_side),2)==0 & mod(length(right_side),2)==0,... ['Operator declaration has mismatched tags in cr ',cr_name]) ; context.name = mttClipText(line(assignment+2:right_side(1)-1)) ; mttAssert(~isempty(context.name),... ['Operator declaration is anonymous in cr ',cr_name]) ; mttValidateName(context.name) ; counter = 0 ; for i = 1:length(index)/2 counter = counter + 1 ; link = [] ; right = 2*i ; left = right - 1 ; if index(right)<assignment link.is_input = 0 ; elseif index(left)>assignment link.is_input = 1 ; end recognised = 1 ; switch line(index([left,right])) case '|>', link.is_flow = 1 ; link.is_effort = 0 ; case '<|', link.is_flow = 0 ; link.is_effort = 1 ; case '<>', link.is_flow = 1 ; link.is_effort = 1 ; otherwise, recognised = 0 ; end mttAssert(recognised,... ['Unrecognised tags in operator ',context.name,' (cr ',cr_name,')']) ; port_declaration = line(index(left):index(right)) ; port = line(index(left)+1:index(right)-1) ; mttAssert(~isempty(port),... ['Empty port in operator ',context.name,' (cr ',cr_name,')']) ; [port_name,qualifier] = mttCutText(port,'=') ; link.name = port_name ; if isempty(qualifier) link.is_unconstrained = 1 ; else link.is_unconstrained = 0 ; mttAssert(strcmp(qualifier,'0'),... ['Non-zero port constraint in operator ',context.name,' (cr ',cr_name,')']) ; end context.link(counter) = link ; end cr_port_names = mttGetFieldNames(cr.interface,'port') ; check.is_input = [] ; check.is_output = [] ; check.is_effort = [] ; check.is_flow = [] ; for j = 1:length(cr_port_names) port_check(j) = check ; end for i = 1:counter port_name = context.link(i).name ; mttAssert(ismember(port_name,cr_port_names),... ['Operator declaration uses undefined port "',port_name,'" in cr ',cr_name]) ; index = strmatch(port_name,cr_port_names,'exact') ; mttAssert(~mttIsEqual(port_check(index).is_input,context.link(i).is_input),... ['Operator declaration has repeated input ports in cr ',cr_name]) ; mttAssert( mttIsEqual(port_check(index).is_output,context.link(i).is_input),... ['Operator declaration has repeated output ports in cr ',cr_name]) ; mttAssert(~mttIsEqual(port_check(index).is_flow,context.link(i).is_flow),... ['Operator declaration has repeated flow in cr ',cr_name]) ; mttAssert(~mttIsEqual(port_check(index).is_effort,context.link(i).is_effort),... ['Operator declaration has repeated effort in cr ',cr_name]) ; port_check(index).is_input = context.link(i).is_input ; port_check(index).is_output = ~context.link(i).is_input ; port_check(index).is_flow = context.link(i).is_flow ; port_check(index).is_effort = context.link(i).is_effort ; end for j = 1:length(cr_port_names) mttAssert(~isempty(port_check(j).is_input),... ['Operator declaration has missing input ports in cr ',cr_name]) ; mttAssert(~isempty(port_check(j).is_output),... ['Operator declaration has missing output ports in cr ',cr_name]) ; mttAssert(~isempty(port_check(j).is_flow),... ['Operator declaration has missing flow in cr ',cr_name]) ; mttAssert(~isempty(port_check(j).is_effort),... ['Operator declaration has missing effort in cr ',cr_name]) ; end