//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
// PLEASE DO NOT EDIT WITHOUT THE EXPLICIT CONSENT OF THE AUTHOR! \\
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
using System.Text;
using System.Collections;
using Ilog.Language.Util;
namespace Ilog.Language.Syntax
{
/**
* This class is an abstract representation of the type of tokens
* that are dynamic operators, whether Operator (used use
* by the grammar at parser construction time), or ParserOperator
* (used by the parser at parse time).
*
* @see Symbol
* @see Operator
* @see Parsing.Operator
*
* @version Last modified on Tue May 31 13:50:22 2005 by hak
* @author Hassan Aït-Kaci
* @copyright © 2000 ILOG, S.A.
*/
public abstract class OperatorSymbol : Symbol
{
/**
* Constructs an operator symbol with the specified name,
* reference list, precedence, and specifier.
*/
public OperatorSymbol (string name, ArrayList list,
int precedence, string specifier)
// throws NonFatalParseErrorException
: base(name,list)
{
this.precedence = precedence;
Decode(specifier);
}
/**
* Constructs an operator symbol with the specified name,
* reference list, precedence, associativity, and fixity.
*/
public OperatorSymbol (string name, ArrayList list,
int precedence, int associativity, int fixity)
: base(name,list)
{
this.precedence = precedence;
this.associativity = associativity;
this.fixity = fixity;
}
/** Constant denoting an operator quality of being prefix. */
public const int PREFIX = 0;
/** Constant denoting an operator quality of being postfix. */
public const int POSTFIX = 1;
/** Constant denoting an operator quality of being infix. */
public const int INFIX = 2;
/** This operator symbol's nonterminal category name. */
public abstract string CategoryName { get; }
/** This operator symbol's precedence. */
protected int precedence;
public int Precedence
{
get { return precedence; }
}
/** This operator symbol's associativity. */
protected int associativity;
public int Associativity
{
get { return associativity; }
}
/** This operator symbol's fixity. */
protected int fixity;
public int Fixity
{
get { return fixity; }
}
/** This operator symbol's associativity/fixity specifier. */
public string Specifier
{
get
{
StringBuilder s = new StringBuilder();
if (associativity == Grammar.LEFT_ASSOCIATIVE)
s.Append("y");
else
if (fixity != PREFIX)
s.Append("x");
s.Append("f");
if (associativity == Grammar.RIGHT_ASSOCIATIVE)
s.Append("y");
else
if (fixity != POSTFIX)
s.Append("x");
return s.ToString();
}
}
/**
* Changes the definition of this operator symbol with
* the specified precedence and specifier.
*/
public void Redefine (int precedence, string specifier)
// throws NonFatalParseErrorException
{
this.precedence = precedence;
Decode(specifier);
}
/**
* Throws a NonFatalParseErrorException reporting the specified
* specifier as bad.
*/
private void Bad (string specifier) // throws NonFatalParseErrorException
{
throw new NonFatalParseErrorException
("Bad dynamic operator specifier ("+specifier+")");
}
/**
* Decodes and interprets the contents of a Prolog-style operator
* specifier string.
*/
private void Decode (string specifier) // throws NonFatalParseErrorException
{
if (specifier.Length == 2)
{
if (specifier.IndexOf('f') == 0)
{
fixity = PREFIX;
if (specifier[1] == 'y')
{
associativity = Grammar.RIGHT_ASSOCIATIVE;
return;
}
if (specifier[1] == 'x')
{
associativity = Grammar.NON_ASSOCIATIVE;
return;
}
Bad(specifier);
}
if (specifier.IndexOf('f') == 1)
{
fixity = POSTFIX;
if (specifier[0] == 'y')
{
associativity = Grammar.LEFT_ASSOCIATIVE;
return;
}
if (specifier[0] == 'x')
{
associativity = Grammar.NON_ASSOCIATIVE;
return;
}
}
Bad(specifier);
}
if (specifier.Length == 3 && specifier.IndexOf('f') == 1)
{
fixity = INFIX;
if (specifier[0] == 'y')
{
if (specifier[2] != 'x')
Bad(specifier);
associativity = Grammar.LEFT_ASSOCIATIVE;
return;
}
if (specifier[0] == 'x')
{
if (specifier[2] == 'y')
associativity = Grammar.RIGHT_ASSOCIATIVE;
else
if (specifier[2] == 'x')
associativity = Grammar.NON_ASSOCIATIVE;
else
Bad(specifier);
return;
}
}
Bad(specifier);
}
/**
* Returns true iff the specified object is an operator symbol
* with identical name, category, and fixity. Note that precedence
* and associativity are transient properties, in that the same
* operator make redefine them without losing its identity.
*/
public override bool Equals (object other)
{
if (this == other)
return true;
if (!(other is OperatorSymbol))
return false;
OperatorSymbol that = (OperatorSymbol)other;
return this.name == that.name
&& this.CategoryName == that.CategoryName
&& this.fixity == that.fixity;
}
/**
* Returns a hash code for this operator symbol.
*/
public override int GetHashCode ()
{
return name.GetHashCode() ^ CategoryName.GetHashCode() ^ fixity;
}
/**
* Returns a string description for this operator sysmbol.
*/
public override string ToString ()
{
return CategoryName
+ "("
+ Grammar.PrologPrecedence(precedence)
+ "," + Specifier
+ "," + name
+ ")";
}
}
}