function [code,labels,export,subs,comment] = myreadcode( ...
    filelist,params,labels,export,parentfile,removecomments)
% myreadcode  [Not a public function] Preparser master file.
%
% Backend IRIS function.
% No help provided.

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

if isempty(params)
    params = struct([]);
end

if isempty(labels)
    labels = {};
end

if isempty(export)
    export = struct('filename',{},'content',{});
end

if isempty(parentfile)
    parentfile = '';
end

if isempty(removecomments)
    removecomments = {};
end

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

code = '';
comment = '';
subs = struct();

if ischar(filelist)
    filelist = {filelist};
end

filestr = '';
nfilelist = length(filelist);
for i = 1 : nfilelist
    code = [code,sprintf('\n'),file2char(filelist{i})]; %#ok<AGROW>
    filestr = [filestr,filelist{i}]; %#ok<AGROW>
    if i < nfilelist
        filestr = [filestr,' & ']; %#ok<AGROW>
    end
end

filestr = sprintf('<a href="matlab:edit %s">%s</a>',filestr,filestr);
if ~isempty(parentfile)
    filestr = [parentfile,' > ',filestr];
end
errorparsing = ['Error preparsing file(s) ',filestr,'. '];

% Convert end of lines.
code = strfun.converteols(code);

% Check if there is an initial %% comment line that will be used as comment
% in model objects.
tokens = regexp(code,'^\s*%%([^\n])+','tokens','once');
if ~isempty(tokens)
    comment = strtrim(tokens{1});
end

% Read quoted strings 'xxx' and "xxx" and replace them with #(00).
% The quoted strings must be contained at one line.
[code,labels] = xxreadlabels(code,labels);

% Remove standard line and block comments.
code = strfun.removecomments(code,removecomments{:});

% Remove triple exclamation point !!!.
% This mark is meant to be used to highlight some bits of the code.
code = strrep(code,'!!!','');

% Characters beyond char(highcharcode) not allowed except comments.
% Default is 1999.
charcap = irisget('highcharcode');
if any(code > char(charcap))
    utils.error('preparser',[errorparsing, ...
        'The file contains characters beyond char(%g).'],charcap);
end

% Replace @keywords with !keywords. This is for backward compatibility
% only.
code = xxprefix(code);

% Discard everything after !stop.
pos = strfind(code,'!stop');
if ~isempty(pos)
    code = code(1:pos(1)-1);
end

% Add a white space at the end.
code = [code,sprintf('\n')];

% EXECUTE CONTROL COMMANDS
% =========================

% Evaluate and expand the following control commands:
% * !if .. !else .. !elseif .. !end
% * !for .. !do .. !end
% * !switch .. !case ... !otherwise .. !end
% * !export .. !end

[code,export,err] = preparser.myparsecontrols(code,params,labels,export);

if ~isempty(err.code)
    utils.error('preparser', [errorparsing, ...
        'Something wrong with this control command(s) or commands nested inside: ''%s...''.'], ...
        xxformaterror(err.code,labels));
end

if ~isempty(err.exprsn)
    utils.error('preparser', [errorparsing, ...
        'Cannot evaluate this control expression: ''%s...''.'], ...
        xxformaterror(err.exprsn,labels));
end

if ~isempty(err.leftover)
    utils.error('preparser', [errorparsing, ...
        'This control command is miplaced or unfinished: ''%s...''.'], ...
        xxformaterror(err.leftover,labels));
end

% IMPORT EXTERNAL FILES
% ======================

[code,labels,export] = xximport(code, ...
    params,labels,export,filestr,removecomments);

% EXPAND PSEUDOFUNCTIONS
% =======================

[code,invalid] = preparser.mypseudofunc(code);
if ~isempty(invalid)
    invalid = xxformaterror(invalid,labels);
    utils.error('preparser',[errorparsing, ...
        'Invalid pseudofunction: ''%s''.'], ...
        invalid{:});
end

% EXPAND SUBSTITUTIONS
% =====================

% Expand substitutions in the top file after all imports have been done.
if isempty(parentfile)
    [code,subs,leftover,multiple,undef] = preparser.mysubstitute(code);
    if ~isempty(leftover)
        leftover = xxformaterror(leftover,labels);
        utils.error('preparser',[errorparsing, ...
            'There is a leftover code in a substitutions block: ''%s''.'], ...
            leftover{:});
    end
    if ~isempty(multiple)
        multiple = xxformaterror(multiple,labels);
        utils.error('preparser',[errorparsing, ...
            'This substitution name is defined more than once: ''%s''.'], ...
            multiple{:});
    end
    if ~isempty(undef)
        utils.error('preparser',[errorparsing, ...
            'This is an unresolved or undefined substitution: ''%s''.'], ...
            undef{:});
    end
end

% Remove leading and trailing empty lines.
code = strfun.removeltel(code);

end

% Subfunctions.


%**************************************************************************
function code = xxprefix(code)
% doprefix  Replace @keywords with !keywords.
code = regexprep(code,'@([a-z]\w*)','!$1');
end
% xxprefix().

%**************************************************************************
function [code,labels,export] = ...
    xximport(code,params,labels,export,parentfile,removecomments)
% doimport  Import external file.
% Call import/include/input files with replacement.
pattern = '(?:!include|!input|!import)\((.*?)\)';
while true
    [tokens,start,finish] = ...
        regexp(code,pattern,'tokens','start','end','once');
    if isempty(tokens)
        break
    end
    fname = strtrim(tokens{1});
    if ~isempty(fname)
        [impcode,labels,export] = preparser.myreadcode(fname, ...
            params,labels,export,parentfile,removecomments);
        code = [code(1:start-1),impcode,code(finish+1:end)];
    end
end
end
% xximport().

%**************************************************************************
function [code,labels] = xxreadlabels(code,labels)
    function out = processlabel_(text)
        labels{end+1} = text;
        out = sprintf('#(%g)',length(labels));
    end
replace = @processlabel_; %#ok<NASGU>
% '\1' cannot be used within [^...], therefore we cannot exclude the
% opening quote (either apostrophe or double quote) from the string.
code = regexprep(code, ...
    '([''"])([^\n]*?)\1','${replace($2)}');
end
% xxreadlabels().

%**************************************************************************
function x = xxlabelsback(x,labels)

    function s = replace(x)
        s = '''''';
        x = sscanf(x,'#(%g)');
        if ~isempty(x) && ~isnan(x)
            s = ['''',labels{x},''''];
        end
    end
% End of nested function replace().
replacefunc = @replace; %#ok<NASGU>
x = regexprep(x,'(#\(\d+\))','${replacefunc($1)}');

end
% xxlabelsback().

%**************************************************************************
function c = xxformaterror(c,labels)

if iscell(c)
    for i = 1 : length(c)
        c{i} = xxformaterror(c{i},labels);
    end
    return
end
c = xxlabelsback(c,labels);
c = regexprep(c,'\s+',' ');
c = strtrim(c);
c = strfun.maxdisp(c,40);

end
% xxformatforerror().