cool语言堆栈机基本内容

基本要求

创建一个cool语言堆栈机:
1、输入为"d",则输出所有栈中元素;
2、输入为int,“s”,“+”,存入栈中;
3、输入为"e",则进行运算,运算规则如下:
若栈顶为"s",则"s"出栈并交换下面的两个元素;
若栈顶为"+“,则”+“和下面的两个整数出栈,计算这两个整数的和并入栈。
4、输入为"x”,则直接退出;

设计思路

cool语言中只有Int,String和Bool三种基本变量类型,此处输入既有数字也有符号,且无法预测,如果使用数字进行存储和处理,在读入处使用in_int,则所有的符号输入值均为0,因此,此处需要使用in_string进行输入;同时,在存储时如果使用Int,即用某个Int值来表示某个符号,必将导致Int能表示的数字变少,因此,此处采用读入String,存储String,仅在处理时将其取出转化为整数的方法。

A2I类的设计

设计A2I类的目的在于包含所有的字符串和数字之间相互转化的函数
首先是单个字符和单个数字之间相互转化的函数

--c2i将单个的字符转换成数字
c2i(char : String) : Int 
{
	if char = "0" then 0 else
	if char = "1" then 1 else
	if char = "2" then 2 else
	if char = "3" then 3 else
	if char = "4" then 4 else
	if char = "5" then 5 else
	if char = "6" then 6 else
	if char = "7" then 7 else
	if char = "8" then 8 else
	if char = "9" then 9 else
	{ abort(); 0; }  -- the 0 is needed to satisfy the typchecker
	fi fi fi fi fi fi fi fi fi fi
};

cool语言中的条件语句只有if,case语句用于实现runtime type tests on objects,故此处只能采用if嵌套。
接着设计字符串转化为整数,首先处理正数,此处采用了循环的方法,从字符串首到尾部进行扫描,将其转化为数字

l2i_aux(s : String) : Int
{
	(let int : Int <- 0 in
	{
		(let j : Int <- s.length() in
		(
			let i : Int <- 0 in
				while i < j loop
				{
					--使用循环,将字符串一一转化为数字
					int <- int * 10 + c2i(s.substr(i,1));
					i <- i + 1;
				}
				pool
		));
	int;
	})
};

接着,当需要处理的字符串为正数时,直接调用即可,否则取返回值的相反数

l2i(s : String) : Int
{
	--如果字符串长度为0,则直接返回0
	if s.length() = 0 then 0 else
	--如果第一个符号是负号,则返回后续数字的相反数
	if s.substr(0,1) = "-" then ~l2i_aux(s.substr(1,s.length()-1)) else
	--否则直接处理即可
	l2i_aux(s)
	fi fi
};

反方向同理即可。

堆栈类的设计

因为cool语言内容很少,既不能对指针进行操作,也没有数组,所以无法使用顺序表或者链表来实现栈,故此处借用链表的思路,不过不存储下一元素的链表,而是直接将除了栈的剩余部分都放在栈顶Cons里,下面我们用stack代表我们使用的栈。

List类

List类的本质是栈顶,一旦有元素入栈,那么stack就不再是List类,因此若stack为List,那么直接可以认为栈是空的,可依此设计List的函数isNil

isNil() : Bool 
{
	true
};

另一个有用的函数是cons,用于入栈

cons(i : String) : Cons
{
	(new Cons).init(i, self)
};

两个虚函数用于让cons来继承

head() : String
{
	{abort();
	"";}
};
	
tail() : List
{
	{abort();
	self;}
};

它们的作用我会在后面细讲

Cons类

Cons类继承List类,Cons类的本质可以认为是是栈中的元素,如果stack的类型是cons,那么栈中一定是有元素的,栈一定不是空的,可以依此设计出Cons的函数isNil

isNil() : Bool
{
	false
};

Cons类中有两个元素,first代表当前的栈顶元素,而rest则存储了栈除了栈顶以外的全部内容;

first : String;
rest :  List;

此处应当注意rest设定的类型是List,但是当我们的Cons不为栈底的第一个元素时,其rest类型应该是Cons,此处可用的原因在于Cons类继承了List类,根据COOL官方文档,所有接受List的地方都接受Cons,故可以这样使用。
一个栈可以如下图表示
示意图
通过上面的示意图我们可以进一步发现,一个栈中,只有栈底的类型是List类型。
head函数用于返回当前栈顶元素,即当前Cons的first,对应图中stack正在指向的Cons2的first,即为1。

head() : String
{	
	first
};

tial函数用于出栈,我们可以发现,当需要出栈时,仅需要将stack指向当前Cons的rest即可,例如图中若出栈,即可直接指向Cons2的rest,即为Cons1

tail() : List
{
	rest
};

init函数用于创建一个新的Cons,

init(head : String, next : List) : Cons
{
	{
		first<-head;
		rest<-next;
		self;
	}
};

结合List类的cons函数,我们可以发现其入栈操作为,先生成一个cons,其first为输入值,rest为当前的栈,然后使用cons函数将stack指向新生成的cons即可完成入栈操作。
此处我们就可以明确的知道,List类中的head和tail函数都是虚函数,作用仅为让Cons类来继承。

Main类

mian函数的本质在于始终进行循环并根据不同的输入进行处理,同上,cool语言中的条件语句只有if,case语句用于runtime type tests on objects,因此只能使用if嵌套的方式。

加操作

1、取出两个栈顶元素a,b
2、将其转换为int,即为anum和bnum
3、anum + bnum,得到结果cnum
4、结果转换为字符串c
5、将c压入栈

let a : Int <- new Int, b : Int <- new Int in 	
{
	a <- z.a2i(stack.head());
	stack <- stack.tail();
	b <- z.a2i(stack.head());
	stack <- stack.tail();
	let c : Int <- a + b in
	stack <- stack.cons(z.i2a(c));
};

s交换操作

1、取出两个元素a,b
2、按先a后b的顺序压入这两个元素

let a : String <- new String , b : String <- new String in 
{
	a <- stack.head();
	stack <- stack.tail();
	b <- stack.head();
	stack <- stack.tail();
	stack <- stack.cons(a);
	stack <- stack.cons(b);
};

参考资料

The Cool Reference Manual

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值