2019-01-22 00:57:24 +01:00
|
|
|
function [Y, lhssub, X, residual, fp, lp] = parse_ols_style_equation(ds, ast)
|
|
|
|
%function [Y, lhssub, X, residual, fp, lp] = parse_ols_style_equation(ds, ast)
|
2019-01-10 14:53:07 +01:00
|
|
|
% Run OLS on chosen model equations; unlike olseqs, allow for time t
|
|
|
|
% endogenous variables on LHS
|
|
|
|
%
|
|
|
|
% INPUTS
|
2019-01-15 11:06:31 +01:00
|
|
|
% ds [dseries] data
|
|
|
|
% ast [struct] AST representing the equation to be parsed
|
2019-01-10 14:53:07 +01:00
|
|
|
%
|
|
|
|
% OUTPUTS
|
2019-01-15 11:06:31 +01:00
|
|
|
% Y [dseries] LHS of the equation (with lhssub subtracted)
|
|
|
|
% lhssub [dseries] RHS subtracted from LHS
|
|
|
|
% X [dseries] RHS of the equation
|
|
|
|
% residual [string] name of residual in equation
|
|
|
|
% fp [date] first common observed period between Y, lhssub, and X
|
|
|
|
% lp [date] last common observed period between Y, lhssub, and X
|
2019-01-10 14:53:07 +01:00
|
|
|
%
|
|
|
|
% SPECIAL REQUIREMENTS
|
|
|
|
% none
|
|
|
|
|
|
|
|
% Copyright (C) 2019 Dynare Team
|
|
|
|
%
|
|
|
|
% This file is part of Dynare.
|
|
|
|
%
|
|
|
|
% Dynare is free software: you can redistribute it and/or modify
|
|
|
|
% it under the terms of the GNU General Public License as published by
|
|
|
|
% the Free Software Foundation, either version 3 of the License, or
|
|
|
|
% (at your option) any later version.
|
|
|
|
%
|
|
|
|
% Dynare is distributed in the hope that it will be useful,
|
|
|
|
% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
% GNU General Public License for more details.
|
|
|
|
%
|
|
|
|
% You should have received a copy of the GNU General Public License
|
|
|
|
% along with Dynare. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2019-01-15 11:06:31 +01:00
|
|
|
%% Check inputs
|
2019-01-22 00:57:24 +01:00
|
|
|
if nargin ~= 2
|
|
|
|
error('parse_ols_style_equation takes 2 arguments')
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
if isempty(ds) || ~isdseries(ds)
|
|
|
|
error('parse_ols_style_equation: arg 1 must be a dseries');
|
|
|
|
end
|
|
|
|
|
2019-01-15 11:06:31 +01:00
|
|
|
if isempty(ast) || ~isstruct(ast)
|
2019-01-22 00:57:24 +01:00
|
|
|
error('parse_ols_style_equation: arg 2 must be a struct');
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
|
2019-01-11 17:27:42 +01:00
|
|
|
line = ast.line;
|
2019-01-10 14:53:07 +01:00
|
|
|
if ~strcmp(ast.AST.node_type, 'BinaryOpNode') ...
|
|
|
|
|| ~strcmp(ast.AST.op, '=')
|
2019-01-15 11:05:27 +01:00
|
|
|
parsing_error('expecting equation with equal sign', line);
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
% Check LHS
|
|
|
|
if ~strcmp(ast.AST.arg1.node_type, 'VariableNode') ...
|
|
|
|
&& ~strcmp(ast.AST.arg1.node_type, 'UnaryOpNode')
|
2019-01-15 11:05:27 +01:00
|
|
|
parsing_error('expecting Variable or UnaryOp on LHS', line);
|
2019-01-10 14:53:07 +01:00
|
|
|
else
|
2019-01-18 11:50:10 +01:00
|
|
|
if ~isOlsVar(ds, ast.AST.arg1) || ~isBaseVarLagEqualToZero(ast.AST.arg1)
|
2019-02-01 11:12:25 +01:00
|
|
|
parsing_error('the LHS of the equation must be an Variable or UnaryOp with lag == 0 that exists in the dataset', line);
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-01-15 11:06:31 +01:00
|
|
|
%% Set LHS (Y)
|
2019-01-10 14:53:07 +01:00
|
|
|
lhssub = dseries();
|
|
|
|
Y = evalNode(ds, ast.AST.arg1, line, dseries());
|
|
|
|
|
2019-01-15 11:06:31 +01:00
|
|
|
%% Set RHS (X)
|
2019-01-10 14:53:07 +01:00
|
|
|
plus_node = ast.AST.arg2;
|
|
|
|
last_node_to_parse = [];
|
|
|
|
residual = '';
|
|
|
|
X = dseries();
|
|
|
|
while ~isempty(plus_node) || ~isempty(last_node_to_parse)
|
|
|
|
Xtmp = dseries();
|
|
|
|
if isempty(last_node_to_parse)
|
|
|
|
[plus_node, node_to_parse, last_node_to_parse] = findNextplus_node(plus_node, line);
|
|
|
|
else
|
|
|
|
node_to_parse = last_node_to_parse;
|
|
|
|
last_node_to_parse = [];
|
|
|
|
end
|
2019-01-15 11:23:59 +01:00
|
|
|
if strcmp(node_to_parse.node_type, 'VariableNode')
|
|
|
|
if strcmp(node_to_parse.type, 'parameter')
|
|
|
|
% Intercept
|
2019-01-29 14:52:03 +01:00
|
|
|
Xtmp = dseries(1, ds.dates, node_to_parse.name);
|
2019-01-15 11:23:59 +01:00
|
|
|
elseif strcmp(node_to_parse.type, 'exogenous') && ~any(strcmp(ds.name, node_to_parse.name))
|
|
|
|
% Residual if not contained in ds
|
|
|
|
if isempty(residual)
|
|
|
|
residual = node_to_parse.name;
|
2019-01-10 14:53:07 +01:00
|
|
|
else
|
2019-01-15 11:23:59 +01:00
|
|
|
parsing_error(['only one residual allowed per equation; encountered ' residual ' & ' node_to_parse.name], line);
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
2019-01-15 11:23:59 +01:00
|
|
|
elseif strcmp(node_to_parse.type, 'endogenous') ...
|
|
|
|
|| (strcmp(node_to_parse.type, 'exogenous') && any(strcmp(ds.name, node_to_parse.name)))
|
|
|
|
% Subtract VariableNode from LHS
|
2019-01-10 14:53:07 +01:00
|
|
|
% NB: treat exogenous that exist in ds as endogenous
|
|
|
|
lhssub = lhssub + evalNode(ds, node_to_parse, line, dseries());
|
2019-01-15 11:23:59 +01:00
|
|
|
else
|
2019-02-01 16:26:25 +01:00
|
|
|
parsing_error('unexpected variable type found', line, node_to_parse);
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
2019-01-15 11:23:59 +01:00
|
|
|
elseif strcmp(node_to_parse.node_type, 'UnaryOpNode')
|
|
|
|
% Subtract UnaryOpNode from LHS
|
|
|
|
% NB: treat exogenous that exist in ds as endogenous
|
|
|
|
lhssub = lhssub + evalNode(ds, node_to_parse, line, dseries());
|
2019-01-10 14:53:07 +01:00
|
|
|
elseif strcmp(node_to_parse.node_type, 'BinaryOpNode') && strcmp(node_to_parse.op, '*')
|
|
|
|
% Parse param_expr * endog_expr
|
|
|
|
Xtmp = parseTimesNode(ds, node_to_parse, line);
|
2019-01-22 15:23:42 +01:00
|
|
|
if Xtmp.vobs > 1 || ...
|
|
|
|
(Xtmp.vobs == 1 && ~isnan(str2double(Xtmp.name)))
|
2019-01-10 14:53:07 +01:00
|
|
|
% Handle constraits
|
|
|
|
% Look through Xtmp names for constant
|
|
|
|
% if found, subtract from LHS
|
2019-01-22 15:25:17 +01:00
|
|
|
names = Xtmp.name;
|
|
|
|
for j = length(names):-1:1
|
|
|
|
if ~isnan(str2double(names{j}))
|
|
|
|
lhssub = lhssub + str2double(names{j}) * Xtmp.(names{j});
|
|
|
|
Xtmp = Xtmp.remove(names{j});
|
2019-01-17 17:00:42 +01:00
|
|
|
else
|
|
|
|
% Multiply by -1 now so that it can be added together below
|
|
|
|
% Otherwise, it would matter which was encountered first,
|
|
|
|
% a parameter on its own or a linear constraint
|
2019-01-22 15:25:17 +01:00
|
|
|
Xtmp.(names{j}) = -1 * Xtmp.(names{j});
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
else
|
2019-02-01 16:26:25 +01:00
|
|
|
parsing_error('didn''t expect to arrive here', line, node_to_parse);
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
2019-01-17 17:00:42 +01:00
|
|
|
|
2019-01-22 15:25:17 +01:00
|
|
|
names = Xtmp.name;
|
|
|
|
for j = length(names):-1:1
|
2019-01-17 17:00:42 +01:00
|
|
|
% Handle constraits
|
2019-01-22 15:25:17 +01:00
|
|
|
idx = find(strcmp(X.name, names{j}));
|
2019-01-17 17:00:42 +01:00
|
|
|
if ~isempty(idx)
|
|
|
|
X.(X.name{idx}) = X{idx} + Xtmp{j};
|
2019-01-22 15:25:17 +01:00
|
|
|
Xtmp = Xtmp.remove(names{j});
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
end
|
2019-01-17 17:00:42 +01:00
|
|
|
X = [X Xtmp];
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
Y = Y - lhssub;
|
2019-01-15 11:06:31 +01:00
|
|
|
|
|
|
|
%% Set start and end dates
|
2019-01-17 15:15:35 +01:00
|
|
|
fp = Y.firstobservedperiod;
|
|
|
|
lp = Y.lastobservedperiod;
|
|
|
|
if ~isempty(X)
|
|
|
|
% X is empty when AR(1) without parameter is encountered
|
|
|
|
fp = max(fp, X.firstobservedperiod);
|
|
|
|
lp = min(lp, X.lastobservedperiod);
|
|
|
|
end
|
2019-01-15 11:06:31 +01:00
|
|
|
if ~isempty(lhssub)
|
|
|
|
fp = max(fp, lhssub.firstobservedperiod);
|
|
|
|
lp = min(lp, lhssub.lastobservedperiod);
|
|
|
|
end
|
|
|
|
|
|
|
|
% If it exists, account for tag set in mod file
|
2019-01-22 00:57:24 +01:00
|
|
|
if isfield(ast, 'tags') ...
|
|
|
|
&& isfield(ast.tags, 'sample') ...
|
|
|
|
&& ~isempty(ast.tags.sample)
|
|
|
|
colon_idx = strfind(ast.tags.sample, ':');
|
|
|
|
fsd = dates(ast.tags.sample(1:colon_idx-1));
|
|
|
|
lsd = dates(ast.tags.sample(colon_idx+1:end));
|
2019-01-15 11:06:31 +01:00
|
|
|
if fp > fsd
|
|
|
|
warning(['The sample over which you want to estimate contains NaNs. '...
|
|
|
|
'Adjusting estimation range to begin on: ' fp.char])
|
|
|
|
else
|
|
|
|
fp = fsd;
|
|
|
|
end
|
|
|
|
if lp < lsd
|
|
|
|
warning(['The sample over which you want to estimate contains NaNs. '...
|
|
|
|
'Adjusting estimation range to end on: ' lp.char])
|
|
|
|
else
|
|
|
|
lp = lsd;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
Y = Y(fp:lp);
|
2019-01-17 15:15:35 +01:00
|
|
|
if ~isempty(X)
|
|
|
|
X = X(fp:lp);
|
2019-02-05 16:38:25 +01:00
|
|
|
names = X.name;
|
|
|
|
for i = 1:length(names)
|
|
|
|
if all(X.(names{i}).data == 0)
|
|
|
|
X = X.remove(names{i});
|
|
|
|
end
|
|
|
|
end
|
2019-01-17 15:15:35 +01:00
|
|
|
end
|
2019-01-15 11:06:31 +01:00
|
|
|
if ~isempty(lhssub)
|
|
|
|
lhssub = lhssub(fp:lp);
|
|
|
|
end
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
%% Helper Functions
|
2019-02-01 16:26:25 +01:00
|
|
|
function parsing_error(msg, line, node)
|
2019-02-05 19:36:11 +01:00
|
|
|
if nargin == 3 && ~isempty(node)
|
2019-02-01 16:26:25 +01:00
|
|
|
error('\nERROR encountered parsing `%s` in equation on line %d: %s\n', printNode(node), line, msg);
|
|
|
|
else
|
2019-02-06 12:14:07 +01:00
|
|
|
error('\nERROR encountered parsing of equation on line %d: %s\n', line, msg)
|
2019-02-01 16:26:25 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function str = printNode(node)
|
|
|
|
if strcmp(node.node_type, 'NumConstNode')
|
|
|
|
str = num2str(node.value);
|
|
|
|
elseif strcmp(node.node_type, 'VariableNode')
|
|
|
|
if strcmp(node.type, 'endogenous') ...
|
|
|
|
|| (strcmp(node.type, 'exogenous') && any(strcmp(ds.name, node.name)))
|
|
|
|
str = node.name;
|
|
|
|
if node.lag ~= 0
|
|
|
|
str = [str '(' num2str(node.lag) ')'];
|
|
|
|
end
|
|
|
|
elseif strcmp(node.type, 'parameter')
|
|
|
|
str = node.name;
|
|
|
|
end
|
|
|
|
elseif strcmp(node.node_type, 'UnaryOpNode')
|
|
|
|
str = printNode(node.arg);
|
|
|
|
str = [node.op '(' str ')'];
|
|
|
|
elseif strcmp(node.node_type, 'BinaryOpNode')
|
|
|
|
str = ['(' printNode(node.arg1) node.op printNode(node.arg2) ')'];
|
|
|
|
end
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
function [next_plus_node, node_to_parse, last_node_to_parse] = findNextplus_node(plus_node, line)
|
|
|
|
% Given an additive entry in the AST, find the next additive entry
|
|
|
|
% (next_plus_node). Also find the node that will be parsed into
|
|
|
|
% parameter*endogenous||param||exog|endog (node_to_parse).
|
|
|
|
% Function used for moving through the AST.
|
|
|
|
if ~(strcmp(plus_node.node_type, 'BinaryOpNode') && strcmp(plus_node.op, '+'))
|
2019-01-15 11:05:27 +01:00
|
|
|
parsing_error('pairs of nodes must be separated additively', line);
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
next_plus_node = [];
|
|
|
|
last_node_to_parse = [];
|
|
|
|
if strcmp(plus_node.arg1.node_type, 'BinaryOpNode') && strcmp(plus_node.arg1.op, '+')
|
|
|
|
next_plus_node = plus_node.arg1;
|
|
|
|
node_to_parse = getOlsNode(plus_node.arg2, line);
|
|
|
|
elseif strcmp(plus_node.arg2.node_type, 'BinaryOpNode') && strcmp(plus_node.arg2.op, '+')
|
|
|
|
next_plus_node = plus_node.arg2;
|
|
|
|
node_to_parse = getOlsNode(plus_node.arg1, line);
|
|
|
|
else
|
|
|
|
node_to_parse = getOlsNode(plus_node.arg1, line);
|
|
|
|
last_node_to_parse = getOlsNode(plus_node.arg2, line);
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function node_to_parse = getOlsNode(node, line)
|
|
|
|
if ~(strcmp(node.node_type, 'BinaryOpNode') && strcmp(node.op, '*')) ...
|
|
|
|
&& ~strcmp(node.node_type, 'VariableNode') ...
|
|
|
|
&& ~strcmp(node.node_type, 'UnaryOpNode')
|
2019-02-06 12:16:27 +01:00
|
|
|
parsing_error('couldn''t find node to parse', line, node);
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
node_to_parse = node;
|
|
|
|
end
|
|
|
|
|
|
|
|
function X = parseTimesNode(ds, node, line)
|
|
|
|
% Separate the parameter expression from the endogenous expression
|
|
|
|
assert(strcmp(node.node_type, 'BinaryOpNode') && strcmp(node.op, '*'))
|
2019-02-01 14:25:35 +01:00
|
|
|
|
|
|
|
if isOlsParamExpr(node.arg1, line)
|
|
|
|
param = assignParam([], node.arg1, line);
|
|
|
|
X = assignEndog(ds, node.arg2, line, dseries());
|
|
|
|
elseif isOlsParamExpr(node.arg2, line)
|
|
|
|
param = assignParam([], node.arg2, line);
|
|
|
|
X = assignEndog(ds, node.arg1, line, dseries());
|
|
|
|
else
|
2019-02-01 16:26:25 +01:00
|
|
|
parsing_error('expecting (param expr)*(var expr)', line, node);
|
2019-02-01 14:25:35 +01:00
|
|
|
end
|
2019-01-10 14:53:07 +01:00
|
|
|
X = X.rename(param{1});
|
|
|
|
for ii = 2:length(param)
|
|
|
|
X = [X dseries(X{1}.data, X{1}.firstdate, param{ii})];
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-02-01 14:25:35 +01:00
|
|
|
function X = assignEndog(ds, node, line, X)
|
|
|
|
if ~isempty(X)
|
2019-02-01 16:26:25 +01:00
|
|
|
parsing_error(['got endog * endog' node.name ' (' node.type ')'], line, node);
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
2019-02-01 14:25:35 +01:00
|
|
|
X = evalNode(ds, node, line, X);
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
function param = assignParam(param, node, line)
|
|
|
|
if ~isempty(param)
|
2019-02-01 16:26:25 +01:00
|
|
|
parsing_error(['got param * param' node.name ' (' node.type ')'], line, node);
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
param = assignParamHelper(param, node, line);
|
|
|
|
end
|
|
|
|
|
|
|
|
function param = assignParamHelper(param, node, line)
|
|
|
|
if strcmp(node.node_type, 'NumConstNode')
|
|
|
|
param{end+1} = num2str(node.value);
|
|
|
|
elseif strcmp(node.node_type, 'VariableNode')
|
|
|
|
param{end+1} = node.name;
|
|
|
|
elseif strcmp(node.node_type, 'BinaryOpNode')
|
|
|
|
if ~strcmp(node.op, '-')
|
2019-02-01 16:26:25 +01:00
|
|
|
parsing_error(['got unexpected parameter op ' node.op], line, node);
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
param = assignParamHelper(param, node.arg1, line);
|
|
|
|
param = assignParamHelper(param, node.arg2, line);
|
|
|
|
else
|
2019-02-01 16:26:25 +01:00
|
|
|
parsing_error(['got unexpected node (' node.type ')'], line, node);
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-01-18 11:50:10 +01:00
|
|
|
function tf = isBaseVarLagEqualToZero(node)
|
|
|
|
if strcmp(node.node_type, 'VariableNode')
|
|
|
|
tf = node.lag == 0;
|
|
|
|
elseif strcmp(node.node_type, 'UnaryOpNode')
|
|
|
|
tf = isBaseVarLagEqualToZero(node.arg);
|
|
|
|
else
|
|
|
|
tf = false;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-01-11 11:47:55 +01:00
|
|
|
function tf = isOlsVar(ds, node)
|
2019-01-10 14:53:07 +01:00
|
|
|
if strcmp(node.node_type, 'VariableNode') ...
|
|
|
|
&& (strcmp(node.type, 'endogenous') ...
|
|
|
|
|| (strcmp(node.type, 'exogenous') && any(strcmp(ds.name, node.name))))
|
|
|
|
tf = true;
|
2019-01-18 11:50:10 +01:00
|
|
|
elseif strcmp(node.node_type, 'UnaryOpNode')
|
|
|
|
tf = isOlsVar(ds, node.arg);
|
2019-01-10 14:53:07 +01:00
|
|
|
else
|
|
|
|
tf = false;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function X = evalNode(ds, node, line, X)
|
2019-02-01 14:25:35 +01:00
|
|
|
global M_
|
2019-01-10 14:53:07 +01:00
|
|
|
if strcmp(node.node_type, 'NumConstNode')
|
2019-02-01 11:37:41 +01:00
|
|
|
X = dseries(node.value, ds.dates, 'const');
|
2019-01-10 14:53:07 +01:00
|
|
|
elseif strcmp(node.node_type, 'VariableNode')
|
2019-02-01 14:25:35 +01:00
|
|
|
if strcmp(node.type, 'endogenous') ...
|
|
|
|
|| (strcmp(node.type, 'exogenous') && any(strcmp(ds.name, node.name)))
|
|
|
|
X = ds.(node.name)(node.lag);
|
|
|
|
elseif strcmp(node.type, 'parameter')
|
|
|
|
X = M_.params(not(cellfun('isempty', strfind(M_.param_names, node.name))));
|
2019-02-01 16:26:25 +01:00
|
|
|
if isnan(X) || isinf(X) || ~isreal(X)
|
|
|
|
parsing_error(['Value incorrectly set for parameter: ' node.name], line);
|
|
|
|
end
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
elseif strcmp(node.node_type, 'UnaryOpNode')
|
|
|
|
Xtmp = evalNode(ds, node.arg, line, X);
|
|
|
|
% Only works if dseries supports . notation for unary op (true for log/diff)
|
|
|
|
% Otherwise, use: X = eval([node.op '(Xtmp)']);
|
2019-02-01 16:26:25 +01:00
|
|
|
try
|
2019-02-05 19:52:12 +01:00
|
|
|
if strcmp(node.op, 'uminus')
|
|
|
|
X = -Xtmp;
|
|
|
|
else
|
|
|
|
X = Xtmp.(node.op);
|
|
|
|
end
|
2019-02-01 16:26:25 +01:00
|
|
|
if any(isinf(X)) || ~isreal(X)
|
|
|
|
parsing_error(['Error applying ' node.op], line, node);
|
|
|
|
end
|
|
|
|
catch
|
|
|
|
parsing_error(['Error applying ' node.op], line, node);
|
|
|
|
end
|
2019-01-10 14:53:07 +01:00
|
|
|
elseif strcmp(node.node_type, 'BinaryOpNode')
|
|
|
|
Xtmp1 = evalNode(ds, node.arg1, line, X);
|
|
|
|
Xtmp2 = evalNode(ds, node.arg2, line, X);
|
2019-02-01 14:28:27 +01:00
|
|
|
switch node.op
|
|
|
|
case '*'
|
|
|
|
Xtmp = Xtmp1 * Xtmp2;
|
|
|
|
case '/'
|
|
|
|
Xtmp = Xtmp1 / Xtmp2;
|
|
|
|
case '+'
|
|
|
|
Xtmp = Xtmp1 + Xtmp2;
|
|
|
|
case '-'
|
|
|
|
Xtmp = Xtmp1 - Xtmp2;
|
|
|
|
otherwise
|
2019-02-01 16:26:25 +01:00
|
|
|
parsing_error(['got unexpected binary op ' node.op], line, node);
|
|
|
|
end
|
|
|
|
if any(isinf(Xtmp)) || ~isreal(Xtmp)
|
|
|
|
parsing_error(['Error applying ' node.op], line, node);
|
2019-02-01 14:28:27 +01:00
|
|
|
end
|
|
|
|
X = X + Xtmp;
|
2019-01-10 14:53:07 +01:00
|
|
|
else
|
2019-02-01 16:26:25 +01:00
|
|
|
parsing_error(['got unexpected node type ' node.node_type], line, node);
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function tf = isOlsParamExpr(node, line)
|
|
|
|
if strcmp(node.node_type, 'NumConstNode')
|
|
|
|
tf = true;
|
|
|
|
elseif strcmp(node.node_type, 'VariableNode')
|
2019-02-01 12:04:46 +01:00
|
|
|
if strcmp(node.type, 'parameter')
|
|
|
|
tf = true;
|
|
|
|
else
|
|
|
|
tf = false;
|
|
|
|
end
|
2019-01-10 14:53:07 +01:00
|
|
|
elseif strcmp(node.node_type, 'UnaryOpNode')
|
|
|
|
tf = false;
|
|
|
|
elseif strcmp(node.node_type, 'BinaryOpNode')
|
2019-02-01 17:01:04 +01:00
|
|
|
tf = isOlsParamExpr(node.arg1, line) && isOlsParamExpr(node.arg2, line);
|
2019-01-10 14:53:07 +01:00
|
|
|
if tf && ~strcmp(node.op, '-')
|
2019-02-01 16:26:25 +01:00
|
|
|
parsing_error(['got unexpected op ' node.op], line, node);
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
else
|
2019-02-01 16:26:25 +01:00
|
|
|
parsing_error(['got unexpected type ' node.node_type], line, node);
|
2019-01-10 14:53:07 +01:00
|
|
|
end
|
|
|
|
end
|