From b58b8aa27df3921b284b7af8778eebf8b313e013 Mon Sep 17 00:00:00 2001 From: Josh Davies Date: Thu, 16 Oct 2025 12:25:49 +0100 Subject: [PATCH 1/2] fix: remove unnecessary arg from builtin macros Providing "?a" as an argument means that it is removed from the prevar list after the macro is used, which removes a genuine ?a prevar which comes from a procedure argument for example. Since the argument is not required at all, just remove it. Also add tests of the builtin macros. --- check/fixes.frm | 83 +++++++++++++++++++++++++++++++++++++++++++++++ sources/pre.c | 14 ++++---- sources/startup.c | 14 ++++---- 3 files changed, 97 insertions(+), 14 deletions(-) diff --git a/check/fixes.frm b/check/fixes.frm index 6df46adb..36c7cfd9 100644 --- a/check/fixes.frm +++ b/check/fixes.frm @@ -3864,6 +3864,89 @@ assert succeeded? assert result("test1") =~ expr("f(i1,N1_?,N2_?,i4)^2") assert result("test2") =~ expr("f(N1_?,N2_?,N3_?,N4_?)^2") *--#] Issue615 : +*--#[ Issue631_1 : +#procedure foo(?a) + #message `toupper_(abc)' + #message `toupper_(a,b,c)' + #message `toupper_(`?a')' + #message `tolower_(ABC)' + #message `tolower_(A,B,C)' + #message `tolower_(`?a')' + #message `?a' +#endprocedure + +#call foo(1,2,3,abc,a,b,c,ABC,A,B,C) +.end +assert succeeded? +assert stdout =~ exact_pattern(<<'EOF') +~~~ABC +~~~A,B,C +~~~1,2,3,ABC,A,B,C,ABC,A,B,C +~~~abc +~~~a,b,c +~~~1,2,3,abc,a,b,c,abc,a,b,c +~~~1,2,3,abc,a,b,c,ABC,A,B,C +EOF +*--#] Issue631_1 : +*--#[ Issue631_2 : +#- +#define MYTOUPPER(x,y) "toupper_(`~x',`~y')" +#procedure foo(x,y) + #message ``MYTOUPPER(`x',`y')'' + #message `toupper_(`x',`y')' +#endprocedure +#call foo(a,b) +#message ``MYTOUPPER(c,d)'' +.end +assert succeeded? +assert stdout =~ exact_pattern(<<'EOF') +~~~A,B +~~~A,B +~~~C,D +EOF +*--#] Issue631_2 : +*--#[ Issue631_3 : +#- +#define str "abcde" +#do i = 0,6 + #message takeleft_(`str',`i') = `takeleft_(`str',`i')' + #message takeright_(`str',`i') = `takeright_(`str',`i')' + #message keepleft_(`str',`i') = `keepleft_(`str',`i')' + #message keepright_(`str',`i') = `keepright_(`str',`i')' +#enddo +.end +assert succeeded? +assert stdout =~ exact_pattern(<<'EOF') +~~~takeleft_(abcde,0) = abcde +~~~takeright_(abcde,0) = abcde +~~~keepleft_(abcde,0) = +~~~keepright_(abcde,0) = +~~~takeleft_(abcde,1) = bcde +~~~takeright_(abcde,1) = abcd +~~~keepleft_(abcde,1) = a +~~~keepright_(abcde,1) = e +~~~takeleft_(abcde,2) = cde +~~~takeright_(abcde,2) = abc +~~~keepleft_(abcde,2) = ab +~~~keepright_(abcde,2) = de +~~~takeleft_(abcde,3) = de +~~~takeright_(abcde,3) = ab +~~~keepleft_(abcde,3) = abc +~~~keepright_(abcde,3) = cde +~~~takeleft_(abcde,4) = e +~~~takeright_(abcde,4) = a +~~~keepleft_(abcde,4) = abcd +~~~keepright_(abcde,4) = bcde +~~~takeleft_(abcde,5) = +~~~takeright_(abcde,5) = +~~~keepleft_(abcde,5) = abcde +~~~keepright_(abcde,5) = abcde +~~~takeleft_(abcde,6) = +~~~takeright_(abcde,6) = +~~~keepleft_(abcde,6) = abcde +~~~keepright_(abcde,6) = abcde +EOF +*--#] Issue631_3 : *--#[ Issue633 : s x,y,z; c f; diff --git a/sources/pre.c b/sources/pre.c index 2953c80d..2658817b 100644 --- a/sources/pre.c +++ b/sources/pre.c @@ -331,20 +331,20 @@ UBYTE GetChar(int level) if ( StrICmp(namebuf,(UBYTE *)"random_") == 0 ) { UBYTE *ranvalue; ranvalue = PreRandom(s); - PutPreVar(namebuf,ranvalue,(UBYTE *)"?a",1); + PutPreVar(namebuf,ranvalue,0,1); M_free(ranvalue,"PreRandom"); goto dostream; } else if ( StrICmp(namebuf,(UBYTE *)"tolower_") == 0 ) { UBYTE *ss = s; while ( *ss ) { *ss = (UBYTE)(tolower(*ss)); ss++; } - PutPreVar(namebuf,s,(UBYTE *)"?a",1); + PutPreVar(namebuf,s,0,1); goto dostream; } else if ( StrICmp(namebuf,(UBYTE *)"toupper_") == 0 ) { UBYTE *ss = s; while ( *ss ) { *ss = (UBYTE)(toupper(*ss)); ss++; } - PutPreVar(namebuf,s,(UBYTE *)"?a",1); + PutPreVar(namebuf,s,0,1); goto dostream; } else if ( StrICmp(namebuf,(UBYTE *)"takeleft_") == 0 ) { @@ -358,7 +358,7 @@ UBYTE GetChar(int level) if ( x > nsize ) x = nsize; } else x = 0; - PutPreVar(namebuf,s+x,(UBYTE *)"?a",1); + PutPreVar(namebuf,s+x,0,1); goto dostream; } else if ( StrICmp(namebuf,(UBYTE *)"takeright_") == 0 ) { @@ -374,7 +374,7 @@ UBYTE GetChar(int level) else x = 0; x = nsize - x; s[x] = 0; - PutPreVar(namebuf,s,(UBYTE *)"?a",1); + PutPreVar(namebuf,s,0,1); goto dostream; } else if ( StrICmp(namebuf,(UBYTE *)"keepleft_") == 0 ) { @@ -389,7 +389,7 @@ UBYTE GetChar(int level) } else x = nsize; s[x] = 0; - PutPreVar(namebuf,s,(UBYTE *)"?a",1); + PutPreVar(namebuf,s,0,1); goto dostream; } else if ( StrICmp(namebuf,(UBYTE *)"keepright_") == 0 ) { @@ -404,7 +404,7 @@ UBYTE GetChar(int level) } else x = nsize; x = nsize-x; - PutPreVar(namebuf,s+x,(UBYTE *)"?a",1); + PutPreVar(namebuf,s+x,0,1); goto dostream; } while ( *s ) { diff --git a/sources/startup.c b/sources/startup.c index d6cdb62d..7de4474b 100644 --- a/sources/startup.c +++ b/sources/startup.c @@ -1191,18 +1191,18 @@ void StartVariables(void) PutPreVar((UBYTE *)"VERSION_",(UBYTE *)STRINGIFY(MAJORVERSION),0,0); PutPreVar((UBYTE *)"SUBVERSION_",(UBYTE *)STRINGIFY(MINORVERSION),0,0); PutPreVar((UBYTE *)"DATE_",(UBYTE *)MakeDate(),0,0); - PutPreVar((UBYTE *)"random_",(UBYTE *)"________",(UBYTE *)"?a",0); + PutPreVar((UBYTE *)"random_",(UBYTE *)"________",0,0); PutPreVar((UBYTE *)"optimminvar_",(UBYTE *)("0"),0,0); PutPreVar((UBYTE *)"optimmaxvar_",(UBYTE *)("0"),0,0); PutPreVar(AM.oldnumextrasymbols,(UBYTE *)("0"),0,0); PutPreVar((UBYTE *)"optimvalue_",(UBYTE *)("0"),0,0); PutPreVar((UBYTE *)"optimscheme_",(UBYTE *)("0"),0,0); - PutPreVar((UBYTE *)"tolower_",(UBYTE *)("0"),(UBYTE *)("?a"),0); - PutPreVar((UBYTE *)"toupper_",(UBYTE *)("0"),(UBYTE *)("?a"),0); - PutPreVar((UBYTE *)"takeleft_",(UBYTE *)("0"),(UBYTE *)("?a"),0); - PutPreVar((UBYTE *)"takeright_",(UBYTE *)("0"),(UBYTE *)("?a"),0); - PutPreVar((UBYTE *)"keepleft_",(UBYTE *)("0"),(UBYTE *)("?a"),0); - PutPreVar((UBYTE *)"keepright_",(UBYTE *)("0"),(UBYTE *)("?a"),0); + PutPreVar((UBYTE *)"tolower_",(UBYTE *)("0"),0,0); + PutPreVar((UBYTE *)"toupper_",(UBYTE *)("0"),0,0); + PutPreVar((UBYTE *)"takeleft_",(UBYTE *)("0"),0,0); + PutPreVar((UBYTE *)"takeright_",(UBYTE *)("0"),0,0); + PutPreVar((UBYTE *)"keepleft_",(UBYTE *)("0"),0,0); + PutPreVar((UBYTE *)"keepright_",(UBYTE *)("0"),0,0); PutPreVar((UBYTE *)"SYSTEMERROR_",(UBYTE *)("0"),0,0); /* Next are a few 'constants' for diagram generation From a88b28bef1197872af5ea396f645fe0885e1b9ed Mon Sep 17 00:00:00 2001 From: Josh Davies Date: Thu, 16 Oct 2025 12:38:58 +0100 Subject: [PATCH 2/2] doc: add additional builtin macros to the manual Manual entries for keepleft_, keepright_, takeleft_, takeright_. --- doc/manual/prepro.tex | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/doc/manual/prepro.tex b/doc/manual/prepro.tex index d3b04c9e..f417757e 100644 --- a/doc/manual/prepro.tex +++ b/doc/manual/prepro.tex @@ -125,7 +125,7 @@ \section{The preprocessor variables} string value will be substituted. \noindent Preprocessor variables can have arguments and thereby become -macro's. One should consult the description of the \#define~\ref{predefine} +macros. One should consult the description of the \#define~\ref{predefine} instruction about the delayed substitution feature to avoid the value of the preprocessor variables in the macro would be substituted immediately during the definition. Hence proper use is @@ -133,15 +133,25 @@ \section{The preprocessor variables} #define EXCHANGE(x,y) "Multiply replace_(`~x',`~y',`~y',`~x');" \end{verbatim} -\noindent \FORM{} has the following built in macro's: +\noindent \FORM{} has the following built in macros: \begin{description} \item[TOLOWER\_(string)] in which the character string in the argument is converted to lower case. After this it will become input. \item[TOUPPER\_(string)] in which the character string in the argument is converted to upper case. After this it will become input. \end{description} -It is anticipated that some more macro's will become available to allow for -the editing of names of variables. +as well as macros which allow one to edit the names of variables, +\begin{description} +\item[KEEPLEFT\_(string,n)] keep only the first n characters of string. +After this it will become input. +\item[KEEPRIGHT\_(string,n)] keep only the last n characters of string. +After this it will become input. +\item[TAKELEFT\_(string,n)] remove the first n characters of string. +After this it will become input. +\item[TAKERIGHT\_(string,n)] remove the last n characters of string. +After this it will become input. +\end{description} +Note that these macro names are not case sensitive. %--#] The preprocessor variables : %--#[ Calculator : @@ -700,7 +710,7 @@ \section{\#define} is allowed. The parameters should be referred to inside a pair of `' as with all preprocessor variables. A special feature is the socalled delayed\index{delayed substitution} -substitution\index{substitution!delayed}. With macro's like the above the +substitution\index{substitution!delayed}. With macros like the above the question is always {\sl when} a preprocessor variable will be substituted. Take for instance % THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS