msv.tahiti.src.com.sun.tahiti.runtime.ll.LLParser Maven / Gradle / Ivy
/*
* @(#)$Id: LLParser.java 1087 2001-08-18 01:37:50Z Bear $
*
* Copyright 2001 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the proprietary information of Sun Microsystems, Inc.
* Use is subject to license terms.
*
*/
package com.sun.tahiti.runtime.ll;
import com.sun.msv.datatype.DatabindableDatatype;
import com.sun.msv.grammar.NameClassAndExpression;
import org.relaxng.datatype.ValidationContext;
import java.util.Vector;
import java.util.Set;
import java.util.Map;
/**
* Generic LL parser.
*
* parses tokens according to the specified LL grammar.
*
* Parser symbols
*
* Terminals
* ---------
* ElementSymbol -- ElementExp
* AttributeSymbol -- AttributeExp
* DataSymbol -- org.relaxng.datatype.DataType
*
* Non-terminals (extends NonTerminalSymbol)
* -----------------------------------------
* ClassSymbol -- ClassSymbol
* NamedSymbol -- NamedSymbol
* IntermediateSymbol -- IntermediateSymbol
*
* ???: It may be possible that we want to have two distinct ClassSymbols whose
* Java type is equal.
*
*
* C = N N
* N = C1
* N = C2
* C1 = $string(maxLength=10)
* C2 = $string(maxLength=12)
*
*
* @author
* Kohsuke KAWAGUCHI
*/
public final class LLParser {
/** logger. */
private static java.io.PrintStream debug = System.out;
/**
* a special symbol that instructs InputReader to remove the last-added filter.
*/
private static final Object removeInterleaveSymbol = new Object();
public interface Receiver {
// // used to kick the production rule which is expanded to an empty sequence.
// // (e.g., A->$epsilon)
// void action() throws Exception;
void start() throws Exception;
void end() throws Exception;
};
public interface FieldReceiver extends Receiver {
void action( Object object, NamedSymbol fieldName ) throws Exception;
}
public interface ObjectReceiver extends Receiver {
void action( Object item ) throws Exception;
}
public interface CharacterReceiver extends Receiver {
void action( DatabindableDatatype datatype, String characterContents, ValidationContext context ) throws Exception;
}
/**
* do-nothing receiver.
*
* This object is used as an action of IgnoreSymbol.
*/
public static final Receiver ignoreReceiver = new CharacterReceiver() {
public void start() {}
public void end() {}
// IgnoreSymbol can be expanded to DataPacket. That is, there are rules
// like "Ignore1->Dstring". So ignoreReceiver has to implement CharacterReceiver.
public void action( DatabindableDatatype datatype, String characterContents, ValidationContext context ) {}
};
class StackItem {// must be immutable
/** previous StackItem. StackItems form a stack by using this field. */
public final StackItem previous;
/**
* actual payload.
* Usually, this is either a terminal symbol or a non-terminal symbol.
*
* Sometimes, this payload is used for out-of-band transmission
* by storing a special token.
*/
public final Object symbol;
/** This object receives the payload of the matched input token. */
public final Receiver receiver;
public StackItem( Object symbol, Receiver receiver ) {
this.symbol=symbol; this.receiver=receiver;
this.previous=stackTop;
}
}
/** ???̓g?[?N???? */
Packet[] inputs;
/** ?g?[?N???ǂݎ??? */
class InputReader {
InputReader(Packet[] attributes,int len) {
this.used = new boolean[inputs.length];
this.attributes = new Packet[len];
System.arraycopy(attributes,0,this.attributes,0,len);
this.attLen = len;
this.base = this.idx = 0;
}
private boolean[] used; // ??????g?[?N????true?ɂȂ??Ă???
private int base; // ?܂????????g?[?N???̐擪?ʒu
private int idx; // ???݂̃g?[?N???ʒu
public int getCurrentIndex() { return idx; }
// ?t?B???^?????????Ă???ƁA???҂??H???Ⴄ???Ƃ?????
public Packet[] attributes; // unconsumed attributes
public int attLen; // length of attributes.
private final class FilterChain {
// must be immutable because of the backtracking
final Filter filter;
final FilterChain previous;
FilterChain( Filter filter, FilterChain previous ) {
this.previous = previous;
this.filter = filter;
}
boolean rejects( Object sym ) {
for( FilterChain f = this; f!=null; f=f.previous )
if(f.filter.rejects(sym)) return true;
return false;
}
}
/** filters that are currently active. */
private FilterChain filter = null;
/** gets the current token. */
public Packet current() {
if(idx==inputs.length) return null; // no more token
return inputs[idx];
}
/** consumes a token and returns a new token. */
public Packet consume() {
used[idx++] = true;
skipFilteredToken();
return current();
}
/** skips currently filtered tokens and find an available one. */
private void skipFilteredToken() {
// look for an unused token.
while( idx Action map
// the result of unmarshalling is stored to this root object.
final Packet.ItemPacket root = new Packet.ItemPacket(startSymbol);
final StackItem startRule = new StackItem(startSymbol,root);
stackTop = startRule;
LLparser:
while(true) {
Packet current = reader.current();
if( stackTop==null ) {
if( reader.attLen!=0 || current!=null ) {
if(debug!=null) {
debug.println("stack is empty but there are unconsumed tokens");
if(reader.attLen!=0)
debug.println("attribute is left");
if(current!=null)
debug.println("input token "+symbolToStr(current)+" is left");
}
// unconsumed attributes are left, or
// unconsumed tokens are left.
// That means we have to back track.
doBackTrack();
continue;
}
break; // LR parser accepts the input
}
if( stackTop.symbol==removeInterleaveSymbol ) {
if(debug!=null)
debug.println("removing an interleave filter");
reader.removeFilter();
popStack();
continue;
}
if( stackTop.symbol instanceof EndNonTerminalAction ) {
addAction( (Action)stackTop.symbol );
popStack();
continue;
}
if( isNonTerminal(stackTop.symbol) || stackTop==startRule) {
// the start rule is either ElementSymbol or AttributeSymbol,
// but it must be considered non-terminals.
// obtain the production rules that are applicable now.
Rule[] rules=null;
Object currentSymbol = (current!=null)?current.symbol:null;
applicableRules.clear();
// usually, it is better to follow the lead of attributes.
for(int i=0; i1 ) {
// we can backtrack to this point later.
// so store necessary information.
for( int j=1/*0 is the applied rule*/; jabc, and manipulate the stack and the tokens accordingly. */
private void applyRule( Rule rule ) {
// since we are trying to expand the non-terminal which is
// currently at the top of the stack,
// the non-terminal of the rule must be equal to the stack top.
// assert( rule.left==stackTop.symbol );
Object left = stackTop.symbol;
// compute the action when this rule is "reduced".
// (when information are propagated from right to left).
// this object will receive the value of the right hand side
Receiver receiver;
if( left instanceof NameClassAndExpression ) {
// LLAttributeExp and LLElementExp are pseudo non-terminals
// and therefore don't have an action.
receiver = stackTop.receiver;
} else {
// other true non-terminals may have their own actions.
assert( isNonTerminal(left) );
receiver = ((NonTerminalSymbol)left).createReceiver(stackTop.receiver);
}
if(debug!=null) {
StringBuffer buf = new StringBuffer();
buf.append("expanding a rule : ");
buf.append( symbolToStr(stackTop.symbol) );
buf.append(" --> ");
for( int i=0; i=0; j-- ) // in the reverse order
stackTop = new StackItem(rule.right[j],receiver);
} else {
// if it's an interleave, push the special token, too.
for( int j=rule.right.length-1; j>=0; j-- ) {
if(j!=rule.right.length-1)
stackTop = new StackItem(removeInterleaveSymbol,null);
stackTop = new StackItem(rule.right[j],receiver);
}
// apply filters. Note that the number of filters are one less than
// the number of right hand side branches because we don't need a filter
// for the first one branch.
for( int j=rule.right.length-2; j>=0; j-- )
reader.applyFilter(rule.filters[j]);
}
}
/**
* checks if a symbol is a non-terminal symbol or not.
*/
private static boolean isNonTerminal( Object symbol ) {
return symbol instanceof NonTerminalSymbol;
}
public static String symbolToStr( Object symbol ) {
if( symbol instanceof NonTerminalSymbol )
return symbol.toString();
if( symbol instanceof com.sun.msv.datatype.xsd.XSDatatype )
return "D<"+((com.sun.msv.datatype.xsd.XSDatatype)symbol).displayName()+">";
if( symbol instanceof DatabindableDatatype )
return "D<"+symbol.getClass().getName()+">";
if( symbol instanceof LLElementExp )
return "E<"+((LLElementExp)symbol).getNameClass()+">";
if( symbol instanceof LLAttributeExp )
return "A<"+((LLAttributeExp)symbol).getNameClass()+">";
if( symbol==null )
return "$$$"; // terminal symbol
throw new Error(symbol.toString());
}
protected static void assert( boolean b ) {
if(!b) throw new Error("asesrtion failed");
}
private void popStack() {
stackTop = stackTop.previous;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy