All Downloads are FREE. Search and download functionalities are using the official Maven repository.

msv.tahiti.src.com.sun.tahiti.runtime.ll.LLParser Maven / Gradle / Ivy

There is a newer version: 2.3.0
Show newest version
/*
 * @(#)$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<Person>	= N<firstName> N<lastName>
 * N<firstName>	= C<String>1
 * N<lastName>	= C<String>2
 * C<String>1	= $string(maxLength=10)
 * C<String>2	= $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