任何我们喜欢使用的标记程序的适配器来实现。用这种方法,我们可以把注意力放在程序结构上而不用担心任一特定标记程序的细节。然后我们可以编写一些方法来从这个流中构造 S-expression 表达式。
本质上,这个过程涉及解析流中的第一个 S-expression,然后确定这个 S-expression 之后没有东西了(因为整个程序只是一个大的 S-expression)。对 S-expression 的解析可以递归定义,因为一个复杂 S-expression 的元素自身就是较简单的 S-expression:
清单 4. 解析原始标记流
import java.util.LinkedList;
import java.util.*;
class SExpParseException extends Exception {
public SExpParseException(String msg) {
super(msg);
}
}
interface StackI {
public Object peek();
public Object pop();
public Object push(Object o);
public boolean empty();
}
abstract class SExp {
public static final String LEFT_PAREN = ''(";
public static final String RIGHT_PAREN = ")";
public static SExp parseSExp(StackI tokens) throws SExpParseException {
SExp nextSExp = parseNextSExp(tokens);
if (tokens.empty()) {
// The stack of tokens consisted of a single S-expression
// (with possible subexpressions), as expected.
return nextSExp;
}
else {
throw new SExpParseException("Extraneous material " +
"at end of stream.");
}
}
public static SExp parseNextSExp(StackI tokens) throws SExpParseException {
if (tokens.empty()) {
throw new SExpParseException("Unexpected end of token stream.");
}
else { // tokens.pop() succeeds
Object next = tokens.pop();
if (next.equals(LEFT_PAREN)) {
// The S-expression is a list. Accumulate the subexpressions
// this list contains, and return the result.
SList result = new SEmpty();
while (! tokens.empty()) { // tokens.pop() succeeds
next = tokens.peek();
if (next.equals(RIGHT_PAREN)) {
// We''ve reached the end of the list. We need only
// pop off the ending right parenthesis before returning.
// Since subexpressions were accumulated in the front
// of the list, we must return the reverse of the list
// to reflect the proper structure of the S-expression.
tokens.pop();
return result.reverse();
}
else {
// Recursively parse the next subexpression and
// add it to result.
result = new SCons(parseNextSExp(tokens), result);
}
}
// If we haven''t yet returned, then we''ve reached the end
// of the token stream without finding the matching right
// paren.
throw new SExpParseException("Unmatched left parenthesis.");
}
else if (next.equals(RIGHT_PAREN)) {
// A right parenthesis was encountered at the beginning of
// the S-expression!
throw new SExpParseException("Unmatched right p
|