input a number and store it in x
input a number and store it in y
while x < 10 do
x =x +1
output value of x;
end while
output the value of y*2
1 回答
While 语句使用 if-goto-label 转换为汇编语言。我们可以用 C 来说明:
while ( x < 10 ) {
x++;
print(x);
}
...
变成:
loop1:
if ( x >= 10 ) goto loop1Done; // this is a conditional branch
x++;
print(x);
goto loop1; // this is an unconditional branch
loop1Done:
...
请注意,在 if-goto-label 样式中,条件x < 10
反转为x >= 10
b/c 我们希望在此条件下退出循环,而 Cwhile
语句告诉我们何时继续循环。因为这两种意义(C while
vs. C if-goto-label)是相反的,所以我们选择 的否定x < 10
,即x >= 10
退出循环。
对应于 C 的 goto 语句,MARIE 使用Jump
汇编指令进行无条件分支。
对应于 C 的 if-goto 结构,MARIE 使用条件跳转进行条件分支:该Skipcond
指令用于多指令序列中。
将累加器寄存器 与 0Skipcond
进行比较AC
,要么允许执行下一条指令,要么跳过并跳过它——当它跳过时,它正好跳过 1 条指令:不多也不少。通常下一条指令Jump
用于更改控制流程(它不一定是跳转,它可以是您想要有条件地跳过的任何其他单条指令)。
为了完成条件分支(if-goto),我们将条件跳转指令 ,Skipcond
与无条件分支指令 ,结合起来Jump
。因为我们告诉Skipcond
何时跳过,它只会在不跳过时分支。因此,我们从 if-goto-label 形式中否定条件:Skipcond
if ( x >= 10 ) goto loop1Done;
变成:
Skipcond 000 // Skip the Jump if AC < 0
Jump loop1Done // Jump may or may not fire, depending on prior Skip
对于更大范围的示例,请使用以下语句:
if ( x >= 10 ) goto loop1Done;
因为跳过/跳转序列使我们从 if-goto-label 形式中取反(第二次,如果你从 C 开始),我们想要x < 10
在Skipcond; Jump
序列中设置。
首先我们应用一些基本的数学运算:x - 10 < 0
,从关系运算符的两边减去 10 <
,保留x < 10
(modulo overflow)的逻辑。现在我们有了一个比较为零的表达式,这适合 MARIESkipcond
可以为我们做的事情。
loop1,
// if ( x >= 10 ) goto loop1Done;
load X // AC = x
Subt Ten // AC = x - 10
Skipcond 000 // MARIE will skip the next instruction if AC < 0, i.e. x < 10
Jump loop1Done // Will only fire if AC >= 0, i.e. x >= 10
// x++;
Load X // AC = x
Add One // AC = x + 1
Store X // x = AC
Output // outputs the AC (note that the AC == x here)
Jump loop1 // continue the loop
loop1Done, // end of loop, on to next statement after
...
// Variables & Constants
X, Hex 0
Ten, Dec 10
One, Dec 1
总之,我们可以使用 if-goto、goto 和标签将任何控制结构从结构化语句形式转换为汇编形式。即使结构化语句是嵌套的(嵌套不会改变替换模式),结构化语句也使用此类模式进行字面翻译。
在 MARIE 上,我们可以从一对 skipcond/jump 指令组成 if-goto 操作。为了使用 skipcond/jump 对,我们需要计算一个相对于 0 的值到 AC 中(即x-10
)。
MARIE 上的复杂问题,Skipcond
不具有所有通用关系:<
, <=
, ==
, !=
, >=
, >
. MARIE 只有<
, ==
, 和>
— 它们不能在一条指令中组合成<=
or >=
。
有时我们需要使用Skipcond
不会直接为我们执行的关系运算符之一执行 if-goto(所以,是的,我们可以再次反转条件)。
首先,让我们看看在 if-goto-label 中使用相反条件的通用方法:
if ( x >= 10 ) goto label1; // goes to label1 if x >= 10
... // comes here otherwise, i.e. x < 10
if ( x < 10 ) goto uniqueNewlabel; // goes to uniqueNewLabel if x < 10
goto label1; // goes here (which jumps to label1) if x >= 10
uniqueNewlabel: // comes here if x < 10
上面的后者将原始 if-goto 中<
的关系替换为关系的使用,以完成相同的控制流逻辑。>=
顺便说一句,这种转换也可以反过来起作用,所以如果你有后者,它可以转换成前者。
好的,现在我们有了一个方法来反转我们需要的操作,我们可以将它应用到 MARIE 的Skipcond
序列中。假设我们确实需要以下内容:
if ( x < 10 ) goto somewhere;
在 MARIE 的假设变体中,这可能转化为
Skipcond >= // skips the succeeding Jump on >=
Jump somewhere // goes here on <, so executes the Jump
但是没有 Skipcond for >=
。我们将使用上述模式替换来反转>=
为<
MARIE 确实具有的:
Skipcond 000 // < that MARIE does have
Jump uniqueNewLabel // fires only when >=, so used to "skip" the next line
Jump somewhere // desired target for when <
uniqueNewLabel,
还有其他模式可以改变测试的感觉。
if ( x < 10 ) goto somewhere;
在逻辑上等价于(在整数上):
if ( x <= 9 ) goto somewhere;
<
交换了for 的使用后<=
,我们可以再次使用 MARIE 的 Skipcond/Jump 两个指令对来处理这个 if-goto。