|
向解析器中添加变量
很多应用使用变量存储数据,包括所有的编程语言、大部分的计算器和电子制表软件。上面介绍的第一版本解析器必须添加变量处理的功能才能用于上述应用领域。为此,解析器需要增加以下一些功能。首先,当然需要增加变量。前文已经提到,我们使用从A到Z的26个字母为变量命名。我们存储在Parser类中的一个包含26个元素的双精度数组之中。因此,必须向Parser类中添加下列域:
// Array for variables.
private double vars[] = new double[26];
当Parser对象初始化时,数组中的每个元素都被自动初始化为0。
解析器还需要一个方法来查找指定变量的值。由于变量名由从A到Z的字母组成,因此可以用变量名第一个字母的ASCII值减去A的ASCII值,得到的就是该变量在数组vars中的索引。下面给出的findVar()方法完成了此功能:
// Return the value of a variable.
private double findVar(String vname) throws ParserException
{
if(!Character.isLetter(vname.charAt(0))){
handleErr(SYNTAX);
return 0.0;
}
return vars[Character.toUpperCase(vname.charAt(0))-'A'];
}
分析上述代码可知,虽然findVar()方法接收的参数可以是一个较长的变量名,例如A12或者test,但是只有变量名的第一个字母是有意义的。读者可以试着改变这一特征以适应自己的需求。
另外还必须修改atom()方法以同时具备处理数字和变量的能力。新的版本的代码如下:
// Get the value of a number or variable.
private double atom() throws ParserException
{
double result = 0.0;
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;
}
从技术上讲,这些代码都是解析器为正确处理变量而增加的;然而,还没有办法为这些变量指定一个值。为了给变量赋值,解析器需要处理赋值运算符(即“=”号)的能力。为了实现赋值功能,需要在Parser类中增加另一个方法evalExp1()。增加evalExp1()之后,递归下降的调用链将由这个方法开始。也就是说,现在evaluate()必须调用evalExp1()方法(而不是evalExp2())开始表达式的解析过程方法。evalExp1()方法的代码如下:
// Process an assignment.
private double evalExp1() throws ParserException
{
double result;
int varIdx;
int ttokType;
String temptoken;
if(tokType == VARIABLE) {
// save old token
temptoken = new String(token);
ttokType = tokType;
// Compute the index of the variable.
varIdx = Character.toUpperCase(token.charAt(0)) - 'A';
getToken();
if(!token.equals("=")) {
putBack(); // return current token
// restore old token -- not an assignment
token = new String(temptoken);
tokType = ttokType;
}
else {
getToken(); // get next part of exp
result = evalExp2();
vars[varIdx] = result;
return result;
}
}
return evalExp2();
}
|