Skip to content

Commit 6905295

Browse files
committed
interp/oword: enable optional return values on 'return' and 'endsub'
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
1 parent 1620409 commit 6905295

10 files changed

Lines changed: 176 additions & 3 deletions

File tree

docs/src/gcode/main.txt

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2051,11 +2051,39 @@ they are defined. They may be called from other functions, and may call
20512051
themselves recursively if it makes sense to do so. The maximum
20522052
subroutine nesting level is 10.
20532053

2054-
Subroutines do not have "return values", but they may change the value
2054+
=== Subroutine return values [[sec:Subroutine-return-values]]
2055+
Subroutines may pass optional return values when executing `return` or
2056+
`endsub`. The value of an optional expression after a `return` or
2057+
`endsub` sets the <<param:_value,`#<_value>`>> named parameter. A
2058+
`return` or `endsub` with no trailing expression sets `#<_value>` to
2059+
0:
2060+
2061+
[source,{ngc}]
2062+
---------------------------------------------------------------------
2063+
o1000 sub
2064+
o1010 if [#1 GT 0]
2065+
o1010 return [123] ; sets #<_value> to 123
2066+
o1010 endif
2067+
2068+
o1020 if [#1 LT 0]
2069+
o1020 return ; sets #<_value> to default value of 0
2070+
o1020 endif
2071+
2072+
o1000 endsub [4711] ; sets #<_value> to 4711
2073+
2074+
o1000 call [23]
2075+
o2000 if [#<_value> EQ 0] ; accessing the return value
2076+
...
2077+
---------------------------------------------------------------------
2078+
2079+
=== Subroutine side effects
2080+
Subroutines may change the value
20552081
of parameters above #30 and those changes will be visible to the
20562082
calling code. Subroutines may also change the value of global named
20572083
parameters.
20582084

2085+
2086+
20592087
== Looping: do, while, endwhile, break, continue (((Looping: do, while, endwhile, break, continue)))
20602088

20612089
The "while loop" has two structures: while/endwhile, and do/while. In

docs/src/gcode/overview.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,11 @@ program with if-then-else statements.
579579
#<_w>::
580580
Return absolute machine W coordinate. Same as #5428.
581581

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

583588
== Expressions [[sub:Expressions]]
584589

nc_files/retval.ngc

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
; demonstrate optional return values from endsub and return
2+
3+
o1000 sub
4+
o1010 if [#1 GT 0]
5+
o1010 return [123*[#1]]
6+
o1010 endif
7+
8+
o1020 if [#1 LT 0]
9+
o1020 return
10+
o1020 endif
11+
12+
o1000 endsub [4712]
13+
14+
o1000 call [0]
15+
(debug,call with arg1=0 return #<_value>)
16+
17+
; #<_value> is 4712.0
18+
19+
o1000 call [2]
20+
(debug,call with arg1=2 return #<_value>)
21+
22+
; #<_value> is 246.0
23+
24+
o1000 call [-1]
25+
(debug,call with arg1=-1 return #<_value>)
26+
27+
; #<_value> is 0.0
28+
29+
m2

src/emc/rs274ngc/interp_internal.hh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,7 @@ typedef struct setup_struct
487487
char *skipping_to_sub; // o_name of sub skipping to (or zero)
488488
int skipping_start; // start of skipping (sequence)
489489
double test_value; // value for "if", "while", "elseif"
490+
double return_value; // optional return value for "return", "endsub"
490491
int call_level; // current subroutine level
491492
context sub_context[INTERP_SUB_ROUTINE_LEVELS];
492493
int oword_labels;

src/emc/rs274ngc/interp_namedparams.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,13 @@ int Interp::lookup_named_param(char *nameBuf,
540540
*value = _setup.w_current;
541541
break;
542542

543+
// o-word subs may optionally have an
544+
// expression after endsub and return
545+
// this 'function return value' is accessible as '_value'
546+
case 249:
547+
*value = _setup.return_value;
548+
break;
549+
543550
default:
544551
MSG("---BUG: lookup_named_param(%s) UNHANDLED INDEX=%f \n",
545552
nameBuf,index);
@@ -660,5 +667,7 @@ int Interp::init_named_parameters()
660667
init_readonly_param("_v", 247, PA_USE_LOOKUP);
661668
init_readonly_param("_w", 248, PA_USE_LOOKUP);
662669

670+
// last (optional) endsub/return value
671+
init_readonly_param("_value", 249, PA_USE_LOOKUP);
663672
return INTERP_OK;
664673
}

src/emc/rs274ngc/interp_read.cc

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,7 +1549,20 @@ int Interp::read_o( /* ARGUMENTS */
15491549
}
15501550
else if(block->o_type == O_endsub)
15511551
{
1552-
block->o_type = O_endsub;
1552+
if ((_setup.skipping_o != 0) &&
1553+
(0 != strcmp(_setup.skipping_o, block->o_name))) {
1554+
return INTERP_OK;
1555+
}
1556+
1557+
*counter += strlen("endsub");
1558+
1559+
// optional return value expression
1560+
if (line[*counter] == '[') {
1561+
CHP(read_real_expression(line, counter, &value, parameters));
1562+
_setup.return_value = value;
1563+
} else {
1564+
_setup.return_value = 0;
1565+
}
15531566
}
15541567
else if(_setup.defining_sub == 1)
15551568
{
@@ -1686,7 +1699,19 @@ int Interp::read_o( /* ARGUMENTS */
16861699
}
16871700
else if(block->o_type == O_return)
16881701
{
1689-
block->o_type = O_return;
1702+
if ((_setup.skipping_o != 0) &&
1703+
(0 != strcmp(_setup.skipping_o, block->o_name))) {
1704+
return INTERP_OK;
1705+
}
1706+
*counter += strlen("return");
1707+
1708+
// optional return value expression
1709+
if (line[*counter] == '[') {
1710+
CHP(read_real_expression(line, counter, &value, parameters));
1711+
_setup.return_value = value;
1712+
} else {
1713+
_setup.return_value = 0;
1714+
}
16901715
}
16911716
else
16921717
{

src/emc/rs274ngc/rs274ngc_pre.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ int Interp::init()
421421
_setup.a_indexer = 0;
422422
_setup.b_indexer = 0;
423423
_setup.c_indexer = 0;
424+
_setup.return_value = 0;
424425

425426
// not clear -- but this is fn is called a second time without an INI.
426427
if(NULL == iniFileName)

tests/interp/return-value/expected

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
2+
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
3+
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
4+
N..... SET_XY_ROTATION(0.0000)
5+
N..... SET_FEED_REFERENCE(CANON_XYZ)
6+
N..... MESSAGE("line 6.000000: _value: - expected 0.000000, got 0.000000")
7+
N..... MESSAGE("line 28.000000: call with arg1=2.000000 expect 246.000000, got 246.000000")
8+
N..... MESSAGE("line 37.000000: call with arg1=-1.000000 expect 0.000000, got 0.000000")
9+
N..... MESSAGE("line 47.000000: call with arg1=0.000000 expect 4712.000000, got 4712.000000")
10+
N..... MESSAGE("line 53.000000: _value=4712.000000 - expected 4712.000000")
11+
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
12+
N..... SET_XY_ROTATION(0.0000)
13+
N..... SET_FEED_MODE(0)
14+
N..... SET_FEED_RATE(0.0000)
15+
N..... STOP_SPINDLE_TURNING()
16+
N..... SET_SPINDLE_MODE(0.0000)
17+
N..... PROGRAM_END()

tests/interp/return-value/test.ngc

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
; test that #<_value> is accessible and is 0
2+
3+
; test for proper initialization of #<_value> if program is re-run
4+
; see note at end of program
5+
#<expect> = 0
6+
(debug,line #<_line>: _value: - expected #<expect>, got #<_value>)
7+
o200 if [#<_value> NE 0]
8+
(debug, fail: _value=#<_value> - expecting 0)
9+
o200 endif
10+
11+
12+
o1000 sub
13+
o1010 if [#1 GT 0]
14+
o1010 return [123*[#1]]
15+
o1010 endif
16+
17+
o1020 if [#1 LT 0]
18+
o1020 return
19+
o1020 endif
20+
21+
o1000 endsub [4712]
22+
23+
24+
; test returning value via 'return'
25+
#<arg> = 2
26+
#<expect> = 246
27+
o1000 call [#<arg>]
28+
(debug,line #<_line>: call with arg1=#<arg> expect #<expect>, got #<_value>)
29+
o3000 if [#<_value> NE #<expect>]
30+
(debug,line #<_line>: 'return' return value=#<_value> - expected #<expect>)
31+
o3000 endif
32+
33+
; test returning no value at all - plain old style 'return'
34+
#<arg> = -1
35+
#<expect> = 0
36+
o1000 call [#<arg>]
37+
(debug,line #<_line>: call with arg1=#<arg> expect #<expect>, got #<_value>)
38+
o4000 if [#<_value> NE #<expect>]
39+
(debug,line #<_line>: 'plain return' return value=#<_value> - expected #<expect>)
40+
o4000 endif
41+
42+
43+
; test returning value via 'endsub'
44+
#<arg> = 0
45+
#<expect> = 4712
46+
o1000 call [#<arg>]
47+
(debug,line #<_line>: call with arg1=#<arg> expect #<expect>, got #<_value>)
48+
o2000 if [#<_value> NE #<expect>]
49+
(debug,line #<_line>: 'endsub' return value=#<_value> - expected #<expect>)
50+
o2000 endif
51+
52+
; note #<_value> is 4712 at this point.
53+
(debug,line #<_line>: _value=#<_value> - expected #<expect>)
54+
55+
m2

tests/interp/return-value/test.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/bash
2+
rs274 -g test.ngc | awk '{$1=""; print}'
3+
exit ${PIPESTATUS[0]}

0 commit comments

Comments
 (0)