GNU Octave
3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
Main Page
Namespaces
Classes
Files
File List
File Members
All
Classes
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Properties
Friends
Macros
Pages
libinterp
parse-tree
pt-binop.cc
Go to the documentation of this file.
1
/*
2
3
Copyright (C) 1996-2013 John W. Eaton
4
5
This file is part of Octave.
6
7
Octave is free software; you can redistribute it and/or modify it
8
under the terms of the GNU General Public License as published by the
9
Free Software Foundation; either version 3 of the License, or (at your
10
option) any later version.
11
12
Octave is distributed in the hope that it will be useful, but WITHOUT
13
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15
for more details.
16
17
You should have received a copy of the GNU General Public License
18
along with Octave; see the file COPYING. If not, see
19
<http://www.gnu.org/licenses/>.
20
21
*/
22
23
#ifdef HAVE_CONFIG_H
24
#include <config.h>
25
#endif
26
27
#include "
error.h
"
28
#include "
defun.h
"
29
#include "
oct-obj.h
"
30
#include "
ov.h
"
31
#include "
profiler.h
"
32
#include "
pt-binop.h
"
33
#include "
pt-bp.h
"
34
#include "
pt-walk.h
"
35
#include "
variables.h
"
36
37
// TRUE means we mark | and & expressions for braindead short-circuit
38
// behavior.
39
static
bool
Vdo_braindead_shortcircuit_evaluation
;
40
41
// Binary expressions.
42
43
octave_value_list
44
tree_binary_expression::rvalue
(
int
nargout)
45
{
46
octave_value_list
retval;
47
48
if
(nargout > 1)
49
error
(
"binary operator '%s': invalid number of output arguments"
,
50
oper
() . c_str ());
51
else
52
retval =
rvalue1
(nargout);
53
54
return
retval;
55
}
56
57
octave_value
58
tree_binary_expression::rvalue1
(
int
)
59
{
60
octave_value
retval;
61
62
if
(
error_state
)
63
return
retval;
64
65
if
(Vdo_braindead_shortcircuit_evaluation
66
&&
eligible_for_braindead_shortcircuit
)
67
{
68
if
(
op_lhs
)
69
{
70
octave_value
a =
op_lhs
->
rvalue1
();
71
72
if
(!
error_state
)
73
{
74
if
(a.
ndims
() == 2 && a.
rows
() == 1 && a.
columns
() == 1)
75
{
76
bool
result =
false
;
77
78
bool
a_true = a.
is_true
();
79
80
if
(!
error_state
)
81
{
82
if
(a_true)
83
{
84
if
(
etype
==
octave_value::op_el_or
)
85
{
86
result =
true
;
87
goto
done;
88
}
89
}
90
else
91
{
92
if
(
etype
==
octave_value::op_el_and
)
93
goto
done;
94
}
95
96
if
(
op_rhs
)
97
{
98
octave_value
b =
op_rhs
->
rvalue1
();
99
100
if
(!
error_state
)
101
result = b.
is_true
();
102
}
103
104
done:
105
106
if
(!
error_state
)
107
return
octave_value
(result);
108
}
109
}
110
}
111
}
112
}
113
114
if
(
op_lhs
)
115
{
116
octave_value
a =
op_lhs
->
rvalue1
();
117
118
if
(!
error_state
&& a.
is_defined
() &&
op_rhs
)
119
{
120
octave_value
b =
op_rhs
->
rvalue1
();
121
122
if
(!
error_state
&& b.
is_defined
())
123
{
124
BEGIN_PROFILER_BLOCK
(
"binary "
+
oper
())
125
126
// Note: The profiler does not catch the braindead
127
// short-circuit evaluation code above, but that should be
128
// ok. The evaluation of operands and the operator itself
129
// is entangled and it's not clear where to start/stop
130
// timing the operator to make it reasonable.
131
132
retval =
::do_binary_op
(
etype
, a, b);
133
134
if
(
error_state
)
135
retval =
octave_value
();
136
137
END_PROFILER_BLOCK
138
}
139
}
140
}
141
142
return
retval;
143
}
144
145
std::string
146
tree_binary_expression::oper
(
void
)
const
147
{
148
return
octave_value::binary_op_as_string
(
etype
);
149
}
150
151
tree_expression
*
152
tree_binary_expression::dup
(
symbol_table::scope_id
scope,
153
symbol_table::context_id
context
)
const
154
{
155
tree_binary_expression
*new_be
156
=
new
tree_binary_expression
(
op_lhs
?
op_lhs
->
dup
(scope, context) : 0,
157
op_rhs
?
op_rhs
->
dup
(scope, context) : 0,
158
line
(),
column
(),
etype
);
159
160
new_be->
copy_base
(*
this
);
161
162
return
new_be;
163
}
164
165
void
166
tree_binary_expression::accept
(
tree_walker
& tw)
167
{
168
tw.
visit_binary_expression
(*
this
);
169
}
170
171
// Boolean expressions.
172
173
octave_value_list
174
tree_boolean_expression::rvalue
(
int
nargout)
175
{
176
octave_value_list
retval;
177
178
if
(nargout > 1)
179
error
(
"binary operator '%s': invalid number of output arguments"
,
180
oper
() . c_str ());
181
else
182
retval =
rvalue1
(nargout);
183
184
return
retval;
185
}
186
187
octave_value
188
tree_boolean_expression::rvalue1
(
int
)
189
{
190
octave_value
retval;
191
192
if
(
error_state
)
193
return
retval;
194
195
bool
result =
false
;
196
197
// This evaluation is not caught by the profiler, since we can't find
198
// a reasonable place where to time. Note that we don't want to
199
// include evaluation of LHS or RHS into the timing, but this is
200
// entangled together with short-circuit evaluation here.
201
202
if
(
op_lhs
)
203
{
204
octave_value
a =
op_lhs
->
rvalue1
();
205
206
if
(!
error_state
)
207
{
208
bool
a_true = a.
is_true
();
209
210
if
(!
error_state
)
211
{
212
if
(a_true)
213
{
214
if
(
etype
==
bool_or
)
215
{
216
result =
true
;
217
goto
done;
218
}
219
}
220
else
221
{
222
if
(
etype
==
bool_and
)
223
goto
done;
224
}
225
226
if
(
op_rhs
)
227
{
228
octave_value
b =
op_rhs
->
rvalue1
();
229
230
if
(!
error_state
)
231
result = b.
is_true
();
232
}
233
234
done:
235
236
if
(!
error_state
)
237
retval =
octave_value
(result);
238
}
239
}
240
}
241
242
return
retval;
243
}
244
245
std::string
246
tree_boolean_expression::oper
(
void
)
const
247
{
248
std::string retval =
"<unknown>"
;
249
250
switch
(
etype
)
251
{
252
case
bool_and
:
253
retval =
"&&"
;
254
break
;
255
256
case
bool_or
:
257
retval =
"||"
;
258
break
;
259
260
default
:
261
break
;
262
}
263
264
return
retval;
265
}
266
267
tree_expression
*
268
tree_boolean_expression::dup
(
symbol_table::scope_id
scope,
269
symbol_table::context_id
context
)
const
270
{
271
tree_boolean_expression
*new_be
272
=
new
tree_boolean_expression
(
op_lhs
?
op_lhs
->
dup
(scope, context) : 0,
273
op_rhs
?
op_rhs
->
dup
(scope, context) : 0,
274
line
(),
column
(),
etype
);
275
276
new_be->
copy_base
(*
this
);
277
278
return
new_be;
279
}
280
281
DEFUN
(do_braindead_shortcircuit_evaluation, args, nargout,
282
"-*- texinfo -*-\n\
283
@deftypefn {Built-in Function} {@var{val} =} do_braindead_shortcircuit_evaluation ()\n\
284
@deftypefnx {Built-in Function} {@var{old_val} =} do_braindead_shortcircuit_evaluation (@var{new_val})\n\
285
@deftypefnx {Built-in Function} {} do_braindead_shortcircuit_evaluation (@var{new_val}, \"local\")\n\
286
Query or set the internal variable that controls whether Octave will\n\
287
do short-circuit evaluation of @samp{|} and @samp{&} operators inside the\n\
288
conditions of if or while statements.\n\
289
\n\
290
This feature is only provided for compatibility with @sc{matlab} and should\n\
291
not be used unless you are porting old code that relies on this feature.\n\
292
\n\
293
To obtain short-circuit behavior for logical expressions in new programs,\n\
294
you should always use the @samp{&&} and @samp{||} operators.\n\
295
\n\
296
When called from inside a function with the @qcode{\"local\"} option, the\n\
297
variable is changed locally for the function and any subroutines it calls. \n\
298
The original variable value is restored when exiting the function.\n\
299
@end deftypefn"
)
300
{
301
return
SET_INTERNAL_VARIABLE
(do_braindead_shortcircuit_evaluation);
302
}
303
304
/*
305
%!test
306
%! x = 0;
307
%! do_braindead_shortcircuit_evaluation (0);
308
%! if (1 | (x = 1))
309
%! endif
310
%! assert (x, 1);
311
%! do_braindead_shortcircuit_evaluation (1);
312
%! if (1 | (x = 0))
313
%! endif
314
%! assert (x, 1);
315
*/
Generated on Mon Dec 30 2013 03:04:37 for GNU Octave by
1.8.1.2