function [S,INVALID] = parse(THIS,varargin)
% parse [Not a public function] Execute theparser object.
%
% Backend IRIS function.
% No help provided.

% -IRIS Toolbox.
% -Copyright (c) 2007-2012 Jaromir Benes.

iserrors = ~isempty(varargin) && any(strcmp(varargin,'error'));

%**************************************************************************

nblk = length(THIS.blkname);

% Replace alternative block syntax.
THIS = altsyntax(THIS);

% Output struct.
S = struct();

S.blk = [];
S.name = [];
S.nametype = [];
S.namelabel = [];
S.namevalue = [];
S.nameflag = [];
S.eqtn = [];
S.eqtntype = [];
S.eqtnlabel = [];
S.eqtnlhs = [];
S.eqtnrhs = [];
S.eqtnsign = [];
S.sstatelhs = [];
S.sstaterhs = [];
S.sstatesign = [];
S.maxt = [];
S.mint = [];

S = S(ones(1,nblk));

INVALID = struct();
INVALID.key = {};
INVALID.allbut = false;
INVALID.flag = {};
INVALID.timesubs = {};

% Read individual blocks and check for unknown keywords.
[blk,INVALID.key,INVALID.allbut] = readblk(THIS);
for iblk = 1 : nblk
    S(iblk).blk = blk{iblk};
end

% Read individual names within each name block.
for iblk = find(THIS.nameblk)
    [S(iblk).name,S(iblk).namelabel, ...
        S(iblk).namevalue,S(iblk).nameflag] = ...
        theparser.parsenames(S(iblk).blk);
    nname = length(S(iblk).name);
    S(iblk).nametype = iblk*ones(1,nname);
end

% Read names in the flag block (only one flag block allowed).
if any(THIS.flagblk)
    [S(THIS.flaggable),INVALID.flag] = ...
        theparser.parseflags(S(THIS.flagblk).blk,S(THIS.flaggable));
end

% Read individual equations within each equation block.
for iblk = find(THIS.eqtnblk)
    [S(iblk).eqtn,S(iblk).eqtnlabel, ...
        S(iblk).eqtnlhs,S(iblk).eqtnrhs,S(iblk).eqtnsign, ...
        S(iblk).sstatelhs,S(iblk).sstaterhs,S(iblk).sstatesign] = ...
        theparser.parseeqtns(S(iblk).blk);
    neqtn = length(S(iblk).eqtn);
    S(iblk).eqtntype = iblk*ones(1,neqtn);
    % Evaluate and check time subscripts, find max and min time subscript.
    [S(iblk).maxt,S(iblk).mint,invalidtimesubs, ...
        S(iblk).eqtnlhs,S(iblk).eqtnrhs, ...
        S(iblk).sstatelhs,S(iblk).sstaterhs] ...
        = theparser.evaltimesubs(S(iblk).eqtnlhs,S(iblk).eqtnrhs, ...
        S(iblk).sstatelhs,S(iblk).sstaterhs);
    INVALID.timesubs = [INVALID.timesubs,invalidtimesubs];
end

% Put back labels.
for iblk = 1 : nblk
    S(iblk).namelabel = labelsback(THIS,S(iblk).namelabel,'%s');
    S(iblk).eqtnlabel = labelsback(THIS,S(iblk).eqtnlabel,'%s');
end

% Errors.

if ~iserrors
    return
end

dochkinvalid();

% Nested functions.

%**************************************************************************
    function dochkinvalid()
        
        % Blocks marked as essential cannot be empty.
        for iiblk = find(THIS.essential)
            caller = strtrim(THIS.caller);
            if ~isempty(caller)
                caller(end+1) = ' '; %#ok<AGROW>
            end
            if isempty(S(iiblk).blk) || all(S(iiblk).blk <= char(32))
                utils.error('model',[errorparsing(THIS), ...
                    'Cannot find a non-empty ''%s'' block. ', ...
                    'This is not a valid ',caller,'file.'], ...
                    THIS.blkname{iiblk});
            end
        end
        
        % Some of the `!log_variables` section have `!allbut`, some do not have.
        if INVALID.allbut
            utils.error('model',[errorparsing(THIS), ...
                'The keyword !allbut may appear in either all or none of ', ...
                'the !log_variables sections.']);
        end
        
        % Invalid keyword.
        if ~isempty(INVALID.key)
            utils.error('model',[errorparsing(THIS), ...
                'This is not a valid keyword: ''%s''.'], ...
                INVALID.key{:});
        end
        
        % Invalid names on the log-variable list.
        if ~isempty(INVALID.flag)
            flagblkname = THIS.blkname{THIS.flagblk};
            utils.error('model',[errorparsing(THIS), ...
                'This name is not allowed ', ...
                'on the ''',flagblkname,''' list: ''%s''.'], ...
                INVALID.flag{:});
        end
        
        % Invalid time subscripts.
        if ~isempty(INVALID.timesubs)
            % Error evaluating time subscripts.
            utils.error('model',[errorparsing(THIS), ...
                'Cannot evaluate this time index: ''%s''.'], ...
                INVALID.timesubs{:});
        end
        
    end
% dochkinvalid().

end