/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * This file is part of Beaver Parser Generator.                       *
 * Copyright (C) 2003,2004 Alexander Demenchuk <alder@softanvil.com>.  *
 * All rights reserved.                                                *
 * See the file "LICENSE" for the terms and conditions for copying,    *
 * distribution and modification of Beaver.                            *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

package beaver;

/**
 * Represents a symbol of a grammar.
 */
public class Symbol implements Cloneable
{
	static private final int COLUMN_FIELD_BITS = 12;
	static private final int COLUMN_FIELD_MASK = (1 << COLUMN_FIELD_BITS) - 1; 
	
	/**
	 * Packs symbol "coordinates" into a single number.
	 */
	static public int makePosition(int line, int column)
	{
		return line << COLUMN_FIELD_BITS | column;
	}
	
	/**
	 * Extracts line number from a packed position.
	 */
	static public int getLine(int position)
	{
		return position >>> COLUMN_FIELD_BITS;
	}
	
	/**
	 * Extracts column number from a packed position.
	 */
	static public int getColumn(int position)
	{
		return position & COLUMN_FIELD_MASK;
	}
	
	/**
	 * Value assigned to this symbol. 
	 */
	public Object value;

	/** 
	 * Numeric symbol ID. 
	 */
	protected short id;
	
	/**
	 * Line and column where this symbol begins.
	 */
	protected int start;
	
	/**
	 * Line and column where this symbol ends.
	 */
	protected int end;
	
	public Symbol(short id)
	{
		this.id = id;
		this.value = null;
	}

	public Symbol(short id, Object value)
	{
		this.id    = id;
		this.value = value;
	}

	public Symbol(short id, int start, int end)
	{
		this.id    = id;
		this.value = null;
		this.start = start;
		this.end   = end;
	}

	public Symbol(short id, int left, int right, Object value)
	{
		this.id    = id;
		this.value = value;
		this.start = left;
		this.end   = right;
	}

	public Symbol(short id, int start_line, int start_column, int length)
	{
		this.id    = id;
		this.value = null;
		this.start = makePosition(start_line, start_column);
		this.end   = makePosition(start_line, start_column + length - 1);
	}

	public Symbol(short id, int start_line, int start_column, int length, Object value)
	{
		this.id    = id;
		this.value = value;
		this.start = makePosition(start_line, start_column);
		this.end   = makePosition(start_line, start_column + length - 1);
	}
	
	/**
	 * Creates Symbol for non-symbolic results of action routines
	 * 
	 * @param value attached Symbol's value
	 */
	public Symbol(Object value)
	{
		this.value = value;
	}

	/**
	 * Special case constructor that allows creation of explicitly Symbol-ized nonterminals.
	 * <p/>
	 * Used by classes descending from Symbol and which instances are returned by reduce actions.
	 * In this case ID and symbol position will be assigned by the parser when reduce action
	 * code returns this symbol.
	 */
	protected Symbol()
	{
		this.value = this;
	}
	
	/**
	 * Returns an ID of this symbol.
	 * <p/>
	 * This ID typically is, depending on a symbol type, either a terminal ID if a Symbol is a token
	 * created and returned by a Scanner, or a nonterminal ID if a symbol was created by parser based
	 * on that nonterminal definition. In the former case the ID is one of IDs generated by Beaver
	 * for terminal symbols. The latter keeps IDs of nonterminal symbols.
	 * 
	 * @return symbol's ID
	 */
	public short getId()
	{
		return id;
	}

	/**
	 * Returns a position in a source where this symbol starts.
	 *
	 * @return packed line and column numbers
	 */
	public int getStart()
	{
		return start;
	}

	/**
	 * Returns a position in a source where this symbol ends.
	 * 
	 * @return packed line and column numbers
	 */
	public int getEnd()
	{
		return end;
	}

	public Symbol clone() throws CloneNotSupportedException {
		Symbol copy = (Symbol) super.clone();
		copy.value = copy;
		return copy;
	}
}
