首页 > 解决方案 > (LC3) 使用字符串中的字符来指向不同子程序的地址?

问题描述

我正在尝试在 LC3 Assembly 中编写一个程序,该程序本质上将采用用户输入的 1-4 个十六进制值,将它们存储到相应的标签中,然后识别这些值中的每一个,以便通知程序要执行哪个子程序跳转到(会有一个子程序十六进制字符x0-xf)。我已经完成了用户输入部分。

我有一个优化识别过程的想法——使用 x0-xf 的 .STRINGZ 作为各种字符索引——但我正在努力实现它。想法是使用counter = #16的循环,这样每次迭代都会从索引字符串中加载相应的字符,然后将该值与用户输入进行比较,如果值相等,则程序将跳转到子程序对应于现在已知的用户输入标识。如果它们不相等,则循环将重新启动。我的问题是:在循环完成并且知道值之后,如何使用字符串中的特定字符指向它对应的相应标签或内存位置?可以想象,您还可以使用循环计数器来指向地址或标签,但从概念上讲,它们非常相似。

.ORIG x3000
;-----------------------------------
;other code
;-----------------------------------
;values in these labels are for the sake of example.
CHAR1       .FILL x30
CHAR2       .FILL x31
CHAR3       .FILL x32
CHAR4       .FILL x33
SUB_RET     .FILL x0000 
;-----------------------------------
;**Question relevant section**
;-----------------------------------
CHAR_FIND   ST R7, SUB_RET
LEA R0, H_INDEX
;CHAR ID LOOP   
            RET
H_INDEX .STRINGZ "0123456789abcdef"         
;-----------------------------------
;CHARACTER SUBROUTINES (REMOVED SEVERAL FOR BREVITY)
;-----------------------------------
D_CHAR_0    ST R7, SUB_RET  
            ;REMOVED SUBROUTINE CONTENTS FOR BREVITY

            
D_CHAR_1    ST R7, SUB_RET          
            ;REMOVED SUBROUTINE CONTENTS FOR BREVITY


D_CHAR_2    ST R7, SUB_RET  
            ;REMOVED SUBROUTINE CONTENTS FOR BREVITY

D_CHAR_3    ST R7, SUB_RET  
            ;REMOVED SUBROUTINE CONTENTS FOR BREVITY

标签: stringassemblymemorysubroutinelc3

解决方案


字符串中的字符一旦提取为字符,就只是一个值。那么,我们可以使用该值来索引数组吗?是的当然。

我们可以有一个指向代码的指针数组吗?也是的,这是一个数据数组,其元素值是指针(指向代码中的标签,可能是函数)。

DTBL, .FILL hello         ; data pointer to code
      .FILL world         ; data pointer to code
      .FILL there         ; data pointer to code
      ...

其中hello是函数标签,world是函数标签。我们将按如下方式使用它(假设您的索引在 R1 中,并且已知它在表大小的限制范围内):

      LEA R0, DTBL        ; point to start of data table / array
      ADD R0, R0, R1      ; points to proper element in table
      LDR R0, R0, #0      ; load data pointer element from table
      JSRR R0             ; indirect function call thru pointer

或者如果代码标签不是函数,而只是代码中的标签都在同一个函数中,那么JMP而不是JSR

      LEA R0, DTBL        ; point to start of data table / array
      ADD R0, R0, R1      ; points to proper element in table
      LDR R0, R0, #0      ; load data pointer element from table
      JMP R0              ; indirect jump thru pointer

此外,如果您愿意,您可以创建一个“代码数组”,其中数组元素是可执行指令(通常是BR指令)的表。因此,我们可以对代码数组进行索引,而不是对数据数组进行索引来执行间接分支——通过索引跳转到代码数组。

CTBL, BR hello            ; code instruction element
      BR world            ; code instruction element
      BR there            ; code instruction element
      ...

这将更直接地用作分支目标,而不是将元素作为指针加载:

      LEA R0, CTBL        ; points to start of code table / array
      ADD R0, R0, R1      ; points to proper element from table
      JSRR R0 ; or JMP R0 ; indirect function call (or jmp) directly into the table

您在这里看到我们实际上分支到表中,因为每个元素都是可执行指令。


这些是编译器用于switch语句的一些结构,特别是当case值密集且连续时。当它们不是时,编译器将尝试识别此类范围的不同组,使用普通的 if-then-else 构造来分隔这些组。


推荐阅读