001: package fri.patterns.interpreter.parsergenerator.lexer;
002:
003: import java.util.*;
004: import java.io.*;
005: import fri.util.Equals;
006: import fri.patterns.interpreter.parsergenerator.syntax.Rule;
007:
008: /**
009: Container for alternative rules/Consumers.
010: If one of the contained consumers succeeds, the
011: alternative succeeds, else it fails.
012:
013: @author (c) 2002, Fritz Ritzberger
014: */
015:
016: class ConsumerAlternatives extends Consumer {
017: private List alternates = new ArrayList(3);
018: private StrategyFactoryMethod strategyFactoryMethod;
019: private Strategy strategy;
020:
021: /** Create a list of alternative consumers, inserting passed consumer. */
022: ConsumerAlternatives(Consumer alternateConsumer) {
023: addAlternate(alternateConsumer);
024: }
025:
026: /** Add another alternative consumer for same nonterminal. */
027: public void addAlternate(Consumer alternateConsumer) {
028: alternates.add(alternateConsumer);
029: }
030:
031: /**
032: Returns the stored alternative consumers that have the same nonterminal.
033: This is for the Lexer to retrieve alternative consumers and call them
034: explicitely to read input. This must be done to match the longest input.
035: */
036: public List getAlternatives() {
037: return alternates;
038: }
039:
040: /** Tries to match to all alternates. Returns true when at least one succeeds. */
041: boolean matchesRepeatableRule(Rule rule) {
042: for (int i = 0; i < alternates.size(); i++) {
043: Consumer ac = (Consumer) alternates.get(i);
044: if (ac.matchesRepeatableRule(rule))
045: return true;
046: }
047: return false;
048: }
049:
050: /** Returns the common start character if all alternatives have the same, else null. */
051: public Character getStartCharacter() {
052: Character c = null;
053:
054: for (int i = 0; i < alternates.size(); i++) {
055: Consumer cc = (Consumer) alternates.get(i);
056: Character c1 = cc.getStartCharacter();
057:
058: if (i == 0)
059: c = c1;
060: else if (Equals.equals(c, c1) == false)
061: return null;
062: }
063:
064: return c;
065: }
066:
067: /**
068: Returns 1 if start character exists, else the sum of possible start variances of all consumers
069: (silently assuming that they have different character sets).
070: */
071: public int getStartVariance() {
072: if (getStartCharacter() != null)
073: return 1;
074:
075: int v = 0;
076: for (int i = 0; i < alternates.size(); i++)
077: v += ((Consumer) alternates.get(i)).getStartVariance();
078:
079: return v;
080: }
081:
082: /**
083: Returns the maximum fixed length of all alternating consumers.
084: A fixed start sequence ends at the first found character set (like "0..9").
085: <p>
086: Returns the maximum start length of all alternating consumers.
087: A consumer start length ends at the first found repeatable or nullable consumer (like "chars*").
088: */
089: protected int getSomeLength(boolean exploreStartLength,
090: List breakIndicator) {
091: int max = 0;
092: for (int i = 0; i < alternates.size(); i++) {
093: Consumer cc = (Consumer) alternates.get(i);
094: int len = cc.getSomeLength(exploreStartLength,
095: breakIndicator);
096: if (len > max)
097: max = len;
098: }
099: return max;
100: }
101:
102: /**
103: Reads from input by delegating to a Strategy object.
104: @param input Input object where to read from.
105: @return null if no match, else scanned input as a StringBuffer.
106: */
107: protected ResultTree consumeInternal(InputText input)
108: throws IOException {
109: if (strategy == null) { // sort alternatives by their start/fixed length
110: strategy = strategyFactoryMethod != null ? strategyFactoryMethod
111: .newStrategy()
112: : new Strategy();
113:
114: for (int i = 0; i < alternates.size(); i++) {
115: Consumer cc = (Consumer) alternates.get(i);
116: strategy.addTokenConsumer(cc.rule.getNonterminal(), cc);
117: }
118: }
119:
120: Strategy.Item item = strategy
121: .consume(input, input.peek(), null);
122: if (item != null)
123: return item.getResultTree();
124:
125: return null;
126: }
127:
128: /** Returns true if the passed consumer could be concurrent with one of the contained alternatives. */
129: public boolean overlaps(Consumer cc) {
130: for (int i = 0; i < alternates.size(); i++) {
131: Consumer ac = (Consumer) alternates.get(i);
132: if (ac.overlaps(cc))
133: return true;
134: }
135: return false;
136: }
137:
138: /** Returns the base string for toString() method. */
139: protected String toStringBase() {
140: StringBuffer sb = new StringBuffer();
141: listToString(alternates, sb, " | ", false);
142: return sb.toString();
143: }
144:
145: /** Sets the factory for Strategy objects. */
146: public void setStrategyFactoryMethod(
147: StrategyFactoryMethod strategyFactoryMethod) {
148: this .strategyFactoryMethod = strategyFactoryMethod;
149:
150: for (int i = 0; i < alternates.size(); i++) {
151: Consumer c = (Consumer) alternates.get(i);
152: c.setStrategyFactoryMethod(strategyFactoryMethod);
153: }
154: }
155:
156: }
|