ACM解题总结——HihoCoder1155

题目来源:
    HihoCoder1155

题目要求:
    题目要求给定一个Lisp语句,求解表达式的值。
    Lisp语句的表达式格式有如下几种:
    (1) 单独的一个非负整数是一个合法的表达式,如:2。
    (2) 单独的一个布尔值是一个合法的表达式,其值只有2种:true 和 false。
    (3) 定义变量。变量的名称由不超过10个的小写英文字母组成,true,false,let,if为保留字,不能作为变量名,该表达式的值为变量的绑定值,如果变量没有绑定,则表达式非法,程序输出:Unbound Identifer。
    (4) 算术运算。包括加减乘除,格式为:( + x y )、( - x y )、( * x y )、( / x y )。其中 x y 均为合法的表达式,并且只有 x y 的值的结果均为数字时,该表达式才合法,否则,表达式非法,程序输出:Type Mismatch。另外,如果除法表达式中的除数是0,则该表达式非法,程序输出:Division By Zero。
    (5) 分支表达式:if。格式为:( if a b c )。其中:a b c 均为合法的表达式。a的表达式的值必须为布尔值,否则,该表达式非法,程序输出:Type Mismatch。如果表达式a的值为true,则该表达式的值为表达式b的计算值,否则,该表达式的值为表达式c的计算值。
    (6) let表达式。let表达式的作用是对变量绑定一个值。格式为:( let ( x a ) b ),其中 x 一定为变量, a 是合法的表达式,该表达式的值是把 x = a 代入到b中后,表达式b的计算值。例如:表达式:( let ( x 2 ) ( + x 1 ) )的值是3;另外在包含let表达式嵌套的表达式中,如果对相同的变量绑定多次,则最层的绑定有效,如:表达式 ( let ( x 1 ) ( let (x 2) ( + x 1 ) ) ) 的计算值是3而不是2。
    (7)比较运算。格式为 ( < x y )、 ( > x y )、( = x y )。其中 x y 都是合法的表达式,并且计算值必须为数字,否则,该表达式非法,程序输出:Type Mismatch。根据x y的值的大小关系确定该表达式的值为true或false。
    以上是题目中用到的Lisp表达式的语法。
    给定的输入数据保证语法正确,仅存在逻辑错误。

解答:
    本题的要求其实是要编写一个简单的编译器。代码量比较大,但难度不算太难。基本的解答思路是根据输入的表达式构建语法树。然后遍历语法树后,整个表达式的值就存储在语法树的根节点中。比较好的一点是:题目中所有的语法都是“前缀语法”,即操作符在操作数的前面。这样程序处理数据的顺序就是表达式的读取顺序——从左到右。首先说明语法树的构建方式。
    根据题目中的语法的描述,需要用到的语法树的节点有如下的几种:
    (1) 数值: 这是最简单的节点,没有子节点,在语法树中是叶子节点。节点的值就是数值本身,存储在节点内。如下:
    
     (2)布尔值:这也是最简单的节点,在语法树中也是叶子节点。节点的值就是布尔值本身,存储在节点内。如下:
     
    (3)变量:变量有变量名和变量值两个属性,但表达式的值仅和变量的值有关,因此变量也是一个叶子节点,节点中存储变量的名称和变量值:
     
    (4)算术计算。算术运算表达式的值需要先计算两个子表达式 x y 的值,再计算整个表达式的值,因此它有两个子节点,分别代表子表达式 x 和 y。如下:
     
    (4)分支表达式:表达式( if a b c ) 的值由表达式 a b c 的值决定,因此if节点具有3个子节点,分别代表表达式a b c,如下:
     
    (6)let 表达式:let表达式有三个字表达式:变量x,赋值表达式a,以及求值表达式b,因此它也有3个子节点,分别代表变量、赋值表达式a、求值表达式b:
      
    (7) 比较运算:比较运算的处理方式和算术运算类似,它也有两个子节点,分别代表子表达式:x 和 y:
     
 
     通过上面的方法,就可以把一个表达式转化为一棵语法树。例如,表达式:
 ( let ( x 4 ) ( if true x y ) )
可以转化为如下的语法树:    

    树中的每个节点存储该节点代表的表达式的值,因此求解整个表达式的值就是对语法树由上到下、从左到右进行深度优先搜索的过程,上面的语法树的求解过程如下:
    (i) 首先访问let节点,计算let表达式的值需要首先计算赋值表达式的值,即let节点的第二个子节点。
    (ii) let节点的第二个节点是一个数字,其值可以直接读出。该节点求解完成。回溯到根节点let。
    (iii) 接下来,求解let表达式中的求值表达式,即let节点的第3个子节点。
    (iv) 求解let节点的第三个子节点的值,该节点是if节点,需要先求解它的第1个子节点的值。
    (v) if节点的第一个子节点为布尔值,节点的值可以直接读出,该节点求解完毕。回溯到if节点。
    (vi) 由于第一个节点的结果是true,因此此时需要求解if节点的第二个子节点的值。
    (vii) if节点的第二个节点是变量,此时x已经被绑定为4,因此该节点的值是4,求解完毕,回溯到if节点。
    (viii) 此时if节点可以求解,它的值就是第2个节点的值,if节点求解完毕回溯到let节点。
    (ix) 此时let节点也可以求值了,它的值就是它第三个节点的值,结果是4。整个表达式的值求解完毕。
    因此,利用语法树求解表达式的值的基本过程就是:从根节点采用深度优先搜索的方式对树进行遍历,如果某个节点有子节点则递归求解子节点的值,然后求解本节点的值后返回。这样遍历完成后就可以从树的根节点中找到整个表达式的值。如果在求解过程中发现题目中说明的非法情况,则输出相关信息,求解结束。
    在每一轮递归过程中,在完成子节点的求解后,在求解本节点的值的过程根据语法的定义求解即可。这里需要说明的是let表达式的求解过程,由于求解let节点的第3个子节点的值的过程中会遇到变量,而变量的值则由let节点的第1、2个子节点决定。因此在求解let节点的第3个子节点的值时会用到这些信息。这里可以定义一个“变量表”来存储每一个变量的值,在求解过程中,如果遇到了变量,就查找这个变量表找到对应变量的值即可,如果找不到对应的表项,则说明该变量没有绑定值,求解非法。
    例如:表达式:( let ( x 1 ) ( let ( x 2 ) ( + x 1 ) ) ) 的语法树和变量表如下:

 
    由于内层变量的绑定会覆盖掉外层,因此在查找变量的值时,要从下向上查找,第一个符合的表项就是要找的变量的值。

输入输出格式:
    输入:第一行为一个整数T,表示有T组测试数据;
            接下来的T行,每一行为一个字符串,表示一个Lisp表达式。
    输出:对于每一个表达式,输出一行,显示表达式的值,如果表达式非法,则输出出错信息。

程序代码:

/****************************************************/
/* File        : hiho_week_87.cpp                   */
/* Author      : Zhang Yufei                        */
/* Date        : 2016-03-01                         */
/* Description : HihoCoder ACM program. (submit:g++)*/
/****************************************************/

/*
 * Update log:
 *		Create by Zhang Yufei in 2016-03-01 ~ 2016-03-02.
 *		Submit result: CE->PE->AC.
 * End.
 */
 
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>

/*
 * Define the closure to record variant in the situation of program
 */
typedef struct node {
	int value;
	int value_type;
	char name[25];
	struct node *pre;
} Closure;

/*
 * Define the super class of s_expression.
 * Parameters:
 *		@type: The type of this expression. The value is as follow:
 *		+-------+------------------------------------------------+ 
 *		| value | 		type                             |
 *              +-------+------------------------------------------------+
 *              |   0   |	nonnegtive integer                       |
 *              +-------+------------------------------------------------+
 *		|   1   |	boolean value: true, false               |
 *              +-------+------------------------------------------------+
 *		|   2   |  <span style="white-space:pre">	</span>variant                                  |
 *		+-------+------------------------------------------------+
 *		|   3   |	add: + x y                               |
 *		+-------+------------------------------------------------+
 *		|   4   |	substract: - x y                         |
 *		+-------+------------------------------------------------+
 *		|   5   |	multiply: * x y                          |
 *		+-------+------------------------------------------------+
 *		|   6   |	devide: / x y                            |
 *		+-------+------------------------------------------------+
 *		|   7   |	if expression: if a b c                  |
 *		+-------+------------------------------------------------+
 *		|   8   |	let expression: let ( x a ) b            |
 *		+-------+------------------------------------------------+
 *		|   9   |	greater comparision: > x y               | 
 *		+-------+------------------------------------------------+
 *		|   10  |	equal comparision: = x y                 |
 *		+-------+------------------------------------------------+
 *		|   11  |	less comparision: < x y                  |
 *		+-------+------------------------------------------------+ 
 *		@value: The value of this s_expression.
 *		@value_type: The type of value.
 */
typedef struct node1 {
	int type;
	int value;
	int value_type;
} s_expression;

/*
 * The sub-classes of s_expression:
 */

// nonnegtive integer
typedef struct node2 {
	int type;
	int value;
	int value_type;
} Integer;

// boolean
typedef struct node3 {
	int type;
	int value;
	int value_type;
} Boolean;

typedef struct node4 {
	int type;
	int value;
	int value_type;
	char name[20];
} Variant;

// + x y 
typedef struct node5 {
	int type;
	int value;
	int value_type;
	s_expression *x, *y;
} Add;

// - x y 
typedef struct node6 {
	int type;
	int value;
	int value_type;
	s_expression *x, *y;
} Substract;

// * x y 
typedef struct node7 {
	int type;
	int value;
	int value_type;
	s_expression *x, *y;
} Multiply;

// / x y 
typedef struct node8 {
	int type;
	int value;
	int value_type;
	s_expression *x, *y;
} Devide;

// if a b c
typedef struct node9 {
	int type;
	int value;
	int value_type;
	s_expression *a, *b, *c;
} If;

// let (x a) b
typedef struct node10 {
	int type;
	int value;
	int value_type;
	s_expression *x, *a, *b;
} Let;

// < x y
typedef struct node11 {
	int type;
	int value;
	int value_type;
	s_expression *x, *y;
} Greater;

// = x y
typedef struct node12 {
	int type;
	int value;
	int value_type;
	s_expression *x, *y;
} Equal;

// < x y
typedef struct node13 {
	int type;
	int value;
	int value_type;
	s_expression *x, *y;
} Less;


// The input data.
char input[250];
// The length of input.
int length;
// The curren index in the process of interpreting.
int start;

/*
 * This function deals with one test case.
 * Parameters:
 *		None.
 * Returns:
 *		None.
 */
void function(void);

/*
 * This function sets a synax tree using given input s_expression.
 * Parameters:
 *		None.
 * Return:
 *		The root node of the synax tree.
 */
s_expression* set_tree(void);

/*
 * This function transfers the string into nodes in synax tree
 * Parameters:
 *		None.
 * Returns:
 *		The node created by this function.
 */
s_expression* make_node(void);

/*
 * This function calculates the value of the input s_expression.
 * Parameter:
 *		@expression: The root of synax tree generated by input s_expression.
 *		@closure: The current closure node of the situation.
 * Return:
 *		If computing process is correct and the result has been worked out,
 *		returns 1, or returns 0.
 */
int calculate(s_expression *expression, Closure *closure);

/*
 * The main progarm.
 */
int main(void) {
	int T;
	scanf("%d", &T);
	getchar();
	for(int i = 0; i < T; i++) {
		function();
	}
	
	return 0;
} 

/*
 * This function deals with one test case.
 * Parameters:
 *		None.
 * Returns:
 *		None.
 */
void function(void) {	
	gets(input);
	length = strlen(input);
	start = 0;
	s_expression *s = set_tree();
	if(calculate(s, NULL) == 1) {
		if(s->value_type == 0) {
			printf("%d\n", s->value);
		} else if(s->value_type == 1) {
			if(s->value == 1) {
				printf("true\n");
			} else {
				printf("false\n");
			}
		}
	}
}

/*
 * This function sets a synax tree using given input s_expression.
 * Parameters:
 *		None
 * Return:
 *		The root node of the synax tree.
 */
s_expression* set_tree(void) {
	s_expression *s = make_node();
	switch (s->type) {
		case 0: break; 
		case 1: break;
		case 2: break; 
		case 3: { Add *add = (Add*)s;
				add->x = set_tree();
				add->y = set_tree();
				break; }	
		case 4: { Substract *substract = (Substract*)s;
				substract->x = set_tree();
				substract->y = set_tree();
				break; }
		case 5: { Multiply *multiply = (Multiply*)s;
				multiply->x = set_tree();
				multiply->y = set_tree();
				break; }
		case 6: { Devide *devide = (Devide*)s;
				devide->x = set_tree();
				devide->y = set_tree();
				break; } 
		case 7:	{ If *iF = (If*)s;
				iF->a = set_tree();
				iF->b = set_tree();
				iF->c = set_tree();
				break; }
 		case 8: { Let *let = (Let*)s;
				let->x = set_tree();
				let->a = set_tree();
				let->b = set_tree();
				break; }
		case 9: { Greater *greater = (Greater*)s;
				greater->x = set_tree();
				greater->y = set_tree();
				break; }
		case 10: { Equal *equal = (Equal*)s;
				equal->x = set_tree();
				equal->y = set_tree(); 
				break; }
		case 11: { Less *less = (Less*)s;
				less->x = set_tree();
				less->y = set_tree(); 
				break; }
		default: break;
	}
	
	return s;	
}

/*
 * This function transfers the string into nodes in synax tree
 * Parameters:
 *		None
 * Returns:
 *		The node created by this function.
 */
s_expression* make_node(void) {
	s_expression *node;
	
	while(start < length && (isblank(input[start]) ||
		input[start] == ')' || input[start] == '('))
		start++;
		
	if(isdigit(input[start])) {
		Integer *integer = (Integer*) malloc(sizeof(Integer));
		int num = 0;
		while(isdigit(input[start])) {
			num *= 10;
			num += input[start] - 48;
			start++;
		}
		integer->type = 0;
		integer->value = num;
		node = (s_expression*) integer;
	} else if(input[start] == '+') {
		Add *add = (Add*) malloc(sizeof(Add));
		add->type = 3;
		node = (s_expression*) add;
		start++;
	} else if(input[start] == '-') {
		Substract *substract = (Substract*) malloc(sizeof(Substract));
		substract->type = 4;
		node = (s_expression*) substract;	
		start++;
	} else if(input[start] == '*') {
		Multiply *multiply = (Multiply*) malloc(sizeof(Multiply));
		multiply->type = 5;
		node = (s_expression*) multiply;
		start++;
	} else if(input[start] == '/') {
		Devide *devide = (Devide*) malloc(sizeof(Devide));
		devide->type = 6;
		node = (s_expression*) devide;
		start++;
	} else if(input[start] == '>') {
		Greater *greater = (Greater*) malloc(sizeof(Greater));
		greater->type = 9;
		node = (s_expression*) greater;
		start++;
	} else if(input[start] == '=') {
		Equal *equal = (Equal*) malloc(sizeof(Equal));
		equal->type = 10;
		node = (s_expression*) equal;
		start++;
	} else if(input[start] == '<') {
		Less *less = (Less*) malloc(sizeof(Less));
		less->type = 11;
		node = (s_expression*) less;
		start++;
	} else if(isalpha(input[start])) {
		char ch[15];
		int index = 0;
		while(isalpha(input[start])) {
			ch[index++] = input[start++];
		}
		ch[index] = '\0';
		
		if(strcmp("if", ch) == 0) {
			If *iF = (If*) malloc(sizeof(If));
			iF->type = 7;
			node = (s_expression*) iF;
		} else if(strcmp("let", ch) == 0) {
			Let *let = (Let*) malloc(sizeof(Let));
			let->type = 8;
			node = (s_expression*) let;
		} else if(strcmp("true", ch) == 0 || strcmp("false", ch) == 0) {
			Boolean *boolean = (Boolean*) malloc(sizeof(Boolean));
			boolean->type = 1;
			if(strcmp("true", ch) == 0) {
				boolean->value = 1;
			} else {
				boolean->value = 0;
			}
			node = (s_expression*) boolean;
		} else {
			Variant *variant = (Variant*) malloc(sizeof(Variant));
			variant->type = 2;
			strcpy(variant->name, ch);
			node = (s_expression*) variant;
		}
	}
	
	return node;
}

/*
 * This function calculates the value of the input s_expression.
 * Parameter:
 *		@expression: The root of synax tree generated by input s_expression.
 *		@closure: The current closure node of the situation.
 * Return:
 *		If computing process is correct and the result has been worked out,
 *		returns 1, or returns 0.
 */
int calculate(s_expression *expression, Closure *closure) {
	int type = expression->type;
	
	switch (type) {
		case 0: expression->value_type = 0; return 1;         // Integer.
		case 1: expression->value_type = 1; return 1;         // Boolean.
		case 2: {Closure *c = closure;                         // variant.
				Variant *v = (Variant*) expression;
				while(c != NULL) {
					if(strcmp(v->name, c->name) == 0) {
						v->value = c->value;
						v->value_type = c->value_type;
						return 1;
					}
					c = c->pre;
				} 
				printf("Unbound Identifier\n");
				return 0; }
		case 3: { Add *add = (Add*) expression;                 // + x y
				if(calculate(add->x, closure) == 0) {
					return 0;
				}
				if(calculate(add->y, closure) == 0) {
					return 0;
				}
				if(add->x->value_type != 0 
					|| add->y->value_type != 0) {
					printf("Type Mismatch\n");
					return 0;
				}
				add->value = add->x->value + add->y->value;
				add->value_type = 0;
				return 1; }
		case 4: { Substract *substract = (Substract*) expression;// - x y
				if(calculate(substract->x, closure) == 0) {
					return 0;
				}
				if(calculate(substract->y, closure) == 0) {
					return 0;
				}
				if(substract->x->value_type != 0 || substract->y->value_type != 0) {
					printf("Type Mismatch\n");
					return 0;
				}
				
				substract->value = substract->x->value - substract->y->value;
				substract->value_type = 0;
				return 1; }
		case 5: { Multiply *multiply = (Multiply*) expression;   // * x y
				if(calculate(multiply->x, closure) == 0) {
					return 0;
				}
				if(calculate(multiply->y, closure) == 0) {
					return 0;
				}
				if(multiply->x->value_type != 0 || multiply->y->value_type != 0) {
					printf("Type Mismatch\n");
					return 0;
				}
				
				multiply->value = multiply->x->value * multiply->y->value;
				multiply->value_type = 0;
				return 1; }
		case 6: { Devide *devide = (Devide*) expression;         // / x y
				if(calculate(devide->x, closure) == 0) {
					return 0;
				}
				if(calculate(devide->y, closure) == 0) {
					return 0;
				}
				if(devide->x->value_type != 0 || devide->y->value_type != 0) {
					printf("Type Mismatch\n");
					return 0;
				}
				if(devide->y->value == 0) {
					printf("Division By Zero\n");
					return 0;
				}
				devide->value = devide->x->value / devide->y->value;
				devide->value_type = 0;
				return 1; }
		case 7: { If *iF = (If*) expression;                    // if a b c
				if(calculate(iF->a, closure) == 0) {
					return 0;
				}
				if(iF->a->value_type != 1) {
					printf("Type Mismatch\n");
					return 0;
				}
				if(iF->a->value == 1) {
					if(calculate(iF->b, closure) == 0) {
						return 0;
					}
					iF->value = iF->b->value;
					iF->value_type = iF->b->value_type;
					return 1;	
				} else {
					if(calculate(iF->c, closure) == 0) {
						return 0;
					}
					iF->value = iF->c->value;
					iF->value_type = iF->c->value_type;
					return 1;
				} }
		case 8: { Let *let = (Let*) expression;               // let ( x a ) b
				if(calculate(let->a, closure) == 0) {
					return 0;
				}
				Closure *new_c = (Closure*) malloc(sizeof(Closure));
				new_c->value = let->a->value;
				new_c->value_type = let->a->value_type;
				strcpy(new_c->name, ((Variant*) (let->x))->name);
				new_c->pre = closure;
				
				if(calculate(let->b, new_c) == 0) {
					free(new_c);
					return 0;
				}
				free(new_c);
				let->value = let->b->value;
				let->value_type = let->b->value_type;
				return 1; }
		case 9: { Greater *greater = (Greater*) expression;   // > x y
				if(calculate(greater->x, closure) == 0) {
					return 0;
				}
				if(calculate(greater->y, closure) == 0) {
					return 0;
				}
				if(greater->x->value_type != 0 || 
					greater->y->value_type != 0) {
						printf("Type Mismatch\n");
						return 0;		
					}
				if(greater->x->value > greater->y->value) {
					greater->value = 1;
					greater->value_type = 1;
					return 1;
				} else {
					greater->value = 0;
					greater->value_type = 1;
					return 1;
				} }
		case 10: { Equal *equal = (Equal*) expression;   // = x y
				if(calculate(equal->x, closure) == 0) {
					return 0;
				}
				if(calculate(equal->y, closure) == 0) {
					return 0;
				}
				if(equal->x->value_type != 0 || 
					equal->y->value_type != 0) {
						printf("Type Mismatch\n");
						return 0;		
					}
				if(equal->x->value == equal->y->value) {
					equal->value = 1;
					equal->value_type = 1;
					return 1;
				} else {
					equal->value = 0;
					equal->value_type = 1;
					return 1;
				} }
		case 11: { Less *less = (Less*) expression;   // < x y
				if(calculate(less->x, closure) == 0) {
					return 0;
				}
				if(calculate(less->y, closure) == 0) {
					return 0;
				}
				if(less->x->value_type != 0 || 
					less->y->value_type != 0) {
						printf("Type Mismatch\n");
						return 0;		
					}
				if(less->x->value < less->y->value) {
					less->value = 1;
					less->value_type = 1;
					return 1;
				} else {
					less->value = 0;
					less->value_type = 1;
					return 1;
				} }
		default: return 0;			
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值