import java.io.*;
/**
*这个模板包含一个可以使用变量的递归下降解析器
*它继承了ParserV1,重写了几乎所有的方法
*说实在的,我自己都有些后悔使用继承,因为感觉并没有减少编写的代码量
*另外,本解析器仅支持单字母变量,以后有时间,可能会改写为多字母吧
*牟勇:2006年8月27日
*/
public class ParserV2 extends ParserV1{
//一个为变量准备的数组,装变量的值
private double vars[]=new double[26];
//返回一个变量的值
private double findVar(String vname) throws ParserException{
System.out.println("V2:findVar:"+token+":"+tokType);
if(!Character.isLetter(vname.charAt(0))){
handleErr(SYNTAX);
return 0.0;
}
return vars[Character.toUpperCase(vname.charAt(0))-'A'];
}
//获得一个变量或数字的值
protected double atom() throws ParserException{
double result=0.0;
System.out.println("V2:atom:"+token+":"+tokType);
switch(tokType){
case NUMBER:
try{
result=Double.parseDouble(token);
}catch(NumberFormatException exc){
handleErr(SYNTAX);
}
getToken();
break;
case VARIABLE:
result=findVar(token);
getToken();
break;
default:
handleErr(SYNTAX);
break;
}
return result;
}
//处理变量赋值
private double evalExp1() throws ParserException{
double result;
int varIdx;
int ttokType;
String temptoken;
System.out.println("V2:Exp1:"+token+":"+tokType);
if(tokType==VARIABLE){//如果标记是一个变量
//保存旧的标记
temptoken=new String(token);
ttokType=tokType;
//计算变量的下标
varIdx=Character.toUpperCase(token.charAt(0))-'A';
getToken();//取下一个标记
if(!token.equals("=")){//如果下一个标记不是赋值号
putBack();//返回当前标记
//恢复原标记
token=new String(temptoken);
tokType=ttokType;
}else{//如果是赋值号
getToken();//获取表达式的下一个部分
result=evalExp2();
vars[varIdx]=result;
return result;
}
}
return evalExp2();
}
//回溯到上一个标记
private void putBack(){
if(token==EOE){
return;
}
for(int i=0;i<token.length();i++){
expIdx--;
}
}
//解析器入口点
public double evaluate(String expstr) throws ParserException
{
double result;
exp=expstr;
expIdx=0;
getToken();
if(token.equals(EOE)){
handleErr(NOEXP);//抛出无表达式异常
}
//解析与计算表达式
result=evalExp1();
if(!token.equals(EOE)){//最后一个标记必须是EOE
handleErr(SYNTAX);
}
return result;
}
//处理加减项
protected double evalExp2() throws ParserException{
char op;
double result;
double partialResult;
result=evalExp3();
while((op=token.charAt(0))=='+' ||op=='-'){
getToken();
partialResult=evalExp3();
switch(op){
case '-':
result=result-partialResult;
break;
case '+':
result=result+partialResult;
break;
}
}
return result;
}
//乘或除两个因素
protected double evalExp3() throws ParserException{
char op;
double result;
double partialResult;
result=evalExp4();
while((op=token.charAt(0))=='*' || op=='/' || op=='%'){
getToken();
partialResult=evalExp4();
switch(op){
case '*':
result=result*partialResult;
break;
case '/':
if(partialResult==0.0)
handleErr(DIVBYZERO);
result=result/partialResult;
break;
case '%':
if(partialResult==0.0)
handleErr(DIVBYZERO);
result=result%partialResult;
break;
}
}
return result;
}
//处理幂
private double evalExp4() throws ParserException{
double result;
double partialResult;
double ex;
int t;
result=evalExp5();
if(token.equals("^")){
getToken();
partialResult=evalExp4();
ex=result;
if(partialResult==0.0){
result=1.0;
}else{
for(t=(int)partialResult-1;t>0;t--){
result=result*ex;
}
}
}
return result;
}
//计算一元+或-(即正负号)
private double evalExp5() throws ParserException{
double result;
String op;
op="";
if((tokType==DELIMITER) && token.equals("+") || token.equals("-")){
op=token;
getToken();
}
result=evalExp6();
if(op.equals("-"))
result=-result;
return result;
}
//处理括号表达式
protected double evalExp6() throws ParserException{
double result;
if(token.equals("(")){
getToken();
result=evalExp2();
if(!token.equals(")"))
{
handleErr(UNBALPARENS);
}
getToken();
}
else{
result=atom();
}
return result;
}
//ParserV2的演示
public static void main(String[] args)throws IOException{
String expr;
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
ParserV2 p=new ParserV2();
System.out.println("Enter an empty expression to stop:");
while(true){
System.out.println("Enter expression:");
expr=br.readLine();
if(expr.equals(""))
{
break;
}
try{
System.out.println("Result: "+p.evaluate(expr));
System.out.println();
}catch(ParserException exc){
System.out.println(exc);
}
}
}
}
发表于 @ 2006年08月29日 15:28:00|评论(loading...)|编辑