PA1中我们要通过实现一个栈机器(stack machine)来熟悉Cool
语言。
规定和要求
定义栈中的如下命令:
命令 | 含义 |
---|---|
int | 压入一个整型数据int |
+ | 压入’+'字符 |
s | 压入’s’字符 |
e | 根据栈顶字符进行操作 |
d | 自顶向下打印栈中数据 |
x | 停止程序 |
e
命令根据栈顶元素的不同而进行不同操作,栈顶为:
- ‘+’:弹出’+'后,再弹出2个整型数字,相加后再压入栈。
- ‘s’:弹出’s’后,栈中最上面的2个元素交换位置。
- 数字或栈为空:什么也不做。
- ‘x’:停止程序的运行。
遇到e
后进行操作的一些例子:
要求:
- 输入为一系列如上面所说的命令,一个命令占一行。
- 每个输入前应该有输入提示符
>
。 - 输入无需错误检查。
- 输入的数字int>=0。
- 为了保持优雅,当接收到
x
时不要使用abort()
退出。
一些注意点
下面列出一些我在编写过程中遇到的比较容易出错的地方:
- 类和函数的大括号后必须跟
;
- 使用
while
和if
时不要忘了loop
、pool
、then
、fi
- 如果函数中只是单独一个表达式,那么后面不用跟
;
,这个表达式值就是返回值,如果有多个表达式,必须将所有表达式都再放在一个{}
中,并且每个后面都要有;
,最后一个表达式的值才是返回值 - 定义变量
x
需要let x: Xxx in {...}
,不能直接x: Xxx
定义
实现
大概流程
我们可以实现一个栈(Stack
)以及一个控制栈操作的控制器(Controller
),栈中实现栈各项操作的函数,而控制器负责对栈进行控制以实现功能。
栈
Cool
里面好像没有数组(巨捞无比),因此我们使用链表式的栈,为了实现这种栈,要先实现节点,因此先定义节点类Node
。
Node
class Node {
item: String;
next: Node;
(*初始化*)
init(i: String, n: Node):Node {
{
item <- i;
next <- n;
self;
}
};
(*判断当前存放的字符串是否为数字*)
isNumber():Bool {
if (item = "+") then false
else
if (item = "s") then false
else
if (item = "e") then false
else
if (item = "d") then false
else
if (item = "x") then false
else true
fi
fi
fi
fi
fi
};
(*自顶向下遍历*)
display():String {
if (isvoid next) then
item
else
item.concat(" ").concat(next.display())
fi
};
(*getter和setter*)
getNext(): Node {
next
};
setNext(s: String): Node {
{ next <- (new Node).init(s, next); next; }
};
getItem():String {
item
};
setItem(i: String):String {
{ item <- i; item; }
};
};
下面就可以开始实现栈了。
Stack
class Stack {
top: Node;
size: Int;
init(): Stack {
{
size <- 0;
self;
}
};
getSize(): Int { size };
getTop():Node { top };
display(): IO {
if (0 < size ) then (new IO).out_string(top.display().concat("\n"))
else (new IO).out_string("\n")
fi
};
push(data: String):Stack {
{
top <- (new Node).init(data, top);
size <- size + 1;
self;
}
};
pop(): Node {
if (size = 0) then top
else
let t: Node <- top
in
{
top <- top.getNext();
size <- size - 1;
t;
} fi
};
plus(): Int {
let a: Int <- 0,
b : Int <- 0,
c: Int <- 0
in
{
a <- (new A2I).a2i(pop().getItem());
b <- (new A2I).a2i(pop().getItem());
c <- a + b;
push((new A2I).i2a(c));
c;
}
};
swap(): Node {
let first: Node <- top,
second:Node <- first.getNext(),
third: Node <- second.getNext()
in
{
top <- second;
second.setNext(first);
first.setNext(third);
}
};
};
控制器
class Controller {
stack: Stack;
init(s: Stack): Controller {
{
stack <- s;
self;
}
};
showInputPrompt(): IO {
(new IO).out_string(">")
};
showStopPrompt(): IO {
(new IO).out_string("stop!\n")
};
getString():String {
(new IO).in_string()
};
run(): Controller {
let c: String <- "" in {
showInputPrompt();
c <- getString();
while (not(c = "x")) loop {
input(c);
showInputPrompt();
c<-getString();
}
pool;
showStopPrompt();
self;
}
};
input(s: String): Controller {
if(s = "e") then
{ operateE(); self; }
else
if (s = "d") then
{ stack.display(); self; }
else
{ stack.push(s); self; }
fi
fi
};
operateE(): Controller {
if (0 < stack.getSize()) then
let t:Node <- stack.getTop(), s:String <- "" in
if (t.isNumber() = false) then
{
s <- stack.pop().getItem();
if (s = "+") then { stack.plus(); self; }
else
if (s = "d") then { stack.display(); self; }
else
if (s = "e") then operateE()
else
if (s = "s") then { stack.swap(); self; }
else self
fi
fi
fi
fi;
}
else self
fi
else self
fi
};
};
入口Main
class Main {
main() : Object {
let s: Stack <- (new Stack).init(),
c: Controller <- (new Controller).init(s)
in
c.run()
};
};