Esempio n. 1
0
  /**
   * prune()
   *
   * @return - An abstract syntax tree with less junk in it than the parse tree itself, which
   *     includes ALL Nonterminals.
   *     <p>Gross.
   *     <p>What Nonterminals are "useless" is determined by the String array at the top of
   *     Parser.java
   *     <p>WHAT ALL DOES PRUNE DO: 1. Removes USELESS_TERMINALS from our parse tree 2. Removes
   *     Nonterminals with no children, unless it is a function call with no arguments 3. Remove
   *     Nonterminals with only one child, pass up the child to parent Nonterminal 4. Combines type
   *     and * to make a "pointer type", ex. type: int and punctuation: * get combined to type:int*
   *     5. Reformats VAR-DECs and FUN_DECs from DECs.
   *     <p>Productions to clean up: 1. FUN-DEC - done 2. VAR-DEC - done 3. CALL 4. EXPR? 5. PARAMS
   */
  public ArrayList<Symbol> prune() {

    ArrayList<Symbol> ret = new ArrayList<Symbol>();

    if (this instanceof Terminal) {
      boolean useless = false;
      for (String s : Parser.USELESS_TERMINALS) if (s.equals(data())) useless = true;

      if (useless) return ret;

      Symbol clone = this.copy();

      ret.add(this.copy());
      return ret;
    }

    // Prune our children.
    ArrayList<Symbol> prunedChildren = new ArrayList<Symbol>();
    for (int i = 0; i < children.size(); i++) {
      Symbol child = children.get(i);
      prunedChildren.addAll(child.prune());
    }

    // Combine type and * to make a "pointer type"
    for (int i = 0; i < prunedChildren.size(); i++) {
      Symbol child = prunedChildren.get(i);
      if (child.type().equals("type") && prunedChildren.get(i + 1).data().equals("*")) {
        child.setData(child.data() + "*");
        prunedChildren.remove(i + 1);
      }
    }

    // AD-HOC FIX: try to associate function names/types with a FUN-DEC,
    // rather than dangling as Terminal children inside the DEC node.
    // Also try to make all variable declarations part of a VAR-DEC node.
    // This includes global variable declarations, vardecs within funcs,
    // params, and args. (some of this stuff TODO).
    if (type().equals("DEC")) {

      // At this point remember: all our children are pruned already.
      for (int i = 0; i < prunedChildren.size(); i++) {
        Symbol child = prunedChildren.get(i);
        //
        // CASE 1: DEC --> FUN-DEC
        //
        if (child.type().equals("FUN-DEC")) {
          child.add(0, prunedChildren.remove(i - 2)); // Add the type
          child.add(1, prunedChildren.remove(i - 2)); // Add function name
        }
      }
      for (int i = 0; i < prunedChildren.size(); i++) {
        Symbol child = prunedChildren.get(i);
        //
        // CASE 2: DEC --> type (*) identifier ([ integer ]) ;
        //
        if (type().equals("DEC") && !child.type().equals("FUN-DEC")) {
          Nonterminal varDec = new Nonterminal("VAR-DEC", "VAR-DEC");
          while (prunedChildren.size() > 0) varDec.add(prunedChildren.remove(i));
          prunedChildren.add(varDec);
        }
      }
    }
    // AD-HOC FIX: Move around information in PARAM so that the first
    // child is always the abbreviated type (type including *, if it's
    // there), and the second child is the identifier's name.
    else if (type().equals("PARAM*")) {
      for (int i = 0; i < prunedChildren.size(); i++) {
        Symbol child = prunedChildren.get(i);
        if (child.data().equals("[") || child.data().equals("]")) continue;
        ret.add(prunedChildren.remove(i--)); // This is SUPER jank. Hahahah!
      }
    }
    // AD-HOC FIX: Move around information in CALL so that identifiers
    // appear inside of the CALL node, rather than before.
    else if (type().equals("PRIMARY-EXPR")) {
      for (int i = 0; i < prunedChildren.size(); i++) {
        Symbol child = prunedChildren.get(i);
        if (child.type().equals("identifier")) {
          // Is the next child a CALL?
          if ((i + 1 < prunedChildren.size()) && prunedChildren.get(i + 1).type().equals("CALL")) {
            prunedChildren.get(i + 1).add(0, prunedChildren.remove(i));
          }
        }
      }
    }
    // AD-HOC FIX: Move around information in ARGS so that it more closely
    // resembles the structure of VAR-DEC, FUN-DEC, and PARAMS
    else if (type().equals("ARGS")) {
      for (int i = 0; i < prunedChildren.size(); i++) {
        Symbol child = prunedChildren.get(i);
        if (child.type().equals("POSTFIX-EXPR")) {
          // TODO??
        }
      }
    }
    // AD-HOC FIX: Move around information in EXPR and EXPR* so that it is
    // clearer what assignment operation we're dealing with. Note that by
    // the nature of our grammar, the LHS of the assignop will always be a
    // single node.
    else if (type().equals("EXPR")) {
      if (prunedChildren.size() >= 2 && prunedChildren.get(1).type().equals("ASSIGN-EXPR*")) {
        // Move LHS of EXPR* assignment operation into EXPR*,
        // and give EXPR* a more appropriate name.
        Symbol exprStar = prunedChildren.get(1);
        exprStar.add(0, prunedChildren.remove(0));
        exprStar.setType("ASSIGN-EXPR");
      }
    } else if (type().equals("EXPR*")) {
      setType("ASSIGN-EXPR*"); // I mean, WTF is an EXPR*, anways?
    }

    // Nonterminal with no children = useless, automatically, Unless it's a call to a funtion with
    // no arguments??
    // if ( prunedChildren.size() == 0 )
    if (prunedChildren.size() == 0 && !type().equals("ARGS") && !type().equals("OPTIONAL-EXPR"))
      return ret;

    // If after pruning we have only 1 child, then just pass
    // up the child and omit this node. We want to keep the CALL and ARGS nodes though
    if (prunedChildren.size() == 1
        && !type().equals("ARGS")
        && !type().equals("PARAMS")
        && !type().equals("CALL")
        && !type().equals("FUN-DEC")
        && // Added FUN-DEC here...not sure why this needs to be here, but it fixes things...
        !type().equals("PROGRAM")) {

      return prunedChildren;
    }

    // Check to see if we are useless
    boolean useless = true;
    for (String s : Parser.USEFUL_NONTERMINALS) if (s.equals(type())) useless = false;

    if (useless) {
      return prunedChildren;
    } else {
      Symbol newSym = this.copy();
      newSym.setChildren(prunedChildren);
      ret.add(newSym);
      return ret;
    }
  }