001: package fri.patterns.interpreter.parsergenerator.semantics;
002:
003: import java.lang.reflect.*;
004: import java.util.*;
005: import fri.patterns.interpreter.parsergenerator.syntax.Rule;
006: import fri.patterns.interpreter.parsergenerator.Semantic;
007:
008: /**
009: Semantic base class that tries to call methods with the same name as nonterminal
010: on left side of rule. The number of parameters of the method must be the same as
011: the number of symbols on the right side of the rule, all parameters must be of type
012: Object, and the return type must be Object. The method might process the parse
013: results and return an arbitrary Object to be processed by another callback method.
014: The ranges of the currently dispatched rule is available by protected getRanges() method.
015: <p/>
016: Example: Both rules
017: <pre>
018: expression ::= expression "+" term ;
019: expression ::= expression "-" term ;
020: </pre>
021: would be dispatched by
022: <pre>
023: public Object expression(Object expression, Object operator, Object term) {
024: int e = ((Integer) expression).intValue();
025: int t = ((Integer) term).intValue();
026: if (operator.equals("+"))
027: return new Integer(e + t);
028: else
029: if (operator.equals("-"))
030: return new Integer(e - t);
031: else
032: throw new IllegalArgumentException("Unknown operator: "+operator);
033: }
034: </pre>
035:
036: @see fri.patterns.interpreter.parsergenerator.examples.Calculator
037: @author (c) 2000, Fritz Ritzberger
038: */
039:
040: public abstract class ReflectSemantic implements Semantic {
041: private List ranges;
042:
043: /**
044: Tries to find a method with same name as left side of rule and number of arguments
045: as much as elements in inputTokens list. All argument types are Object.
046: @param rule the rule that was recognized by the parser.
047: @param inputTokens all semantic call returns from underlying rules, collected according to current rule.
048: @return object to push on parser value-stack.
049: */
050: public Object doSemantic(Rule rule, List inputTokens, List ranges) {
051: this .ranges = ranges;
052:
053: String nonterminal = rule.getNonterminal();
054:
055: Class[] types = new Class[inputTokens.size()];
056: for (int i = 0; i < types.length; i++)
057: types[i] = Object.class;
058:
059: Method m = null;
060: try {
061: m = getClass().getMethod(nonterminal, types);
062: } catch (Exception e) {
063: //System.err.println("WARNING: method not implemented: "+nonterminal+", input is "+inputTokens);
064: return fallback(rule, inputTokens, ranges);
065: }
066:
067: Object[] args = new Object[inputTokens.size()];
068: inputTokens.toArray(args);
069:
070: if (m != null) {
071: try {
072: m.setAccessible(true); // problem with anonymous inner classes
073: Object o = m.invoke(this , args);
074: return o;
075: } catch (IllegalAccessException e) {
076: e.printStackTrace();
077: } catch (IllegalArgumentException e) {
078: e.printStackTrace();
079: } catch (InvocationTargetException e) {
080: e.printStackTrace();
081: throw new RuntimeException(
082: "ERROR in ReflectSemantic : "
083: + e.getTargetException().toString());
084: }
085: }
086: return null;
087: }
088:
089: /**
090: Fallback semantic handler that is called when no method was found by reflection.
091: This method provides a default List aggregation for left recursive rules.
092: @return first list element if input list has only one element,
093: a List if the passed rule is left recursive,
094: else the unmodified inputTokens list.
095: */
096: protected Object fallback(Rule rule, List inputTokens, List ranges) {
097: if (inputTokens.size() == 1) // push the one object on parser value stack
098: return inputTokens.get(0);
099:
100: // check for loop rule and add 1..n right symbols to first right symbol (List)
101: if (inputTokens.size() >= 2
102: && inputTokens.get(0) instanceof List
103: && rule.getNonterminal().equals(rule.getRightSymbol(0))) {
104: List list = (List) inputTokens.get(0);
105: for (int i = 1; i < inputTokens.size(); i++)
106: list.add(inputTokens.get(i));
107:
108: return list;
109: }
110:
111: return inputTokens;
112: }
113:
114: /** Returns the current Token.Range list of all input tokens. */
115: protected List getRanges() {
116: return ranges;
117: }
118:
119: }
|