ACM解题总结——HihoCoder1155

来源:互联网 发布:周易软件研发 编辑:程序博客网 时间:2024/05/06 12:15
题目来源:
    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 integertypedef struct node2 {int type;int value;int value_type;} Integer;// booleantypedef 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 ctypedef struct node9 {int type;int value;int value_type;s_expression *a, *b, *c;} If;// let (x a) btypedef struct node10 {int type;int value;int value_type;s_expression *x, *a, *b;} Let;// < x ytypedef struct node11 {int type;int value;int value_type;s_expression *x, *y;} Greater;// = x ytypedef struct node12 {int type;int value;int value_type;s_expression *x, *y;} Equal;// < x ytypedef 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 yif(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 yif(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 yif(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 yif(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 cif(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 ) bif(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 yif(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 yif(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 yif(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;}


0 0
原创粉丝点击