在 MIPS 中编写一个函数,将表示整数(以给定基数)的字符串转换为以 10 为基数的相应数字

问题描述:

假设我们有一个字符串代表一个给定基数的整数,而且是这个基数.参数是存储字符串的起始地址(在 $a0 中)和 $a1 中的基址.

Suppose we have a string representing an integer in a given base, and that very base. The parameters are the address (in $a0) starting from which the string is stored, and the base in $a1.

我应该将相应的数字转换为以 10 为底的数字,并将其保存在 $v0 中.在这种情况下,应该将 0 加载到 $v1 中.
如果字符串不能正确表示给定基数中的整数,那么最后 $v0 应该包含 -1,$v1 应该包含 1.

I should convert the corresponding number into base 10, and save it in $v0. In this case 0 should be loaded into $v1.
If instead the string does not correctly represent an integer in the given base, then in the end $v0 should contain -1 and $v1 should contain 1.

此外,实际执行转换的函数应该是递归的.

Also, the function that actually performs the conversion should be recursive.

我预先编写了一个 Python 程序(您会注意到各种 s0、s1 等),我可以将想法转移到 MIPS,但是当我意识到我可能应该在上下文中执行对字符串的字符进行计数,对字符串的调查是in base"与否,以及逐渐将数量相加到某个指定变量的实际转换 - 而不是像下面的程序那样单独转换.

I have written beforehand a Python program in such a way (you'll notice the various s0, s1 etc.) that I could transfer the thinking to MIPS, but it got really confusing when I realised I probably should perform contextually the counting of the characters of the string, the investigation over the string being "in base" or not, and the actual conversion with the gradual summing of quantities to some designated variable - and not separately as in the below program.

我应该如何解决这个问题并编写函数?

How should I go about this and write the function(s)?

这是 Python 代码:

Here's the Python code:

digitsDict = dict();

lowerCase = "abcdefghijklmnopqrstuvwxyz"
upperCase = lowerCase.upper();

for i in range(26):
    digitsDict.update({lowerCase[i]:i+10})
    digitsDict.update({upperCase[i]:i+10})

def isInBase(string, base):
    s1 = False; 
    for char in string:
        if (str(char).isdigit()):
            if (int(char) >= base):
                return s1
        else:
            if (char not in digitsDict.keys() or digitsDict[char] >= base):
                return s1
    s1 = True
    return s1

def convert(string, base, k=0):
    s2 = 0
    char = string[k]
    l = len(string) - 1
    if str(char).isdigit(): s2 += int(char)*(base**(l-k))
    else:   s2 += digitsDict[char]*(base**(l-k))
    
    if k == l: return s2;
    return s2 + convert(string, base, k+1)
    

def strToInt(string, base):
    return (convert(string, base, 0), 0)
    
def main(a0String, a1Integer):
    if isInBase(a0String, a1Integer):
        v0, v1 = strToInt(a0String, a1Integer)
    else: v0 = -1; v1 = 1;
    
    print(v0)
    if (v0 == -1): return 22 #MIPS error code for invalid argument
    return 0 #OK

首先,你有伪代码,太好了!

First, you have pseudo code, so very good!

接下来,作为一般规则,请确保您的伪代码确实有效(因此对其进行测试),因为在汇编中调试设计问题非常困难,并且对设计(伪代码)的微小更改可能需要对设计进行大的更改汇编(例如重写大量代码).

Next, as a general rule, make sure your pseudo code actually works (so test it), as debugging design issues in assembly is very difficult, and small changes to the design (in pseudo code) can require large changes in the assembly (e.g. rewriting a lot of code).

你正在用 Python 做一些与汇编语言相关的事情,所以你应该先用 C 编写你的伪代码,因为这会让你解决这些差异.

You're doing some things in Python that are rather involved in assembly language, so you ought to write your pseudo code in C first, since that will make you address those differences. 

  • in — 表示 C 或汇编中的循环
  • 字符串上的
  • +=+ — 表示对全局缓冲区的一些简单操作,或者一些复杂的内存管理(提示:选择前者)
  • .isDigit() 是条件连接还是分离,取决于您的编码方式
  • .update() 需要一些替代翻译
  • ** 也代表 C 或汇编中的循环
  • in — represents a loop in C or assembly
  • += and + on strings — represents either some simple operations on global buffer, or, some complicated memory management (hint: go for the former)
  • .isDigit() is conditional conjunction or disjunction depending on how you code it
  • .update() will need some alternative translation
  • ** also represents a loop in C or assembly

下一个大麻烦是函数的调用.由于需要使用寄存器和堆栈处理,MIPS 汇编语言中的函数调用可能是最复杂的主题.

The next big complication is the calling of functions.  Function calling in MIPS assembly language is probably the most complex topic, due to the requirements register usage and stack handling.

递归对于汇编语言来说有点红鲱鱼:它看起来很难,但实际上在汇编语言中与调用其他函数而不涉及递归的函数没有什么区别(这是真的,假设汇编指令集有用于函数调用的运行时堆栈,MIPS 可以(但如果没有,您就必须模拟调用堆栈)).

Recursion is a bit of a red herring for assembly language: it appears hard but it is actually no harder and even no different in assembly language than functions calling other functions without involving recursion (this is true assuming the assembly instruction set has a runtime stack for function calling, MIPS does (but if it didn't you'd have to simulate a call stack)).

你需要研究这个,它有点牵扯.寻找其他示例,例如斐波那契.

You'll need to study up on this, it is somewhat involved.  Look for other example, fibonacci, for example.

当将调用另一个函数的函数转换为 MIPS 时,我们需要分析跨函数调用"的变量和值.这些变量需要特别考虑,因为调用另一个函数会清除一些寄存器.例如,您会在斐波那契数列中看到这一点.

When translating to MIPS one function that calls another function, we need an analysis of variables and values that are "live across a function call".  These variables need special consideration, since some registers are wiped out by calling another function.  You'll see this in fibonacci, for example.

递归 fib 的一部分,是 fib(n-1)+fib(n-2).第一次调用 fib 的返回值必须进行特殊处理,因为它最终需要加法 (+),因此它在第二次调用 时有效>fib,如果没有特殊处理,将在第二次调用时丢失.此外,n 在第一次调用时仍然存在,但需要再次进行第二次调用,如果没有一些特殊处理,第一次调用同样会被清除.

Part of recursive fib, is fib(n-1)+fib(n-2).  The return value from the first call to fib must be given special handling since it ultimately needed for the addition (+), so it is live across the 2nd call to fib, and without special handling, will be lost by making that 2nd call.  Also, n is live across the first call yet needed again to make the second call, and without some special handling would similarly be wiped out by that first call.

这是 MIPS 中函数调用函数的结果,其指令集不会自动堆叠事物,需要汇编语言程序员或编译器手动进行.其他架构也需要其中的一些或全部.这不是递归的结果,因此 a(n)+b(n) 将涉及对变量和值的分析和特殊处理的相同要求.

This is a consequence of functions calling functions in MIPS whose instruction set does not automatically stack things and requires the assembly language programmer or compiler to do so manually.  Some or all of this is also needed on other architectures.  This is not a consequence of recursion, so a(n)+b(n) would involve the same requirements for analysis and special handling of variables and values.

当您有一个好的算法(例如在 C 中)并且它可以工作时,您就可以进行组装了.首先翻译您的数据:全局变量.接下来翻译函数,类似地:将您的局部变量翻译成 MIPS,然后按照其汇编语言模式翻译每个结构化语句(例如 iffor).嵌套结构化语句也嵌套在汇编语言中,只要您准确观察嵌套,就可以先翻译内部语句还是先翻译外部语句.

When you have a good algorithm (e.g. in C) and it works, your ready for assembly.  Translate your data first: global variables.  Next translate functions, similarly: translate your local variables into MIPS, then translate each structured statement, (e.g. if, for) following its assembly language pattern.  Nested structured statements also nest in assembly language, and it doesn't matter if you translate the inner statements first or outer statements first, as long as you exactly observe the nesting.

为了将结构化语句翻译成汇编,我首先使用 C 中的中间形式,例如:

In order to translate structured statements into assembly I first use intermediate forms in C, for example:

for ( int i = 0; i < n; i++ ) {
    ..body of for..
}

请注意,在上面的for 主体"中可以很容易地包含控制结构,比如另一个 for 或一个 if.然后,这些是嵌套结构语句——一次只翻译它们,每个结构化语句都遵循其完整的模式,并确保在汇编中同样观察到 C 中的嵌套.

Note that in the above the "body of the for" could easily contain control structures, like another for or an if.  These then, are nested structure statements — just translate them one at a time, each structured statement following its complete pattern, and make sure the nesting in C is equally observed in assembly.

for 翻译成 while :

...
int i = 0;
while ( i <n ) {
    ..body of for..
    i++;
}
...

接下来,应用if-goto-label";中间形式:

Next, apply "if-goto-label" intermediate form :

    ...
    int i = 0;
loop1:
    if ( i >= n ) goto endLoop1;
    ..body of for..
    i++;
    goto loop1;
endLoop1:
    ...

在应用模式时,您需要创建标签名称;模式的每个应用程序的新标签名称.

As you apply patterns, you'll need to create label names; new label names for each application of the pattern.

然后这很容易转化为汇编.如果for 的主体"还具有控制结构,确保它们的整个翻译都嵌入并位于for"的主体"中.上述模式中的部分.

Then this translates into assembly fairly easily.  If the "body of for" also has control structures make sure their entire translation is embedded and located at the "body of for" section in the above pattern.

注意 i <汇编中的 n 有时会转换为 i >= n — 这里是因为 if-goto-label 形式的控制流 make 是说:在 逻辑相反的条件下退出循环>while C 中的语句.

Notice how the i < n in assembly sometimes translates into i >= n — here because control flow in if-goto-label form make is say: exit the loop on the logically opposite condition of the while statement in C.

最后,将 C 代码中语句中的表达式翻译成汇编.

And finally, translate expressions within statements in your C code into assembly.