Package net.sourceforge.chaperon.build

Source Code of net.sourceforge.chaperon.build.ParserAutomatonBuilder

/*
*  Copyright (C) Chaperon. All rights reserved.
*  -------------------------------------------------------------------------
*  This software is published under the terms of the Apache Software License
*  version 1.1, a copy of which has been included  with this distribution in
*  the LICENSE file.
*/

package net.sourceforge.chaperon.build;

import net.sourceforge.chaperon.build.conflict.ConflictList;
import net.sourceforge.chaperon.build.conflict.ReduceReduceConflict;
import net.sourceforge.chaperon.build.conflict.ShiftReduceConflict;
import net.sourceforge.chaperon.common.IntegerSet;
import net.sourceforge.chaperon.model.Violations;
import net.sourceforge.chaperon.model.grammar.Associativity;
import net.sourceforge.chaperon.model.grammar.Error;
import net.sourceforge.chaperon.model.grammar.Grammar;
import net.sourceforge.chaperon.model.symbol.SymbolSet;
import net.sourceforge.chaperon.model.symbol.Terminal;
import net.sourceforge.chaperon.process.ParserAutomaton;

import org.apache.commons.logging.Log;

/**
* This class represents a builder for parser automata.
*
* @author <a href="mailto:stephan@apache.org">Stephan Michels</a>
* @version CVS $Id: ParserAutomatonBuilder.java,v 1.27 2003/12/14 09:48:33 benedikta Exp $
*/
public class ParserAutomatonBuilder
{
  private static final EndOfFile EOF = new EndOfFile();
  private Grammar grammar;
  private SymbolSet tsymbols;
  private SymbolSet ntsymbols;
  private FirstSetCollection firstsets;
  private ItemSetCollection itemsets;
  private ParserAutomaton automaton;
  private ConflictList conflicts = new ConflictList();
  private Log log;

  /**
   * Create a builder for an parser automaton.
   *
   * @param grammar Grammar, which should be used to build the automaton.
   */
  public ParserAutomatonBuilder(Grammar grammar)
  {
    this(grammar, null);
  }

  /**
   * Create a builder for an parser automaton.
   *
   * @param grammar Grammar, which should be used to build the automaton.
   * @param log Log, which should be used.
   */
  public ParserAutomatonBuilder(Grammar grammar, Log log)
  {
    this.grammar = (Grammar)grammar.clone();
    this.log = log;

    Violations violations = grammar.validate();

    if ((violations!=null) && (violations.getViolationCount()>0))
      throw new IllegalArgumentException("Grammar is not valid: "+violations.getViolation(0));

    SymbolSet symbols = grammar.getSymbols();

    tsymbols = symbols.getTerminals();
    ntsymbols = symbols.getNonterminals();

    //long time = System.currentTimeMillis();
    // generate all first sets
    if ((log!=null) && (log.isDebugEnabled()))
      log.debug("Generating first sets");

    firstsets = new FirstSetCollection(grammar, log);
    if ((log!=null) && (log.isDebugEnabled()))
      log.debug(firstsets.toString());

    // calculation of alle states and transitions
    if ((log!=null) && (log.isDebugEnabled()))
      log.debug("Building states and transitions");

    itemsets = new ItemSetCollection(grammar, firstsets, log);
    if ((log!=null) && (log.isDebugEnabled()))
      log.debug(itemsets.toString());

    if ((log!=null) && (log.isDebugEnabled()))
      log.debug("Building parser automaton");

    automaton =
      new ParserAutomaton(tsymbols.getSymbolCount(), ntsymbols.getSymbolCount(),
                          grammar.getProductionCount(), 0, itemsets.getItemSetCount());

    // for alle terminal symbols
    for (int i = 0; i<tsymbols.getSymbolCount(); i++)
      automaton.setTerminal(i, tsymbols.getSymbol(i).getName());

    // for the non terminal symbols
    for (int i = 0; i<ntsymbols.getSymbolCount(); i++)
      automaton.setNonterminal(i, ntsymbols.getSymbol(i).getName());

    // for all productions
    for (int i = 0; i<grammar.getProductionCount(); i++)
    {
      automaton.setProductionSymbol(i, ntsymbols.indexOf(grammar.getProduction(i).getSymbol()));
      automaton.setProductionLength(i, grammar.getProduction(i).getLength());
    }

    // for all itemsets I in itemsets C
    for (int state = 0; state<itemsets.getItemSetCount(); state++)
    {
      ItemSet I = itemsets.getItemSet(state);

      SymbolSet shiftsymbols = I.getShiftSymbols()// Transition symbols for shift actions
      SymbolSet reducesymbols = I.getReduceSymbols()// Lookahead symbols for reduce actions

      for (int symbol = 0; symbol<tsymbols.getSymbolCount(); symbol++)
      {
        IntegerSet reduceproductions = I.getReduceProductions(tsymbols.getSymbol(symbol));
        int productionpriority = -1;
        int highestproduction = -1;
        for (int k = 0; k<reduceproductions.getCount(); k++)
        {
          ReduceReduceConflict reduceconflict = null;

          if (k>0)
          {
            reduceconflict =
              new ReduceReduceConflict(grammar, itemsets, state,
                                       (Terminal)tsymbols.getSymbol(symbol),
                                       reduceproductions.get(k-1), reduceproductions.get(k));

            conflicts.addConflict(reduceconflict);
          }

          if (grammar.getPriority(grammar.getProduction(reduceproductions.get(k)))>productionpriority)
          {
            highestproduction = reduceproductions.get(k);
            productionpriority = grammar.getPriority(grammar.getProduction(highestproduction));

            if ((log!=null) && (reduceconflict!=null))
              log.info(reduceconflict.toString());
          }
          else if (grammar.getPriority(grammar.getProduction(reduceproductions.get(k)))==productionpriority)
          {
            if (log!=null)
              log.warn(reduceconflict.toString());
          }
        }

        if (reduceproductions.getCount()>1)
          if ((log!=null) && (log.isInfoEnabled()))
            log.info("The parser will reduce the production "+
                     grammar.getProduction(highestproduction));

        boolean errorreduce = reducesymbols.contains(Error.instance);

        if (shiftsymbols.contains(tsymbols.getSymbol(symbol)))
        {
          if ((errorreduce) || (reducesymbols.contains(tsymbols.getSymbol(symbol))))
          {
            int tokenpriority = grammar.getPriority((Terminal)tsymbols.getSymbol(symbol));

            ShiftReduceConflict shiftconflict =
              new ShiftReduceConflict(grammar, itemsets, state,
                                      (Terminal)tsymbols.getSymbol(symbol), highestproduction);

            if (tokenpriority>productionpriority)
            {
              automaton.setShiftAction(state, symbol, I.getTransition(tsymbols.getSymbol(symbol)));

              if (log!=null)
              {
                log.info(shiftconflict.toString());
                log.info("The parser will shift");
              }
            }
            else if (tokenpriority<productionpriority)
            {
              automaton.setReduceAction(state, symbol, highestproduction);

              if (log!=null)
              {
                log.info(shiftconflict.toString());
                log.info("The parser will reduce");
              }
            }
            else
            {
              if (log!=null)
                log.warn(shiftconflict.toString());

              Associativity associativity =
                grammar.getAssociativity((Terminal)tsymbols.getSymbol(symbol));
              if (associativity.equals(Associativity.RIGHT))
              {
                // if the terminal has a right associativity
                automaton.setShiftAction(state, symbol, I.getTransition(tsymbols.getSymbol(symbol)));

                if (log!=null)
                  log.warn("The parser will shift");
              }
              else if (associativity.equals(Associativity.LEFT))
              {
                // if the terminal has a left associativity
                automaton.setReduceAction(state, symbol, highestproduction);

                if (log!=null)
                  log.warn("The parser will reduce");
              }
              else
              {
                // SHIFT should be always prefered
                automaton.setShiftAction(state, symbol, I.getTransition(tsymbols.getSymbol(symbol)));

                if (log!=null)
                  log.warn("The parser will shift");
              }
            }
          }
          else
            automaton.setShiftAction(state, symbol, I.getTransition(tsymbols.getSymbol(symbol)));
        }
        else if ((errorreduce) || (reducesymbols.contains(tsymbols.getSymbol(symbol))))
          automaton.setReduceAction(state, symbol, highestproduction);
        else
          for (int i = 0; i<shiftsymbols.getSymbolCount(); i++)
            if (shiftsymbols.getSymbol(i) instanceof Error)
              automaton.setErrorAction(state, symbol, I.getTransition(shiftsymbols.getSymbol(i)));
      }

      // create all actions for the end of file.
      if (reducesymbols.contains(EOF))
      {
        IntegerSet reduceproductions = I.getReduceProductions(EOF);
        int productionpriority = -1;
        int highestproduction = -1;
        for (int k = 0; k<reduceproductions.getCount(); k++)
        {
          if (grammar.getPriority(grammar.getProduction(reduceproductions.get(k)))>productionpriority)
          {
            highestproduction = reduceproductions.get(k);
            productionpriority = grammar.getPriority(grammar.getProduction(highestproduction));
          }
        }

        if ((grammar.getProduction(highestproduction).getSymbol().equals(grammar.getStartSymbol())))
          automaton.setAcceptAction(state, highestproduction);
        else
          automaton.setReduceAction(state, highestproduction);
      }
      else
        for (int i = 0; i<shiftsymbols.getSymbolCount(); i++)
          if (shiftsymbols.getSymbol(i) instanceof Error)
            automaton.setErrorAction(state, I.getTransition(shiftsymbols.getSymbol(i)));

      // create all entries for the goto table
      for (int symbol = 0; symbol<ntsymbols.getSymbolCount(); symbol++)
        if (shiftsymbols.contains(ntsymbols.getSymbol(symbol)))
          automaton.setTransition(state, symbol, I.getTransition(ntsymbols.getSymbol(symbol)));
    }

    if ((log!=null) && (log.isDebugEnabled()))
      log.debug("Parser automaton:\n"+automaton.toString());
  }

  /**
   * Returns the generated parser automaton. If a error occurs the method will return null.
   *
   * @return The parser automaton.
   */
  public ParserAutomaton getParserAutomaton()
  {
    return automaton;
  }
}
TOP

Related Classes of net.sourceforge.chaperon.build.ParserAutomatonBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.