📄 tffparse.m
字号:
lc = endline + 1;
% invalid ListOfFields
if lc > llc
error( ...
'BVQXtools:BadTFFSpec', ...
'Unclosed or bad ListOfFields block.' ...
);
end
% list/table field separator
listsep = tffval;
% get rule headers
rhead = splittocell(tfflines{blc}, listsep, 0);
% build header struct
hstruct = struct;
for hfc = 1:length(rhead)
hfield = lower(makelabel(rhead{hfc}));
hstruct.(hfield) = hfc;
rhead{hfc} = hfield;
end
blc = blc + 1;
% bail out if invalid header given
if ...
~isfield(hstruct, 'type') || ...
~isfield(hstruct, 'cond') || ...
~isfield(hstruct, 'field') || ...
~isfield(hstruct, 'datatype') || ...
~isfield(hstruct, 'format') || ...
~isfield(hstruct, 'dim') || ...
~isfield(hstruct, 'default') || ...
~isfield(hstruct, 'varname')
warning( ...
'BVQXtools:BadTFFSpec', ...
'ListOfFields with bad headers.' ...
);
continue;
end
% get list of header field names (in their order)
hfields = fieldnames(hstruct);
nfields = length(hfields);
% build empty field list struct
frules = cell2struct(cell(0, 0, nfields), hfields, 3);
% check global fieldlist struct
tfields = fieldnames(tffspec.ListOfFields);
% no rules yet -> OK
if isempty(tfields)
tffspec.ListOfFields = frules;
% otherwise compare header fields
else
% assume no mismatch
headermismatch = false;
% check number of fields
if length(tfields) ~= length(hfields)
tfields = {};
headermismatch = true;
end
% only if still content in tfields, check names
for tfc = 1:length(tfields)
if ~strcmp(tfields{tfc}, hfields{tfc})
headermismatch = true;
break;
end
end
% if mismatch give warning and continue with next block
if headermismatch
warning( ...
'BVQXtools:BadTFFSpec', ...
'ListOfFields blocks must match in their headers.' ...
);
continue;
end
end
% build list of rules to consider
actrules = frules;
for slc = blc:endline
% split to fields
rcont = splittocell(tfflines{slc}, listsep, 0);
% reject too short arrays
if length(rcont) < length(rhead)
continue;
end
% deal into struct
rstruct = hstruct;
for hfc = 1:length(hfields)
hfield = hfields{hfc};
rstruct.(hfield) = deblank(rcont{hstruct.(hfield)});
end
rstrtype = lower(rstruct.type);
% deal with empty lines
if isempty(rstrtype)
continue;
elseif ...
~any(strcmp(rstrtype, {'skipn', 'wrtln'})) && ...
isempty(rstruct.varname)
warning( ...
'BVQXtools:AmbiguousTFFSpec', ...
'Non recognized TYPE token: ''%s''.', ...
rstruct.type ...
);
continue;
end
% put non-empty type/varname rules into actrules
actrules(end + 1) = rstruct;
end
% init loop checking variables and flist array
looplist = {};
loopused = {};
% parse rules (using for; if any rules fail, error out!)
for slc = 1:length(actrules)
% get rstruct from actrules
rstruct = actrules(slc);
rstrtype = lower(rstruct.type);
% copy varname into empty fields
if isempty(rstruct.field)
rstruct.field = rstruct.varname;
actrules(slc).field = rstruct.field;
end
% check syntax of fields, type
if ~any(strcmp(rstrtype, ...
{'bloop', 'eloop', 'expre', 'skipn', 'xloop', ...
'array', 'field', 'flist', 'wrtln'}))
error( ...
'BVQXtools:BadTFFSpec', ...
'Invalid ListOfFields.type token: ''%s''.', ...
rstruct.type ...
);
end
% ... cond
if ~isempty(rstruct.cond)
try
eval([ ...
'if 1==0,if ' ...
strrep(strrep(rstruct.cond, '$', ''), '@', '') ...
',disp(1);end,end']);
catch
error( ...
'BVQXtools:BadTFFSpec', ...
'Invalid ListOfFields.cond content: ''%s''.', ...
rstruct.cond ...
);
end
end
% ... field
if ...
any(strcmp(rstrtype, ...
{'array', 'field', 'flist'})) && ...
isempty(regexpi(rstruct.field, '^[a-z][a-z_0-9\-]*$'))
error( ...
'BVQXtools:BadTFFSpec', ...
'Invalid ListOfFields.field name: ''%s''.', ...
rstruct.field ...
);
end
% ... datatype / format
if ...
any(strcmp(rstrtype, ...
{'array', 'field', 'flist'})) && ...
(isempty(regexpi(rstruct.datatype, '^[a-z][a-z_0-9]+$')) || ...
length(find(rstruct.format == '%')) ~= 1)
error( ...
'BVQXtools:BadTFFSpec', ...
['Invalid ListOfFields.datatype/format tag: ' ...
'''%s''/''%s''.'], ...
rstruct.datatype, rstruct.format ...
);
end
% ... dim (loops, fields and flists)
if any (strcmp(rstrtype, {'bloop', 'field', 'flist'}))
% only single number OR variable
if isempty(regexpi(rstruct.dim, ...
'^(\d+|[\$\@][a-z][a-z_0-9\.]*(\((\d+|[\$\@][a-z][a-z_0-9\.]*)\))?)$'))
error( ...
'BVQXtools:BadTFFSpec', ...
'Invalid LOOP/FIELD/FLIST.DIM given: ''%s''.', ...
rstruct.dim ...
);
end
% ... dim (arrays)
elseif strcmp(rstrtype, 'array')
% multiple numbers AND/OR variables
if isempty(regexpi(rstruct.dim, ...
['^((\d+|[\$\@][a-z][a-z_0-9]*)(\((\d+|[\$\@][a-z][a-z_0-9]*)\))?' ...
'(\.[a-z][a-z_0-9]*(\((\d+|[\$\@][a-z][a-z_0-9]*)\))?)*\,\s*)*' ...
'((\d+|[\$\@][a-z][a-z_0-9]*)(\((\d+|[\$\@][a-z][a-z_0-9]*)\))?)$']))
error( ...
'BVQXtools:BadTFFSpec', ...
'Invalid ARRAY.dim given: ''%s''.', ...
rstruct.dim ...
);
end
% ... dim (skipn)
elseif strcmp(rstrtype, 'skipn')
% only a 1-D numeric value accepted
if isempty(regexp(rstruct.dim, '^\-?\d+$', 'once'))
error( ...
'BVQXtools:BadTFFSpec', ...
'Invalid SKIPN.dim given: ''%s''.', ...
rstruct.dim ...
);
end
end
% ... default (if non-empty)
if ~isempty(rstruct.default)
try
eval(['if 1==0,' ...
strrep(strrep(rstruct.default, '$', ''), '@', '') ',end']);
catch
error( ...
'BVQXtools:BadTFFSpec', ...
'Invalid ListOfFields.default value: ''%s''.', ...
rstruct.default ...
);
end
end
% ... varname (loops, fields)
if any(strcmp(rstrtype, ...
{'array', 'bloop', 'eloop', 'field', 'flist', 'xloop'}))
% fields can be complex
if any(strcmp(rstrtype, {'array', 'field', 'flist'}))
if isempty(regexpi(rstruct.varname, ...
['^([a-z][a-z_0-9]*(\((\d+|[\$\@][a-z][a-z_0-9]*)\))?\.)*' ...
'[a-z][a-z_0-9]*(\((\d+|[\$\@][a-z][a-z_0-9]*)\))?$']))
error( ...
'BVQXtools:BadTFFSpec', ...
'Invalid ListOfFields.varname: ''%s''.', ...
rstruct.varname ...
);
end
% loop variables MUST be simple
else
if isempty(regexpi(rstruct.varname, ...
'^[a-z][a-z_0-9]*(\(\d+\))?$'))
error ( ...
'BVQXtools:BadTFFSpec', ...
'Invalid ListOfFields.varname: ''%s''.', ...
rstruct.varname ...
);
end
end
% ... varname (expressions, WRTLN must not be check)
elseif ~strcmp(rstrtype, 'wrtln')
try
eval(['if 1==0,if 1==0,' ...
strrep(strrep(strrep(rstruct.varname, ...
'@@', 'cvar'), '$', 'nvar.'), '@', 'cvar.') ...
',end,end']);
catch
error( ...
'BVQXtools:BadTFFSpec', ...
'Invalid EXPRE in ListOfFields.varname: ''%s''.', ...
rstruct.varname ...
);
end
end
% look at loop details
if strcmp(rstrtype, 'bloop')
% varname might not be part of current looplist
if any(strcmp(rstruct.varname, loopused))
error( ...
'BVQXtools:BadTFFSpec', ...
'LOOP variable name reused: ''%s''.', ...
rstruct.varname ...
);
end
% put varname at the end of looplist
lvname = rstruct.varname;
looplist{end + 1} = lvname;
loopused{end + 1} = lvname;
slooplist = looplist;
% scan for loop end
eloopfound = false;
subloops = 1;
for sslc = (slc+1):length(actrules)
% get another shortcut
tstruct = actrules(sslc);
tstrtype = lower(tstruct.type);
% subloops (BLOOP)
if strcmp(tstrtype, 'bloop')
subloops = subloops + 1;
slooplist{end + 1} = tstruct.varname;
% end-of-loop (ELOOP)
elseif strcmp(tstrtype, 'eloop')
subloops = subloops - 1;
try
if ~strcmp(slooplist{end}, tstruct.varname)
error('ILLEGALLOOP');
end
slooplist(end) = [];
catch
error( ...
'BVQXtools:BadTFFSpec', ...
'Illegal loop nesting found.' ...
);
end
% checking loop names for xloop
elseif strcmp(tstrtype, 'xloop')
% must be found in slooplist !
if ~any(strcmp(slooplist, tstruct.varname))
error( ...
'BVQXtools:BadTFFSpec', ...
'Unknown XLOOP token: ''%s''.', ...
tstruct.varname ...
);
end
end
% type must be ELOOP and varname match
if ...
strcmpi(actrules(sslc).type, 'eloop') && ...
strcmp(actrules(sslc).varname, lvname)
eloopfound = true;
elooprule = sslc;
break;
end
end
% if no end of loop found...
if ~eloopfound
error( ...
'BVQXtools:BadTFFSpec', ...
'Missing closing tag for LOOP %s.', ...
lvname ...
);
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -