Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 83 additions & 3 deletions check/features.frm
Original file line number Diff line number Diff line change
Expand Up @@ -2390,11 +2390,91 @@ assert succeeded?
assert result("F") =~ expr("f(1,2,4,5)")
*--#] Issue243_1 :
*--#[ Issue243_2 :
#continuedo
NF f;
L F = 1;
#define i "9"
#do i=1,2
#do i=1,3
#do i=1,8
#if `i' == 3
#continuedo 2
#endif
multiply right, f(`i');
#enddo
multiply right, f(-`i');
#enddo
multiply right, f(-`i');
#enddo
multiply right, f(`i');
chainin f;
P;
.end
assert preprocess_error?
assert stdout =~ exact_pattern("#continuedo without #do")
assert succeeded?
assert result("F") =~ expr("f(1,2,1,2,1,2,-1,1,2,1,2,1,2,-2,9)")
*--#] Issue243_2 :
*--#[ Issue243_3 :
NF f;
L F = 1;
#do i=1,3
#do i=1,2
#continuedo 0
multiply right, f(`i');
#enddo
#enddo
chainin f;
P;
.end
assert succeeded?
assert result("F") =~ expr("f(1,2,1,2,1,2)")
*--#] Issue243_3 :
*--#[ Issue243_e1 :
#continuedo
.end
assert preprocess_error?("#continuedo without #do")
*--#] Issue243_e1 :
*--#[ Issue243_e2 :
#do i=1,3
#continuedo -1
#enddo
.end
assert preprocess_error?("Improper syntax of #continuedo instruction")
*--#] Issue243_e2 :
*--#[ Issue243_e3 :
#do i=1,3
#continuedo 1a
#enddo
.end
assert preprocess_error?("Improper syntax of #continuedo instruction")
*--#] Issue243_e3 :
*--#[ Issue243_e4 :
#do i=1,3
#continuedo 2
#enddo
.end
assert preprocess_error?("Too many loop levels requested in #continuedo instruction")
*--#] Issue243_e4 :
*--#[ Issue243_e5 :
#procedure foo
#continuedo
#endprocedure
#do i=1,3
#call foo
#enddo
.end
assert preprocess_error?("Trying to jump out of a procedure with a #continuedo instruction")
*--#] Issue243_e5 :
*--#[ Issue243_e6 :
#procedure foo
#continuedo 2
#endprocedure
#do i=1,3
#do j=1,3
#call foo
#enddo
#enddo
.end
assert preprocess_error?("Trying to jump out of a procedure with a #continuedo instruction")
*--#] Issue243_e6 :
*--#[ Issue392_ContinuationLines_1 :
#: ContinuationLines 1
* Setting ContinuationLines to 0 should remove continuation line limit.
Expand Down
22 changes: 22 additions & 0 deletions doc/manual/prepro.tex
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,28 @@ \section{\#commentchar}
The default commentary character is $\ast$.

%--#] commentchar :
%--#[ continuedo :

\section{\#continuedo}
\label{precontinuedo}

\noindent Syntax:

\#continuedo [{\tt<}number{\tt>}]

\noindent See also \#do (\ref{predo}) and \#enddo (\ref{preenddo})

\noindent The \#continuedo\index{\#continuedo} instruction allows one to
jump to the next iteration of a \#do loop.
If a (nonzero integer) number is specified
it indicates the number of enclosing loops
that the program should continue to the next iteration of.
Control will continue at the beginning of the next iteration
of the enclosing loop indicated by `number'.
The default value is one.
If the value is zero the instruction has no effect.

%--#] continuedo :
%--#[ create :

\section{\#create}
Expand Down
68 changes: 62 additions & 6 deletions sources/pre.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#[ Includes :
*/
#include "form3.h"
#include "comtool.h"
#ifdef WITHFLOAT
#include "math.h"
#endif
Expand All @@ -43,6 +44,8 @@ static STREAM *oldstream = 0;
static UBYTE underscore[2] = {'_',0};
static PREVAR *ThePreVar = 0;

static int ExitDoLoops(int, const char *);

static KEYWORD precommands[] = {
{"add" , DoPreAdd , 0, 0}
,{"addseparator" , DoPreAddSeparator,0,0}
Expand Down Expand Up @@ -2783,9 +2786,22 @@ int DoTerminate(UBYTE *s)
#[ DoContinueDo :
*/

/**
* Jumps forward to the corresponding `#enddo` of the specified number of outer `#do` loops.
*
* @par Syntax:
* @code
* #continuedo [<number>=1]
* @endcode
*
* If `number` is omitted, it defaults to 1.
* If `number` is zero then the instruction has no effect.
*/
int DoContinueDo(UBYTE *s)
{
DOLOOP *loop;
WORD levels;
int result;

if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
Expand All @@ -2795,6 +2811,37 @@ int DoContinueDo(UBYTE *s)
return(1);
}

SkipSpaces(&s);
if ( *s == 0 ) {
levels = 1;
}
else if ( FG.cTable[*s] == 1 ) {
ParseNumber(levels,s);
SkipSpaces(&s);
if ( *s != 0 ) goto improper;
}
else {
improper:
MesPrint("@Improper syntax of %#continuedo instruction");
return(1);
}

if ( levels > NumDoLoops ) {
MesPrint("@Too many loop levels requested in %#continuedo instruction");
return(1);
}

result = ExitDoLoops(levels-1,"continuedo");
if ( result != 0 ) return(result);

if ( levels <= 0 ) return(0);

if ( AC.CurrentStream->type == PREREADSTREAM3
|| AP.PreTypes[AP.NumPreTypes] == PRETYPEPROCEDURE ) {
MesPrint("@Trying to jump out of a procedure with a %#continuedo instruction");
return(1);
}

loop = &(DoLoops[NumDoLoops-1]);
AP.NumPreTypes = loop->NumPreTypes+1;
AP.PreIfLevel = loop->PreIfLevel;
Expand Down Expand Up @@ -3031,7 +3078,6 @@ illdo:;

int DoBreakDo(UBYTE *s)
{
DOLOOP *loop;
WORD levels;

if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
Expand Down Expand Up @@ -3062,6 +3108,19 @@ int DoBreakDo(UBYTE *s)
MesPrint("@Too many loop levels requested in %#breakdo instruction");
Terminate(-1);
}
return(ExitDoLoops(levels,"breakdo"));
}

/**
* Exits the specified number of nested `#do` loops.
*
* @param levels The number of loops to exit.
* @param instruction The instruction name used for error reporting.
* @return 0 on success, nonzero on error.
*/
static int ExitDoLoops(int levels, const char *instruction)
{
DOLOOP *loop;
while ( levels > 0 ) {
while ( AC.CurrentStream->type != PREREADSTREAM
&& AC.CurrentStream->type != PREREADSTREAM2
Expand All @@ -3072,16 +3131,13 @@ int DoBreakDo(UBYTE *s)
&& AP.PreTypes[AP.NumPreTypes] != PRETYPEPROCEDURE ) AP.NumPreTypes--;
if ( AC.CurrentStream->type == PREREADSTREAM3
|| AP.PreTypes[AP.NumPreTypes] == PRETYPEPROCEDURE ) {
MesPrint("@Trying to jump out of a procedure with a %#breakdo instruction");
Terminate(-1);
MesPrint("@Trying to jump out of a procedure with a %#%s instruction",instruction);
return(1);
}
loop = &(DoLoops[NumDoLoops-1]);
AP.NumPreTypes = loop->NumPreTypes;
AP.PreIfLevel = loop->PreIfLevel;
AP.PreSwitchLevel = loop->PreSwitchLevel;
/*
AP.NumPreTypes--;
*/
NumDoLoops--;
DoUndefine(loop->name);
M_free(loop->p.buffer,"loop->p.buffer");
Expand Down
Loading