Skip to content

Commit

Permalink
interp/oword: enable optional return values on 'return' and 'endsub'
Browse files Browse the repository at this point in the history
See nc_files/retval.ngc for an example.

there's a single global value '#<_value>' which holds the last returned value
Default for #<_value> is 0.
Document in gcode/main and gcode/overview.
Add test case in tests/interp/return-value.

Conflicts:

	src/emc/rs274ngc/rs274ngc_pre.cc
  • Loading branch information
Michael Haberler committed Oct 28, 2011
1 parent 1620409 commit 6905295
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 3 deletions.
30 changes: 29 additions & 1 deletion docs/src/gcode/main.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2051,11 +2051,39 @@ they are defined. They may be called from other functions, and may call
themselves recursively if it makes sense to do so. The maximum
subroutine nesting level is 10.

Subroutines do not have "return values", but they may change the value
=== Subroutine return values [[sec:Subroutine-return-values]]
Subroutines may pass optional return values when executing `return` or
`endsub`. The value of an optional expression after a `return` or
`endsub` sets the <<param:_value,`#<_value>`>> named parameter. A
`return` or `endsub` with no trailing expression sets `#<_value>` to
0:

[source,{ngc}]
---------------------------------------------------------------------
o1000 sub
o1010 if [#1 GT 0]
o1010 return [123] ; sets #<_value> to 123
o1010 endif

o1020 if [#1 LT 0]
o1020 return ; sets #<_value> to default value of 0
o1020 endif

o1000 endsub [4711] ; sets #<_value> to 4711

o1000 call [23]
o2000 if [#<_value> EQ 0] ; accessing the return value
...
---------------------------------------------------------------------

=== Subroutine side effects
Subroutines may change the value
of parameters above #30 and those changes will be visible to the
calling code. Subroutines may also change the value of global named
parameters.



== Looping: do, while, endwhile, break, continue (((Looping: do, while, endwhile, break, continue)))

The "while loop" has two structures: while/endwhile, and do/while. In
Expand Down
5 changes: 5 additions & 0 deletions docs/src/gcode/overview.txt
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,11 @@ program with if-then-else statements.
#<_w>::
Return absolute machine W coordinate. Same as #5428.

#<_value>:: [[param:_value]]
Return value from the last O-word `return` or `endsub`. Default
value 0 if no expression after `return` or `endsub`. Initialized
to 0 on program start. See also
<<sec:Subroutine-return-values,Subroutine return values>>.

== Expressions [[sub:Expressions]]

Expand Down
29 changes: 29 additions & 0 deletions nc_files/retval.ngc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
; demonstrate optional return values from endsub and return

o1000 sub
o1010 if [#1 GT 0]
o1010 return [123*[#1]]
o1010 endif

o1020 if [#1 LT 0]
o1020 return
o1020 endif

o1000 endsub [4712]

o1000 call [0]
(debug,call with arg1=0 return #<_value>)

; #<_value> is 4712.0

o1000 call [2]
(debug,call with arg1=2 return #<_value>)

; #<_value> is 246.0

o1000 call [-1]
(debug,call with arg1=-1 return #<_value>)

; #<_value> is 0.0

m2
1 change: 1 addition & 0 deletions src/emc/rs274ngc/interp_internal.hh
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ typedef struct setup_struct
char *skipping_to_sub; // o_name of sub skipping to (or zero)
int skipping_start; // start of skipping (sequence)
double test_value; // value for "if", "while", "elseif"
double return_value; // optional return value for "return", "endsub"
int call_level; // current subroutine level
context sub_context[INTERP_SUB_ROUTINE_LEVELS];
int oword_labels;
Expand Down
9 changes: 9 additions & 0 deletions src/emc/rs274ngc/interp_namedparams.cc
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,13 @@ int Interp::lookup_named_param(char *nameBuf,
*value = _setup.w_current;
break;

// o-word subs may optionally have an
// expression after endsub and return
// this 'function return value' is accessible as '_value'
case 249:
*value = _setup.return_value;
break;

default:
MSG("---BUG: lookup_named_param(%s) UNHANDLED INDEX=%f \n",
nameBuf,index);
Expand Down Expand Up @@ -660,5 +667,7 @@ int Interp::init_named_parameters()
init_readonly_param("_v", 247, PA_USE_LOOKUP);
init_readonly_param("_w", 248, PA_USE_LOOKUP);

// last (optional) endsub/return value
init_readonly_param("_value", 249, PA_USE_LOOKUP);
return INTERP_OK;
}
29 changes: 27 additions & 2 deletions src/emc/rs274ngc/interp_read.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1549,7 +1549,20 @@ int Interp::read_o( /* ARGUMENTS */
}
else if(block->o_type == O_endsub)
{
block->o_type = O_endsub;
if ((_setup.skipping_o != 0) &&
(0 != strcmp(_setup.skipping_o, block->o_name))) {
return INTERP_OK;
}

*counter += strlen("endsub");

// optional return value expression
if (line[*counter] == '[') {
CHP(read_real_expression(line, counter, &value, parameters));
_setup.return_value = value;
} else {
_setup.return_value = 0;
}
}
else if(_setup.defining_sub == 1)
{
Expand Down Expand Up @@ -1686,7 +1699,19 @@ int Interp::read_o( /* ARGUMENTS */
}
else if(block->o_type == O_return)
{
block->o_type = O_return;
if ((_setup.skipping_o != 0) &&
(0 != strcmp(_setup.skipping_o, block->o_name))) {
return INTERP_OK;
}
*counter += strlen("return");

// optional return value expression
if (line[*counter] == '[') {
CHP(read_real_expression(line, counter, &value, parameters));
_setup.return_value = value;
} else {
_setup.return_value = 0;
}
}
else
{
Expand Down
1 change: 1 addition & 0 deletions src/emc/rs274ngc/rs274ngc_pre.cc
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ int Interp::init()
_setup.a_indexer = 0;
_setup.b_indexer = 0;
_setup.c_indexer = 0;
_setup.return_value = 0;

// not clear -- but this is fn is called a second time without an INI.
if(NULL == iniFileName)
Expand Down
17 changes: 17 additions & 0 deletions tests/interp/return-value/expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... MESSAGE("line 6.000000: _value: - expected 0.000000, got 0.000000")
N..... MESSAGE("line 28.000000: call with arg1=2.000000 expect 246.000000, got 246.000000")
N..... MESSAGE("line 37.000000: call with arg1=-1.000000 expect 0.000000, got 0.000000")
N..... MESSAGE("line 47.000000: call with arg1=0.000000 expect 4712.000000, got 4712.000000")
N..... MESSAGE("line 53.000000: _value=4712.000000 - expected 4712.000000")
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_MODE(0)
N..... SET_FEED_RATE(0.0000)
N..... STOP_SPINDLE_TURNING()
N..... SET_SPINDLE_MODE(0.0000)
N..... PROGRAM_END()
55 changes: 55 additions & 0 deletions tests/interp/return-value/test.ngc
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
; test that #<_value> is accessible and is 0

; test for proper initialization of #<_value> if program is re-run
; see note at end of program
#<expect> = 0
(debug,line #<_line>: _value: - expected #<expect>, got #<_value>)
o200 if [#<_value> NE 0]
(debug, fail: _value=#<_value> - expecting 0)
o200 endif


o1000 sub
o1010 if [#1 GT 0]
o1010 return [123*[#1]]
o1010 endif

o1020 if [#1 LT 0]
o1020 return
o1020 endif

o1000 endsub [4712]


; test returning value via 'return'
#<arg> = 2
#<expect> = 246
o1000 call [#<arg>]
(debug,line #<_line>: call with arg1=#<arg> expect #<expect>, got #<_value>)
o3000 if [#<_value> NE #<expect>]
(debug,line #<_line>: 'return' return value=#<_value> - expected #<expect>)
o3000 endif

; test returning no value at all - plain old style 'return'
#<arg> = -1
#<expect> = 0
o1000 call [#<arg>]
(debug,line #<_line>: call with arg1=#<arg> expect #<expect>, got #<_value>)
o4000 if [#<_value> NE #<expect>]
(debug,line #<_line>: 'plain return' return value=#<_value> - expected #<expect>)
o4000 endif


; test returning value via 'endsub'
#<arg> = 0
#<expect> = 4712
o1000 call [#<arg>]
(debug,line #<_line>: call with arg1=#<arg> expect #<expect>, got #<_value>)
o2000 if [#<_value> NE #<expect>]
(debug,line #<_line>: 'endsub' return value=#<_value> - expected #<expect>)
o2000 endif

; note #<_value> is 4712 at this point.
(debug,line #<_line>: _value=#<_value> - expected #<expect>)

m2
3 changes: 3 additions & 0 deletions tests/interp/return-value/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash
rs274 -g test.ngc | awk '{$1=""; print}'
exit ${PIPESTATUS[0]}

0 comments on commit 6905295

Please sign in to comment.