News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Macro Magic: Upper/lower case macro strings.

Started by dawnraider, November 05, 2016, 12:19:17 PM

Previous topic - Next topic

dawnraider

Hi all,

Up until now I have never required a string upper-/lower-casing routine. This routine was a start (http://masm32.com/board/index.php?topic=2587.msg27311#msg27311)
but left me thinking I could perhaps do a little better. I did some playing around and rolled this compact one-line workhorse. Lower-case can be done by simply reversing
the search/replacement strings.

Of course, the single line is wrapped in a nice function, expanding it to a completely bloated six lines...

I thought I'd create this post for future persons looking for a ready-to-go solution.

Cheers,


@AdtToUpper MACRO source

    LOCAL uppr_str, next_chr

    ;;
    ;; perform character-for-character replacement...
    ;;
    uppr_str TEXTEQU <>

    FORC next_chr, <source>
        uppr_str CATSTR uppr_str, @SubStr(<next_chr><ABCDEFGHIJKLMNOPQRSTUVWXYZ>, @InStr(1, <abcdefghijklmnopqrstuvwxyz>, <next_chr>) + 1, 1)
    ENDM

    EXITM uppr_str

ENDM


jj2007

Good work, may need some polishing. Little testbed attached.
include \masm32\include\masm32rt.inc

@AdtToUpper MACRO source

    LOCAL uppr_str, next_chr

    ;;
    ;; perform character-for-character replacement...
    ;;
    uppr_str TEXTEQU <>

    FORC next_chr, <source>
        uppr_str CATSTR uppr_str, @SubStr(<next_chr><ABCDEFGHIJKLMNOPQRSTUVWXYZ>, @InStr(1, <abcdefghijklmnopqrstuvwxyz>, <next_chr>) + 1, 1)
    ENDM

    EXITM uppr_str

ENDM

@Lower$ macro txIn ; borrowed from \masm32\MasmBasic\MasmBasic.inc
LOCAL txOut, is, arg
  txOut equ <>
  FORC arg, <txIn>
is INSTR <ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ>, <arg>
if is
txOut CATSTR txOut, @SubStr(<abcdefghijklmnopqrstuvwxyzäöü>, is, 1)
else
txOut CATSTR txOut, <arg>
endif
  ENDM
  EXITM txOut
ENDM

.code
start:
  % echo @Lower$(<Let's count 1, 2, 3, and let's not forget the Umlaute ÄÖÜ...>)
  % echo @Lower$("Let's count 1, 2, 3, and let's not forget the Umlaute ÄÖÜ...")
  tmp$ equ @AdtToUpper("Let's count 1, 2, 3, and let's not forget the Umlaute ÄÖÜ...")
  echo tmp$ ; echoes only "tmp$"
  % echo tmp$ ; trouble, lots of errors
  tmp$ equ @AdtToUpper(Monday Tuesday)
  % echo tmp$
  % echo @AdtToUpper(Wednesday Thursday)
  .err
  exit

end start

hutch--

 :biggrin:

> expanding it to a completely bloated six lines...

Damn, you have to watch all of that code bloat.  :P

dawnraider

#3
Ah, it's been very busy so I've not been able to reply all week.

jj2007, thanks for your feedback. I admit, mine is not a perfect routine as it was not designed to handle special characters - quotes,
percents, exclamation marks, etc. - these are filtered out before the routine ever gets called.

The object of the excercise was not to create the perfect routine - it was to create a functioning one-liner; the holy grail of upper-/
lower-case routines. However, I shall endeavour to improve it,! Thanks for your encouragement!  :t

By the way, in your log you had:


echo tmp$ ; echoes only "tmp$"


This is probably because you forgot the percent prefix to echo like the other lines. I managed to get the same "non-result" when I used
@Lower$ and didn't prefix echo with a percent.

Surprisingly, it appears that the only reason your lower-case routine @Lower$ actually works is due to a bug in MASM that results
in it not raising error A2046 (missing single or double quotation) if a string is not closed at the end of line for non-function versions of the
built-in string functions (i.e. INSTR, CATSTR, etc.).

i.e. this line in your routine:


        txOut CATSTR txOut, <arg>


expands to:


        txOut CATSTR txOut, <">


which should raise error A2046 because the quotation mark inside the string is not escaped with an exclamation mark, resulting in
an un-terminated string at the end of line. However, MASM is silent. The correct expanded code should be:


        txOut CATSTR txOut, <!">


You can verify this by creating the following file:


tmp1$ CATSTR <Hello>, <">
%echo 1. tmp1$

tmp2$ EQU @CatStr(<Hello>, <">)
%echo 2. tmp2$

tmp3$ CATSTR <Hello>, < ">, <World>, <">
%echo 3. tmp3$

tmp4$ EQU @CatStr(<Hello>, < ">, <World>, <">)
%echo 4. tmp4$

tmp5$ EQU @CatStr(<Hello>, < !">, <World>, <!">)
%echo 5. tmp5$


Then assemble. The output I got from ml64.exe v12.00.31101.0 (Visual Studio 2013 Professional) was:


Assembling: test.asm
1. Hello"                       [ This should raise error A2046 ]
test.asm(5) : error A2046:missing single or double quotation mark in string
@CatStr(1): Macro Called From
  afx-32-sse4.asm(5): Main Line Code
afx-32-sse4.asm(5) : warning A4010:expected '>' on text literal
@CatStr(1): Macro Called From
  afx-32-sse4.asm(5): Main Line Code
2. Hello">                      [ Now we have an error?! This should at least be consistent with test #1. However, behaviour is as per the manual ]
3. Hello "World"                [ This behaviour isn't as per the manual as quotation marks aren't escaped ]
4. Hello ">, <World>, <"        [ This definitely shouldn't happen! Should at least be consistent with previous line. Yet another bug... CATSTR != @CatStr  ]
5. Hello "World"                [ Behaviour as per the manual ]


It is for this reason that my function @AdtToUpper fails as while the non-function versions of CATSTR and INSTR can handle
un-terminated strings, the function versions cannot.

Ah well, looks the holy grail of a one-liner for upper-/lower-casing a string might be impossible after all...

jj2007

Quote from: dawnraider on November 10, 2016, 04:28:54 PMthis line in your routine:


        txOut CATSTR txOut, <arg>


expands to:


        txOut CATSTR txOut, <">


which should raise error A2046 because the quotation mark inside the string is not escaped with an exclamation mark, resulting in an un-terminated string at the end of line. However, MASM is silent.

HJWasm and AsmC are also silent, and rightly so. You are confusing <strings> with "strings". Macros don't care for "string" or 'strings'.

dawnraider

Quote
HJWasm and AsmC are also silent, and rightly so. You are confusing <strings> with "strings". Macros don't care for "string" or 'strings'.

I also would expect HJWasm to be silent, if it is claiming to be compatible with MASM. After all, bugs or no bugs, compatible means doing the
same thing.

While investigating further, it appears that this:


tmp1$ EQU @Lower$(<This is a " test>)
%echo tmp1$


produces error A2046 as expected. Not in your code, but on the macro call itself. However, interestingly, this does work:


tmp1$ EQU <This is a " test>
tmp2$ EQU @Lower$(tmp1$)
%echo tmp2$


Relying on the bug that the directives don't care about un-terminated strings, this works even though it looks like it shouldn't. Maybe you could
explain to me what is going on here as I would be interested to know the logic (if any).

MASM has lots of bugs, and so many people's code relies on the bugs as much the normal features that it is highly unlikely these bugs will
ever be fixed. I was just curious to know why CATSTR and @CatStr were not compatible (even though the manual states that they are) and
was interested to find that your implementation relied on an inconsistency in MASM in order to work.

Cheers.

jj2007

Quote from: dawnraider on November 11, 2016, 12:18:26 AMWhile investigating further, it appears that this:


tmp1$ EQU @Lower$(<This is a " test>)
%echo tmp1$


produces error A2046 as expected.

Your expectations are incorrect :biggrin:
include \masm32\include\masm32rt.inc

@Lower$ macro txIn ; borrowed from \masm32\MasmBasic\MasmBasic.inc
LOCAL txOut, is, arg
  echo --- in the macro ---
  txOut equ <>
  FORC arg, <txIn>
is INSTR <ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ>, <arg>
if is
txOut CATSTR txOut, @SubStr(<abcdefghijklmnopqrstuvwxyzäöü>, is, 1)
else
txOut CATSTR txOut, <arg>
endif
  ENDM
  EXITM txOut
ENDM

.code
start:

  echo ---------- calling ------------ 
  tmp1$ EQU @Lower$(<This is a " test>) ; single quote
  % echo --------- out: tmp1$ ------------ 

  echo ---------- calling ------------ 
  tmp1$ EQU @Lower$(<This is a " test">) ; double quote
  % echo --------- out: tmp1$ ------------ 
  .err
  exit

end start


Output from MASM:tmp_file.asm(23) : error A2046: missing single or double quotation mark in string
@Lower$(1): Macro Called From
  tmp_file.asm(23): Main Line Code
tmp_file.asm(23) : warning A4010: expected '>' on text literal
@Lower$(1): Macro Called From
  tmp_file.asm(23)


I'd call that a MASM bug - one of many. The Watcom forks don't throw an error, and rightly so: The macro must produce a single quotation mark if the coder tells it to do so.