代码设计与实现
-
采用面向对象方式进行代码设计,涉及到的类的结构图如下:
-
代码总的设计思路是,终端读入字符到StackMachine,然后StackMachine根据字符产生相应种类的StackCommand,StackMachine再执行这些相关的指令并维护自身所持有的栈。下面我们按照书写顺序来分析各个Class的代码。流程图见下:
-
StackCommand:这里注释给出了该类的features含义。该类是让StackMachine执行的命令的载体,方便后续进行命令的扩展。
class StackCommand {
(*
cName: The name or string of command.
cType: It is designed to classify different command, but now we just need use "case".
getName(): To get cName.
getType(): To get cType.
init(String): Use a string to name command.
*)
cName : String;
cType : Int;
getName() : String {
cName
};
getType() : Int {
cType
};
init(commandName : String) : StackCommand {
{
cName <- commandName;
self;
}
};
};
- StackExecuteCommand/StackDisplayCommand/StackStopCommand
这里给出了三种命令,分别是执行、打印、停止的命令,这三个命令没有引入新的属性和方法,只是继承了StackCommand,并改写了cType的值,其实后面并没有用到。
class StackExecuteCommand inherits StackCommand {
init(comandName : String) : StackCommand{
{
self@StackCommand.init(comandName);
cType <- 0;
self;
}
};
};
class StackDisplayCommand inherits StackCommand {
init(comandName : String) : StackCommand{
{
self@StackCommand.init(comandName);
cType <- 1;
self;
}
};
};
class StackStopCommand inherits StackCommand {
init(comandName : String) : StackCommand{
{
self@StackCommand.init(comandName);
cType <- 2;
self;
}
};
};
- StackPushCommand中添加了一个属性"elem",用来记录要被添加到栈中的元素(element),该命令就是来让StackMachine将需要push到栈中的元素push进去,因此需要额外引入“elem”属性。
class StackPushCommand inherits StackCommand {
elem : Element; (*The element will be pushed into the stack.*)
getElem() : Element {elem};
initPC(comandName : String , e : Element) : StackCommand{
{
self@StackCommand.init(comandName);
cType <- 3;
elem <- e;
self;
}
};
};
- Element是栈中存放的数据类型,最开始是想要把字符串直接放入的,但是考虑到放入栈中的只能有数据和操作符(Data and Operation),并且后续可能有多种Data和Operation,因此我们定义了Element类,用来存入栈中。
class Element {
(*
eName: The name of element.
eType: The type of element. It is designed to classify different element but now we just need use "case".
getName(): To get eName.
getType(): To get eType.
init(): Use a string to init the eName.
*)
eName : String;
eType : Int;
getName() : String {
eName
};
getType() : Int {
eType
};
init(elementName : String) : Element{
{
eName <- elementName;
self;
}
};
};
- Operation类指的是操作符,增加了新的属性"opNumber",以及对应的获取方法getOpNum()。opNumber属性是用来表示该操作符的操作数,本次实验操作符"s"和"+"均为双目运算符;同时代码添加了initOp()方法,用来初始化一个操作符。
class Operation inherits Element {
opNumber : Int;
getOpNum() : Int {
opNumber
};
initOp(elementName : String , operationNumber : Int) : Operation{
{
self@Element.init(elementName);
eType <- 0;
opNumber <- operationNumber;
self;
}
};
};
- Data类就是数据类型,可以有多个具体的数据类型继承,但是这里为了简便,仅采用一个属性"dType"用来表示数据类型,这里用0表示Int型,同时增加了initData()方法,用来初始化一个数据。
(*
* The types of data means:
* 0 : int;
*)
class Data inherits Element {
dType : Int;
getType() : Int {
dType
};
initData(elementName : String , dataType : Int) : Data{
{
self@Element.init(elementName);
eType <- 1;
dType <- dataType;
self;
}
};
};
- 目前为之,我们已经分析了两个主要的类:StackCommand和Element,下面简要分析Stack的组成。这里参考的是list.cl中列表的实现,有点类似于c语言中的链表,因此我们也是通过实现一个链表,然后通过对链表的维护,实现一个栈,这里栈中基本的数据类型就是Element。
- Link/LinkCons:这两个类主要是为了构成链表,如同c语言中结构体Node来实现链表,具体可以参考/examples/list.cl
class Link {
isNil() : Bool {true};
head() : Element {{abort();new Element.init("NULL");}};
tail() : Link {{abort();self;}};
setRest(r : Link) : Link {{abort(); new LinkCons.init(head(),tail());}};
cons(e : Element) : Link {
(new LinkCons).init(e,self)
};
};
class LinkCons inherits Link{
elem : Element;
rest : Link;
isNil() : Bool {false};
head() : Element {elem};
tail() : Link {rest};
setRest(r : Link) : Link{
rest <- r
};
init(e : Element , s : Link) : Link{
{
elem <- e;
rest <- s;
self;
}
};
};
- Stack:Stack继承IO,是为了方便输出。这里主要是通过对链表的维护来实现的。具体支持的方法如下
- 判断是否为空: isNil()
- 获取顶部元素: top()
- 弹出顶部元素: pop()
- 压入元素: push()
- 获取长度: getLength()
- 打印栈中元素: display()
class Stack inherits IO{
top : Element;
link : Link;
length : Int;
isNil() : Bool{link.isNil()};
getLength() : Int{length};
top() : Element {top};
pop() : Bool {
let temp : Link , void : Link in {
if isNil() then false
else {
temp <- link.tail();
link.setRest(void);
link <- temp;
if length = 1 then 1 else top <- link.head() fi;
length <- length - 1;
true;
} fi;
}
};
push(e : Element): Bool {
{
link <- link.cons(e);
top <- e;
length <- length + 1;
true;
}
};
init() : Stack {
{
link <- (new Link);
length <- 0;
top <- (new Element);
self;
}
};
display() : Stack {
{
let i : Int <- 0 , l : Link <- link in {
while i < length loop {
out_string(l.head().getName());
out_string("\n");
i <- i + 1;
l <- l.tail();
} pool;
};
self;
}
};
};
- StackMachine:该类实现对命令和元素的创建、执行以对栈的维护和操作。该类主要支持的方法如下:
- elementCreate(String): 根据读入的字符串创建相关的元素(操作符或者数据)
- commandCreate(String): StackCommand类的工厂函数,用来创建相应的命令
- execute(StackCommand): 用来执行相关命令如停止、打印、Push、执行。这里指的一提的是,对于StackExecuteCommand,我们会根据顶部元素为Operation(执行executeOp()方法)或Data(执行executeData()方法)执行不同的操作。
- run(): StackMachine的运行函数,用来显示"<"、创建命令、执行命令等。
class StackMachine inherits IO {
stack : Stack;
init() : StackMachine {
{
stack <- (new Stack).init();
self;
}
};
commandCreate(cmdString : String) : StackCommand{
if cmdString = "e" then {
new StackExecuteCommand.init(cmdString);
} else if cmdString = "d" then {
new StackDisplayCommand.init(cmdString);
} else if cmdString = "x" then {
new StackStopCommand.init(cmdString);
} else {
new StackPushCommand.initPC(cmdString,elementCreate(cmdString));
} fi fi fi
};
elementCreate(cmdString : String) : Element {
if cmdString = "+" then (new Operation).initOp(cmdString,2) else
if cmdString = "s" then (new Operation).initOp(cmdString,2) else
(new Data).initData(cmdString,0) fi fi
};
execute(scmd : StackCommand) : Bool {
let state_code : Bool in
{
case scmd of
temp : StackExecuteCommand => {
if stack.isNil() then 1 else
let elem : Element , i : Int in {
elem <- stack.top();
stack.pop();
case elem of
op : Operation => execute_op(op);
data : Data => execute_data(data);
esac;
} fi;
state_code <- true;
};
temp : StackDisplayCommand => {
stack.display();
state_code <- true;
};
temp : StackStopCommand => {
state_code <- false;
};
temp : StackPushCommand => {
stack.push(temp.getElem());
state_code <- true;
};
esac;
state_code;
}
};
execute_op(op : Operation) : StackMachine{
{
if op.getOpNum() = 2 then {
let ad : Int , bd : Int , at : Int , bt : Int , c : Int , d : Int in {
if op.getName() = "+" then {
ad <- (new A2I).a2i(stack.top().getName());
at <- stack.top().getType();
stack.pop();
bd <- (new A2I).a2i(stack.top().getName());
bt <- stack.top().getType();
stack.pop();
c <- ad+bd;
if at < bt then d <- at else d <- bt fi;
stack.push(new Data.initData((new A2I).i2a(c),d));
} else if op.getName() = "s" then {
let a : Element , b : Element in {
a <- stack.top();
stack.pop();
b <- stack.top();
stack.pop();
stack.push(a);
stack.push(b);
};
} else {
out_string("No operation: ");
out_string(op.getName());
out_string("\n");
}fi fi;
};
} else if op.getOpNum() = 1 then {
op.getOpNum();
} else {
op.getOpNum();
} fi fi ;
self;
}
};
execute_data(data : Data) : StackMachine{
self
};
run() : StackMachine {
{
let cmd : StackCommand , str : String in {
let state_code : Bool <- true in {
while state_code loop {
out_string(">");
str <- in_string();
cmd <- commandCreate(str);
state_code <- execute(cmd);
} pool;
};
};
self;
}
};
};
- Main:程序的入口,只需创建一个StackMachine并运行它即可
class Main inherits IO {
machine : StackMachine;
main() : Object {
{
machine <- (new StackMachine).init();
machine.run();
}
};
};