function THIS = myparse(THIS,FNAME,OPT)
% myparse  [Not a public function] Parse syeq file.
%
% Backend IRIS function.
% No help provided.

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

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

% Run the preparser.
p = preparser(FNAME);
THIS.fname = p.fname;
THIS.Comment = p.Comment;
THIS.build = irisversion();
THIS.Export = p.Export;
export(THIS);

% Run the theta parser.
q = theparser('syeq',p);
S = parse(q,'error');

donames();
dotimesubs();
doequations();
douserdiff();
ne = sum(THIS.nametype == 3);
nt = THIS.maxt - THIS.mint + 1;
tzero = 1 - THIS.mint;
nname = length(THIS.name);
neqtn = length(THIS.eqtn);

% Preallocate new properties.
doprealloc();
THIS.stdcorr(1,1:ne,:) = OPT.std;

% Transform eqtn to eqtnf.
dotransformeqtn();
isident = ~isnan(THIS.ident);

% Differentiate equations wrt current dates of variables and shocks.
dodiff();

% Convert char equations to anonymous functions.
doeqtn2afcn();

THIS.evalident = myevalgroupfunc(THIS,isident,'@(x,t,L)');
THIS.evalnonident = myevalgroupfunc(THIS,~isident,'@(x,t,L)');

% Nested functions.

%**************************************************************************
    function donames()
        THIS.name = [S(1:4).name];
        THIS.nametype = [S(1:4).nametype];
        THIS.namelabel = [S(1:4).namelabel];
        % Keep logs for variables and shocks only.
        THIS.log = [S(1:3).nameflag];
    end
% donames().

%**************************************************************************
    function dotimesubs()
        THIS.mint = S(6).mint;
        THIS.maxt = S(6).maxt;
    end
% donames().

%**************************************************************************
    function doequations()
        THIS.eqtn = S(6).eqtn;
        THIS.eqtntype = ones(size(THIS.eqtn));
        THIS.eqtnlabel = S(6).eqtnlabel;
    end
% doequations().

%**************************************************************************
    function douserdiff()
        userdifflist = regexp(S(7).blk,'[a-zA-Z][\w\.]+','match');
        THIS.userdifflist = '{';
        for i = 1 : length(userdifflist)
            if i > 1
                THIS.userdifflist = [THIS.userdifflist,','];
            end
            THIS.userdifflist = [THIS.userdifflist, ...
                '''',userdifflist{i},''''];
        end
        THIS.userdifflist = [THIS.userdifflist,'}'];
    end
% douserdiff().

%**************************************************************************
    function doprealloc()
        THIS.ident = nan(1,neqtn);
        THIS.occur = false(neqtn,nname,nt);
        THIS.eqtnf = cell(1,neqtn);
        THIS.Assign = nan(1,nname);
        THIS.stdcorr = zeros(1,ne+ne*(ne-1)/2);
        THIS.deqtnx = cell(1,neqtn);
        THIS.deqtne = cell(1,neqtn);
    end
% doprealloc().

%**************************************************************************
    function dotransformeqtn()
        lhs = S(6).eqtnlhs;
        rhs = S(6).eqtnrhs;
        undeclared = {};
        validlhs = true(1,neqtn);
        multiple = false(1,nname);
        replacefunc = @doreplacevariables; %#ok<NASGU>
        lhs0 = strtrim(lhs);
        for iieqtn = 1 : neqtn
            pattern = '([&\$])?\<([a-zA-Z]\w*)\>(\{[+\-\d]+\})?(?!\()';
            lhs{iieqtn} = regexprep(lhs{iieqtn}, ...
                pattern,'${replacefunc($1,$2,$3)}');
            rhs{iieqtn} = regexprep(rhs{iieqtn}, ...
                pattern,'${replacefunc($1,$2,$3)}');
            if any(any(THIS.occur(iieqtn,THIS.nametype == 3,:)))
                % Regular equation.                
                if isempty(lhs{iieqtn})
                    THIS.eqtnf{iieqtn} = rhs{iieqtn};
                else
                    THIS.eqtnf{iieqtn} = ...
                        [lhs{iieqtn},'-(',rhs{iieqtn},')'];
                end
                if THIS.eqtnf{iieqtn}(end) ~= ';'
                    THIS.eqtnf{iieqtn}(end+1) = ';';
                end
            else
                % Identity.
                index = strcmp(lhs0{iieqtn},THIS.name) & THIS.nametype == 1;
                if ~any(index)
                    validlhs(iieqtn) = false;
                    continue
                end
                iiname = find(index);
                if any(iiname == THIS.ident)
                    multiple(iiname) = true;
                end
                THIS.ident(iieqtn) = iiname;
                THIS.eqtnf{iieqtn} = rhs{iieqtn};
            end
        end
        
        if ~isempty(undeclared)
            utils.error('syeq',[utils.errorparsing(THIS), ...
                'Undeclared or mistyped name ''%s'' in ''%s''.'], ...
                undeclared{:});
        end
        
        if any(~validlhs)
            utils.error('syeq',[utils.errorparsing(THIS), ...
                'Invalid LHS in this identity equation: ''%s''.'], ...
                THIS.eqtn{~validlhs});
        end
        
        if any(multiple)
            utils.error('syeq',[utils.errorparsing(THIS), ...
                'This variable occurs on the LHS ', ...
                'in more than one identity: ''%s''.'], ...
                THIS.name{multiple});
        end            
        
        function C = doreplacevariables(C1,C2,C3)
            index = strcmp(THIS.name,C2);
            if ~any(index)
                undeclared{end+1} = C2;
                undeclared{end+1} = THIS.eqtn{iieqtn};
                C = '';
                return
            end
            iiname = find(index);
            if ~isempty(C1) || THIS.nametype(iiname) == 4
                C = sprintf('L(%g)',iiname);
                return
            end
            if isempty(C3)
                tt = 0;
                C = sprintf('x(:,%g,t)',iiname);
            else
                tt = sscanf(C3(2:end-1),'%g');
                C = sprintf('x(:,%g,t%+g)',iiname,tt);
            end
            THIS.occur(iieqtn,iiname,tzero+tt) = true;
        end
        
    end
% doequations().

%**************************************************************************
    function dodiff()
        % Differentiate non-identity equations wrt current dates of variables, and
        % wrt shocks.
        for iieq = 1 : neqtn
            nmocc = myfindoccur(THIS,iieq,'variables');
            z = sydney.mydiffeqtn(THIS.eqtnf{iieq},1,nmocc,[],THIS.log,'bsx'); %#ok<FNDSB>
            x = str2double(z);
            if isnan(x)
                z = strrep(z,'$userdifflist$',THIS.userdifflist);
                THIS.deqtnx{iieq} = z;
            else
                THIS.deqtnx{iieq} = x;
            end
            % Only non-identities will be differentiated wrt shocks.
            if ~isident(iieq)
                nmocc = myfindoccur(THIS,iieq,'shocks');
                z = sydney.mydiffeqtn(THIS.eqtnf{iieq},1,nmocc,[],THIS.log,'bsx'); %#ok<FNDSB>
                x = str2double(z);
                if isnan(x)
                    z = strrep(z,'$userdifflist$',THIS.userdifflist);
                    THIS.deqtne{iieq} = z;
                else
                    THIS.deqtne{iieq} = x;
                end 
            end
        end
    end
% dodiff().

%**************************************************************************
    function doeqtn2afcn()
        for iieqtn = 1 : neqtn
            THIS.eqtnf{iieqtn} = ...
                strfun.vectorise(THIS.eqtnf{iieqtn});
            THIS.eqtnf{iieqtn} = ...
                str2func(['@(x,t,L)',THIS.eqtnf{iieqtn}]);
            if ~isnumeric(THIS.deqtnx{iieqtn})
                THIS.deqtnx{iieqtn} = ...
                    strfun.vectorise(THIS.deqtnx{iieqtn});
                THIS.deqtnx{iieqtn} = ...
                    str2func(['@(x,t,L)',THIS.deqtnx{iieqtn}]);
            end
            if ~isident(iieqtn) && ~isnumeric(THIS.deqtne{iieqtn})
                THIS.deqtne{iieqtn} = ...
                    strfun.vectorise(THIS.deqtne{iieqtn});
                THIS.deqtne{iieqtn} = ...
                    str2func(['@(x,t,L)',THIS.deqtne{iieqtn}]);
            end
        end
    end
% dodiffwrtvariables().

end