- import java.util.*;
- import java.io.*;
- //Evaluator class interface: evaluate infix expressions
- //construction:with a string
- //************public operations***************
- //long getValue() -->return value of infix expression
- //*********************************************
- //
- public class Evaluator {
- /**made by Mark Allen Weiss
- * revise @blacksapper
- */
- //不是显式输出表达式.而是把他们送到后缀机
- private static final int EOL=0;
- private static final int VALUE=1;
- private static final int OPAREN=2;
- private static final int CPAREN=3;
- private static final int EXP=4;
- private static final int MULT=5;
- private static final int DIV=6;
- private static final int PLUS=7;
- private static final int MINUS=8;
- private static final int MOD=9;
- private static final int C=10;//排列
- private static final int P=11;//组合
- private static final int GCD=12;//欧几里得运算.最大公约数
- //part A
- private static class Precedence
- {/*程序7-16*/
- public int inputSymbol;
- public int topOfStack;
- public Precedence(int inSymbol ,int topSymbol)
- {
- inputSymbol=inSymbol;
- topOfStack=topSymbol;
- }
- }
- //preTable matches order of token enumeration
- //用于计算中缀表达式的优先级表
- //用于计算栈顶哪些符号应该弹出
- //左结合的运算符在栈中级别比外面高1右接合的比外面的小1.
- private static Precedence[] precTable=
- {
- new Precedence(0 , -1),//EOL
- new Precedence(0 , 0),//VALUE
- new Precedence(100, 0),//OPAREN
- new Precedence(0 , 99),//CPAREN
- new Precedence(10 , 9),//EXP
- new Precedence(5 , 6),//MULT
- new Precedence(5 , 6),//DIV
- new Precedence(1 , 2),//PLUS
- new Precedence(1 , 2), //MINUS
- new Precedence(5 , 6),//MOD
- new Precedence(11 , 12),//排列
- new Precedence(11 , 12),//组合
- new Precedence(7 , 8)//GCD要重新改写优先级了.欧几里得运算
- //part B
- };//可能有错
- private static class Token
- {/*程序7-11*/
- public Token()
- {
- this (EOL);
- }
- public Token(int t)
- {
- this(t,0);
- }
- public Token(int t,long v)
- {
- type=t;
- value=v;
- }
- public int getType()
- {
- return type;
- }
- public long getValue()
- {
- return value;
- }
- private int type=EOL;
- private long value=0;
- }
- private static class EvalTokenizer
- {/*程序7-11*/
- public EvalTokenizer(StringTokenizer is)
- {str=is;}
- /**得到标记序列,并知道它读入的值是什么
- * find the next token,skipping blacks,and return it.
- * for value token,place the process value in currentValue
- * print error message if input is unrecognized
- * 输入的没定义则抛出异常为没定义.
- */
- public Token getToken()
- {/*程序清单7-12*/
- long theValue;
- if(!str.hasMoreTokens())
- return new Token();
- //PART C
- String s = str.nextToken();
- if(s.equals(""))return getToken();
- if(s.equals("^"))return new Token(EXP);
- if(s.equals("/"))return new Token(DIV);
- if(s.equals("*"))return new Token(MULT);
- if(s.equals("("))return new Token(OPAREN);
- if(s.equals(")"))return new Token(CPAREN);
- if(s.equals("+"))return new Token(PLUS);
- if(s.equals("-"))return new Token(MINUS);
- if(s.equals("%"))return new Token(MOD);
- if(s.equals("P"))return new Token(P);
- if(s.equals("C"))return new Token(C);
- if(s.equals("G"))return new Token(GCD);
- try
- {theValue=Long.parseLong(s);}
- catch(NumberFormatException e)
- {
- System.err.println("Parse error");
- return new Token();
- }
- return new Token(VALUE,theValue);
- }
- private StringTokenizer str;
- }
- public Evaluator (String s)
- {
- opStack=new Stack<Integer>();opStack.push(EOL);
- postfixStack=new Stack<Long>();
- str=new StringTokenizer(s,"+*-/^()%PCG",true);
- //PART D }
- public long getValue()
- {/*程序清单7-13*/
- /**
- * 重复读取一个标记并处理之.
- */
- EvalTokenizer tok=new EvalTokenizer(str);
- Token lastToken;
- do{
- lastToken=tok.getToken();
- processToken(lastToken);
- }while(lastToken.getType()!=EOL);
- if(postfixStack.isEmpty())
- {
- System.err.println("Missing operand!");
- return 0;
- }
- long theResult=postfixStack.pop();
- if(!postfixStack.isEmpty())
- {System.err.println("Warning:missing operators!");}
- return theResult;
- }
- private Stack<Integer> opStack; //Operator stack for conversion
- private Stack<Long> postfixStack; //Stack for postfix machine
- private StringTokenizer str; //StringTokenizer stream
- /**
- * after a token is read,use operator precedence parsing
- * are detected here
- * 用来遍历输入行
- */
- private void processToken(Token lastToken)
- {/*程序清单7-17*/
- /**
- * 遇到运算符就放到后缀栈中.如果遇到右括号就重复计算栈中的项直到遇到左括号为止
- * 否则就是处理一般运算符
- */
- int topOp;
- int lastType=lastToken.getType();
- switch(lastType)
- {
- case VALUE:
- postfixStack.push(lastToken.getValue());
- return;
- case CPAREN:
- while((topOp=opStack.peek())!=OPAREN&&topOp!=EOL)
- binaryOp(topOp);
- if(topOp==OPAREN)
- opStack.pop();//get rid of opening parentheseis
- break;
- default:
- while(precTable[lastType].inputSymbol<=
- precTable[topOp=opStack.peek()].topOfStack)
- binaryOp(topOp);
- if(lastType!=EOL)
- opStack.push(lastType);
- break;
- }
- }
- private long postfixpop() //getTop()
- {/*程序清单7-14*/
- /**
- * 后缀机栈的弹出.必要时候抛出异常.
- */
- if(postfixStack.isEmpty())
- {
- System.err.println("Missing operand");
- return 0;
- }
- return postfixStack.pop();
- }
- //重写的方法
- PART E
- private static long pow( long x, long n )
- {
- /**
- * pow in long
- */
- if( x == 0 )
- {
- if( n == 0 )
- System.err.println( "0^0 is undefined" );
- return 0;
- }
- if( n < 0 )
- {
- System.err.println( "Negative exponent" );
- return 0;
- }
- if( n == 0 )
- return 1;
- if( n % 2 == 0 )
- return pow( x * x, n / 2 );
- else
- return x * pow( x, n - 1 );
- }
- private static long pailie(long lhs, long rhs) {
- long lhs1;
- if(lhs==rhs)
- return 1;
- else
- {
- lhs1=lhs-1;
- }
- return lhs*pailie(lhs1,rhs);
- }
- private static long zuhe(long lhs, long rhs) {
- long output=0;
- output=pailie(lhs,rhs)/jiecheng(lhs);
- return output;
- }
- private static long jiecheng(long n) {
- if(n==0 || n==1)
- {
- return 1;
- }
- return jiecheng(n-1)*n;
- }
- private static long gcd(long n,long m){
- if(m == 0)
- return n;
- else
- return gcd(m,n%m);
- }
- //end重写的方法结束
- private void binaryOp(int topOp)
- {/*程序清单7-15*/
- /**
- * 运算符栈的栈顶用作后缀机栈的最上面两项.然后用得出结果替换掉它们.也将运算符栈顶弹出
- */ //part F
- if(topOp==OPAREN)
- {
- System.err.println("Unbalanced parentheses");
- opStack.pop();
- return;
- }
- long rhs=postfixpop();
- long lhs=postfixpop();
- if(topOp==EXP)
- postfixStack.push(pow(lhs,rhs));
- else if(topOp==MOD)
- postfixStack.push(lhs%rhs);
- else if(topOp==P)
- {
- if(rhs<lhs)
- {
- postfixStack.push(pailie(lhs,rhs));
- }
- else
- {
- System.err.println("input error");
- postfixStack.push(lhs);
- }
- }
- else if(topOp==GCD)
- {
- if(rhs<lhs)
- {
- postfixStack.push(gcd(lhs,rhs));
- }
- else
- postfixStack.push(gcd(rhs,lhs));
- }
- else if(topOp==C)
- {
- if(rhs<lhs)
- {
- postfixStack.push(zuhe(lhs,rhs));
- }
- else
- {
- System.err.println("input error");
- postfixStack.push(lhs);
- }
- }
- else if(topOp==PLUS)
- postfixStack.push(lhs+rhs);
- else if(topOp==MINUS)
- postfixStack.push(lhs-rhs);
- else if(topOp==MULT)
- postfixStack.push(lhs*rhs);
- else if(topOp==DIV)
- if(rhs!=0)
- postfixStack.push(lhs/rhs);
- else
- {
- System.err.println("Division by zero");
- postfixStack.push(lhs);
- }
- opStack.pop();
- }
- public static void main(String[] args) {
- String str;
- BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
- try{
- System.out.println("Enter expressions,1 per line");
- while((str=in.readLine())!=null)
- {
- System.out.println("Read:"+str);
- Evaluator ev=new Evaluator(str);
- System.out.println(ev.getValue( ));
- System.out.println("Enter next expression");
- }
- }
- catch(IOException e)
- {e.printStackTrace();}
- }
- }
Mark Allen Weiss教授写的算符优先计算器.我拿来山寨了一下.增加了四个运算.%模运算 C排列运算 P组合运算 G求最大公约数运算.
如果想像我一样加入方法.在part ABCDE五个地方加入.
A表示方法. B表示优先级.分别是栈外优先级和栈内优先级.
为什么^的后面的优先级比前面高而其他的一律低.左括号的又不一样呢.运算^的是从右往左运算的而不是从左往右.这个是数学计算的规定.好比 2^2^5=2^32 而不是 4^5 左括号在栈外优先级是很高的.在栈内 (+)当然是先算+了.所以栈内的优先级不最低.
C表示识别的字符的长相分别对应的给定的那个定义的算符.
D规定了运算符长相为合法长相.这个是我破解这个的难点.看出来了也就容易了.我怕规定GCD会引起二义性.就用G运算代替.
E就是重写的方法.以后要写自己加.
F就是规定进栈的运算.教授重写了POW运算.我要算的除了%都重写了方法.
昨天问老师这个怎么弄.怎么加.他说东西都写好了.你为什么还要重写方法?我说Java课设不止是Java课设.以后可能用汇编重写方法.这个是终极目的.
说明书.运算可以再long范围内运算加减乘除乘方排列组合和最大公约数运算.
求最小公倍数运算
7*8/7G8 或者 7*8/8G7
求阶乘运算
nP1
算符优先级
+ = - < * = / = % < G < P = C <( )
P C 的输入只能左边比右边大 ^乘方运算是从右往左其他一概从左往右运算.
这个系统不支持单目运算符和小数运算.如果想用到开方运算就要重写方法用泰勒公式或者麦克劳林公式展开了.