【问题标题】:How to capitalise ASCII character in string define?如何在字符串定义中大写ASCII字符?
【发布时间】:2019-12-05 14:19:54
【问题描述】:

对于我创建的脚本for another question,我必须在字符串定义中将传递给 NASM 的文件名大写。我使用 %substr 提取 %rep 循环中的单个字符,重复计数来自 %strlen。我尝试了以下方法来大写一个字符:

$ cat test.asm
 %define cc 'a'
 %if cc >= 'a' && cc <= 'z'
  %strcat cc cc - 'a' + 'A'
 %endif

但失败如下:

$ nasm test.asm
test.asm:3: error: non-string passed to `%strcat' (9)
$

错误信息是由 NASM 预处理器源中的这个位产生的:https://repo.or.cz/nasm.git/blob/437e0ffa01505d173a8b9cfe2decf74f2e9795a5:/asm/preproc.c#l3472

使用https://repo.or.cz/nasm.git/blob/437e0ffa01505d173a8b9cfe2decf74f2e9795a5:/asm/preproc.c#l207中定义的token类型(9好像是TOK_OTHER。)

【问题讨论】:

  • @Rob:对不起,我把标签放在标题中的错误。我不明白你第一次编辑它。
  • 另一个失败的尝试:%assign cc cc - 'a' + 'A' \ %strcat cc cc 这失败了error: non-string passed to '%strcat' (6)
  • 为了帮助网络搜索,让我提一下,我们希望在此处使用 NASM 预处理器将字符大写

标签: assembly nasm preprocessor capitalize


【解决方案1】:

我最终以这种方式解决了这个问题,尽管它看起来很奇怪,可能会有更好的方法。

 %if cc >= 'a' && cc <= 'z'
  %substr cc "ABCDEFGHIJKLMNOPQRSTUVWXYZ" (cc - 'a' + 1)
 %endif

来自我的来源https://hg.ulukai.org/ecm/bootimg/file/f8c890f92116f2593c1e2016a71f95dfd7bbcd36/bootimg.asm#l314

【讨论】:

    【解决方案2】:

    我确实找到了另一种方法,它允许我们在任何地方使用 %xdefine 而不是 %strcat。 (x 很重要,否则会导致错误的递归宏。)然而,这需要一个特殊的类似“strlen”的宏来计算字符串片段和数字,以计算出复合字符串列表的长度与db 一起使用时向上。这是完整的示例,基于已在另一个答案中链接的 from my script 部分。

    %include "lmacros1.mac"
    
        %macro checkchar 2-3.nolist 0
    %if %2 <= ' ' || %2 >= 128 || \
        %2 == '/' || %2 == '\' || \
        %2 == '"' || %2 == "'" || \
        %2 == %3
     %error Invalid character (%2) in name (%1)
    %endif
        %endmacro
    
    
        %macro strlen_ll 1-*.nolist
    %assign ll 0
    %rep %0
    %ifstr %1
     %strlen ll2 %1
     %assign ll ll + ll2
    %else
     %assign ll ll + 1
    %endif
    %rotate 1
    %endrep
        %endmacro
    
    
        %macro test 1
    %define string %1
    %strlen length string
    %assign ii 1
    %rep length
     %substr cc string length - ii + 1
     %ifidn cc,"/"
      %substr string string length -ii + 2, -1
      %exitrep
     %endif
     %ifidn cc,"\"
      %substr string string length -ii + 2, -1
      %exitrep
     %endif
     %assign ii ii + 1
    %endrep
    %strlen length string
    %assign ii 1
    %define name ""
    %define ext ""
    %assign dotyet 0
    %rep length
     %substr cc string ii
     %assign ii ii + 1
     %if cc >= 'a' && cc <= 'z'
      %xdefine cc (cc - 'a' + 'A')
     %endif
     %ifn dotyet
      %ifidn cc,"."
       %assign dotyet 1
      %else
       strlen_ll name
       %if ll >= 8
        %error Too long name part in %1
        %exitrep
       %endif
       checkchar %1,cc
       %xdefine name name,cc
      %endif
     %else
      strlen_ll ext
      %if ll >= 3
       %error Too long ext part in %1
       %exitrep
      %else
       checkchar %1,cc,"."
       %xdefine ext ext,cc
      %endif
     %endif
    %endrep
    %ifidn name,""
     %error Invalid empty name part in %1
    %endif
    
    fill 8,32,db name
    fill 3,32,db ext
        %endmacro
    
    
    test "../foo/bar/baz.bin"
    test "quux"
    

    【讨论】:

      【解决方案3】:

      我认为cc - 'a' + 'A' 是一个数字常量,不再是字符串。它不能作为多字符串的一部分工作。不幸的是%strcat 不会将数字转回字符串?


      对于单个字符,您不需要字符串内容,只需按位运算符即可生成正确的 ASCII 码。 (What is the idea behind ^= 32, that converts lowercase letters to upper and vice versa?)

      ;; %if cc >= 'a' && cc <= 'z'            ; if cc might not be alphabetic
      %define upper_cc  (cc & ~0x20)
      ;; %endif
      ;; %if ...
      %define lower_cc  (cc | 0x20)
      ;; %endif
      

      nasm -felf64 -l/dev/stdout test.asm 的测试用例确认我们得到了正确的数字常量,高位没有垃圾。

           1                                  %define cc 'a'
           2                                  
           3                                  %define upper_cc  (cc & ~0x20)
           4                                  %define lower_cc  (cc | 0x20)
           5                                  
           6 00000000 B8 61000000              mov eax, lower_cc
           7 00000005 B8 41000000              mov eax, upper_cc
      

      不过,如果您想稍后对结果进行字符串连接和填充,这可能没有用。

      【讨论】:

      • 这有两个问题: 1. 正如你提到的,我想对由这些组成的字符串进行操作。 2. cc 可以是非字母字符,其中一些你的 upper/lower_cc 宏会失败。
      • @ecm: for 2:您可以将重新定义包装在 %if 范围检查中。对于 1:是的,我已经赞成你的答案。 :P 把这个留在这里,以防它对其他未来的读者有用,因为这种简单的方法起作用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-21
      • 1970-01-01
      • 1970-01-01
      • 2021-12-28
      • 2021-12-13
      • 2014-06-21
      • 1970-01-01
      相关资源
      最近更新 更多