S-expression is a prefix notation invented for and popularized by the programming language Lisp. Your task is to evaluate some simple s-expressions. In this problem, s-expression is defined as:
1. An atom.
A. a nonnegative integer. Its value is the value of the integer.
B. A Boolean value, True or false. Its value is the Boolean value of itself.
C. A variable, consisting of no more than lower case letters, excluding reserved words "if", "let", "true" and "false". Its value is the value of bound to the variable. If the varible is not bound yet, produce an error "unbound Identifier". (see below for details)
2. (f x ...)
A. One of the following 4 forms: (+ x Y) (-X Y) (* x y) (/x y) in which X and Y is both s-expressions.
To evaluate the s-expression, you need to first evaluate x then evaluate Y.
If the value of x or y is not a integer, produce an error "Type mismatch".
If both x and y are integers, their value is the their sum (x+y)/difference (x-y)/product (x*y)/quotient (x/y). The division is the same as the integer division ("/" operator) in c/c++/java/c#, truncated division. If the value of y is zero, produce a error: "Division by Zero".
B. (if a B c) in which a, B and C is s-expressions.
To evaluate the s-expression, you need to evaluate a at first.
If the value of a is not a Boolean value, produce an error: "Type mismatch".
If the value of a is true, evaluate B and the s-expression ' S value are the value of B.
If the value of a is false, evaluate C and the S-expression ' S value are the value of C.
Note that B or C is not being evaluated during the calculation.
C. (Let (x a) b) in which x are a variable consisting of no more than lower case letters, excluding reserved words " If "," let "," true "and" false ", A and B is s-expressions.
To evaluate the s-expression, you need to first evaluate a.
Then bind the value of a to the variable x and evaluate B. Binding means if variable x appears in B, it value is the Valu E of A. The S-expression ' S value is the value of B.
Note that if X is bound to another value in B, the outer binding is ineffective. For example the value of a (Let (x 1) (Let (x 2) x)) is 2.
D. One of the following 3 forms: (< x y) (> x y) (= x y) in which x and Y is s-expressions.
To evaluate the s-expression, you need to first evaluate x then evaluate Y.
If the value of x or y is not a integer, produce an error "Type mismatch".
If both x and y are integers, their value is a Boolean value indicating whether x < Y, x > y or x = y is true.
Given an s-expression, and output its value. If An error occurs stop the evaluation and output the error.
Input Description:
The first line contains an integer t (1 <= t <=), the number of testcases.
The following T lines each contain a s-expression consisting of no more than, characters.
It is guaranteed input s-expressions does not has any syntax error. The variables, parentheses, integers, true and false are seperated by at least one space.
For 100% of the data, the integers in the whole evaluation would not exceed 32bit signed integers.
Output Description:
For each testcase output the value of the s-expression or one of the three errors "division by Zero", "Type mismatch" and "Unbound Identifier" without quotes.
Input Example:
2
(+ (-3 2) (* 4 5))
(Let (x 4) (if True x y))
Output Example:
4
A lot of pits, big trouble, tinkering before, but the idea is not difficult to think.
The problem has been listed in several cases of s-expression: with keywords, including calculation operations, if, let, true, false, without keywords, including variables (expressed in lowercase letters), 32-bit integers, bool values
To add, the second case of S-expression, F (x ...) can also appear in the ' > ', ' < ', ' = ' operator, which is not described in the topic.
First give a s-expression, the beginning and end of a space, first remove a layer, and then decide which kind of situation
For example, if the keyword "if" is the case: there will be if a B c form, the need to pay special attention to a, B, C are s-expression, also means that the actual occurrence of the formula may be a composite form such as
if (> 3 2) (+ 4 (+ (-3 2) (* 4 5)) 8, a corresponds to (> 3 2), B corresponds (+ 4 (+ (-3 2) (* 4 5)), and C corresponds to 8, which involves a Finding the sub-s-expression is the process of finding a, B, c after the IF keyword, because a, B, C may also be a composite form, this process can use the stack structure to do auxiliary, record ' (' The number, when scanned to empty characters and ' (' The number and ') ' When the number is equal, it means that a complete sub-s-expression has been taken, and the child s-expression can be processed recursively.
The return value uses an array of length 2 to record the state, and the meanings of each state are as follows
Value of retarr[0] |
Meaning of the representative |
-3 |
Unbound Identifier |
-2 |
Division by Zero |
-1 |
Type mismatch |
0 |
The s-expression evaluates to a 32-bit integer |
1 |
The s-expression evaluates to a bool value. |
2 |
S-expression is a variable, the variable has no bound value |
3 |
S-expression is a variable, the variable binding value is a bool variable |
4 |
S-expression is a variable, and the variable binding value is a 32-bit integer |
When the value of Retarr[0] is 0, 1, 2, 3, the value of retarr[1] is meaningful, meaning that it is a specific value
For example, an array of return values (* 4 5) is retarr[0]=0,retarr[1]=20
When the keyword is let, pay special attention to let (x a) B in the form itself contains a pair of parentheses, scan sub-s-expression to separate scan
Other in accordance with the description of the problem to do, arithmetic, relational operations need to detect (F x y) in the X, Y is an integer, if a b c is a bool value, let (x a) B is the x is a variable, there is an illegal situation to return the corresponding error type, there is a compound let statement can be Can make a variable "bind" multiple times, so you need to distinguish between the state "is not a variable cannot be assigned", "is a variable is not assigned", "is the variable has been assigned", multiple bindings do not need to be processed separately, directly according to the rules of the dry description of the iteration can be.
Import java.util.ArrayList;
Import Java.util.HashMap;
Import Java.util.Scanner;
public class Main {hashmap<string, string> HashMap;
public static void Main (string[] args) {main t=new main ();
T.getresult ();
} public void GetResult () {Scanner cin=new Scanner (system.in);
int T=cin.nextint ();
Cin.nextline ();
while (t>0) {String s=cin.nextline ();
Hashmap=new hashmap<> ();
Int[] Ret=valueofexp (S,0,s.length ()-1);
Switch (ret[0]) {case 0:system.out.println (ret[1]);
Break Case 1:system.out.println (ret[1]==1? ")
True ":" false ");
Break
Case-1: System.out.println ("Type mismatch");
Break
Case-2: System.out.println ("Division by Zero");
Break
Case 2:case-3: System.out.println ("unbound Identifier");
Break
Default:break;
} t--;
}} public int[] Valueofexp (String s,int begin,int end) {if (S.charat (begin) = = ' (' &&s.charat (end) = = ') ') {begin+=2;
end-=2;
} arraylist<integer> divideinfo=dividestr (s, begin, end);
Switch (divideinfo.get (0)) {Case 1: {int[] Part1=valueofexp (S,divideinfo.get (1), Divideinfo.get (2));
Int[] Part2=valueofexp (S,divideinfo.get (3), Divideinfo.get (4));
Int[] Part3=valueofexp (S,divideinfo.get (5), Divideinfo.get (6)); if (! ( part1[0]==1| |
part1[0]==3)) return new int[] { -1,0};
else {return part1[1]==1?part2:part3;
}} Case 2: {int[] Part1=valueofexp (S,divideinfo.get (1), Divideinfo.get (2));
Int[] Part2=valueofexp (S,divideinfo.get (3), Divideinfo.get (4));
if (PART1[0]<2) return new int[]{-1,0};
String word=s.substring (Divideinfo.get (1), Divideinfo.get (2) +1); if (part2[0]==1| | part2[0]==3) hashmap.put (Word, part2[1]==1? ")
True ":" false "); else if (part2[0]==0| |
part2[0]==4) {hashmap.put (Word, string.valueof (part2[1]));
} int[] Part3=valueofexp (S,divideinfo.get (5), Divideinfo.get (6)); if (part3[0]==2) return new int[]{-3,0};
if (part3[0]==3) return new Int[]{1, (part3[1]==1?1:0)};
else if (part3[0]==4) return new Int[]{0,part3[1]};
else {return part3;
}} case 3:return new int[]{1,1};
Case 4:return New int[]{1,0};
Case 5: {int[] Part1=valueofexp (S,divideinfo.get (1), Divideinfo.get (2));
Int[] Part2=valueofexp (S,divideinfo.get (3), Divideinfo.get (4)); if (! ( (part1[0]==0| | part1[0]==4) && (part2[0]==0| |
part2[0]==4))) return new int[]{-1,0};
Char Op=s.charat (BEGIN);
Int[] Retarr=new int[2];
retarr[0]=0;
Switch (OP) {case ' + ': retarr[1]=part1[1]+part2[1];
Break
Case '-': retarr[1]=part1[1]-part2[1];
Break
Case ' * ': retarr[1]=part1[1]*part2[1];
Break
Case '/': if (part2[1]==0) {retarr[0]=-2;
retarr[1]=0;
} else {retarr[1]=part1[1]/part2[1];
} break;
Case ' > ': retarr[0]=1;
retarr[1]=part1[1]>part2[1]?1:0;
Break Case ' < ': retarr[0]=1;
retarr[1]=part1[1]<part2[1]?1:0;
Break
Case ' = ': retarr[0]=1;
retarr[1]=part1[1]==part2[1]?1:0;
Break
Default:break;
} return Retarr;
} Case 6: {String word=s.substring (begin, End+1);
if (Hashmap.containskey (word)) {String val=hashmap.get (word);
if (Val.compareto ("true") ==0) return new int[] {3,1};
else if (Val.compareto ("false") ==0) return new int[] {3,0};
return new int[] {4,integer.valueof (val)};
} char Firstchar=word.charat (0);
if (firstchar>= ' 0 ' &&firstchar<= ' 9 ') return new int[]{0,integer.valueof (word)};
return new int[]{2,0};
} Default:return new int[]{-4,0};
}} public arraylist<integer> dividestr (String s, int begin,int end) {StringBuilder sb=new StringBuilder ();
int i=begin;
for (; i<=end;i++) if (S.charat (i)! = ") Sb.append (S.charat (i));
else {break;
} String word=sb.tostring (); ArraylisT<integer> arraylist=new arraylist<> ();
if (Word.compareto ("if") ==0) {Arraylist.add (1);
Findkexp (S, i+1, End, 3, ArrayList);
} else if (Word.compareto ("let") ==0) {Arraylist.add (2);
int leftcount=1;
int leftindex=i+1;
int rightindex=i+1;
for (; i<=end;i++) if (S.charat (i) = = ') ') if (--leftcount==0) {rightindex=i;
Break
} findkexp (S, leftindex+2, Rightindex-2, 2, ArrayList);
Findkexp (S, rightindex+2, end, 1, ArrayList);
} else if (Word.compareto ("true") ==0) {Arraylist.add (3);
} else if (Word.compareto ("false") ==0) {Arraylist.add (4); } else if (Word.compareto ("+") ==0| | Word.compareto ("-") ==0| | Word.compareto ("*") ==0| | Word.compareto ("/") ==0| | Word.compareto (">") ==0| | Word.compareto ("<") ==0| |
Word.compareto ("=") ==0) {Arraylist.add (5);
Findkexp (S, i+1, end, 2, ArrayList);
} else {Arraylist.add (6);
} return ArrayList; } public void Findkexp (String s,int begin,int ENd,int k,arraylist<integer> ArrayList) {int leftcount=0;
int pre=begin-1;
int cur=begin;
int cnt=0;
while (cnt<k&&cur<=end) {char c=s.charat (cur);
if (c== ' (') leftcount++;
else if (c== ') ') leftcount--;
else if (c== ' &&leftcount==0) {arraylist.add (pre+1);
Arraylist.add (CUR-1);
Pre=cur;
cnt++;
} cur++;
} arraylist.add (pre+1);
Arraylist.add (CUR-1);
}
}