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