package edu.princeton.toy.lang;
import java.lang.ref.*;
import edu.princeton.toy.*;
/**
* TWord is the primitive value which toy registers and memory can take. TWord is immutable, like
* java.lang.String, which means that classes can return TWords without being concerned with wheter
* or not the recipient will change the value. The immutable feature allows us to keep track of and
* reuse TWord CACHED_REFERENCES to save memory allocation overhead.
*
*
CACHED_REFERENCES of TWord are slightly different than short primitives in that they can take on a
* special value, UNINITIALIZED_VALUE, which is identical to getWord(0) except for two things:
*
- The isInitialized() method returns false in UNINITIALIZED_VALUE but not in getWord(0).
*
- The to_____String() methods will return question marks if the distinguishUninitialized
* argument is true.
*
- Performing arithmatic operations on uninitialized values will cause an exception of the
* family TExceptionType.UNINITIALIZED_FAMILY to be raised.
*
* @author btsang
* @version 7.1
*/
public class TWord
{
/**
* The number of bits a TWord would take.
*/
public static final int BIT_COUNT = 16;
/**
* An array to convert an integer between 0 and 16 to a hexidecimal digit.
*/
public static final char HEX_DIGITS[] =
{
'0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'A', 'B',
'C', 'D', 'E', 'F'
};
/**
* An array to convert an integer between 0 and 256 to a pair of hexidecimal digit.
*/
public static final String HEX_PAIRS[] = new String[256];
private static final Reference CACHED_REFERENCES[] =
new Reference[Short.MAX_VALUE - Short.MIN_VALUE + 1];
/**
* The uninitialized value is identical to getWord(0) with the following exceptions:
* - The isInitialized() method returns false in UNINITIALIZED_VALUE but not in
* getWord(0).
*
- The to_____String() methods will return question marks if the distinguishUninitialized
* argument is true.
*
- Performing arithmatic operations on uninitialized values will cause an exception of the
* family TExceptionType.UNINITIALIZED_FAMILY to be raised.
*/
public static final TWord UNINITIALIZED_VALUE = new TWord();
/**
* The minimum value a TWord can take.
*/
public static final TWord MIN_VALUE = new TWord(Short.MIN_VALUE);
/**
* The maximum value a TWord can take.
*/
public static final TWord MAX_VALUE = new TWord(Short.MAX_VALUE);
/**
* A constant for getWord((short)0).
*/
public static final TWord ZERO = new TWord((short)0);
/**
* A constant for getWord((short)0).
*/
public static final TWord ONE = new TWord((short)1);
private short value;
private boolean isInitialized;
private String binaryString;
private String formattedBinaryString;
private String decimalString;
private String hexString;
private String pseudoCodeString;
private String detailedString;
/**
* Initialize CACHED_REFERENCES[0] and CACHED_REFERENCES[Short.MAX_VALUE - Short.MIN_VALUE],
* since we can't really do that practically in the declaration of the CACHED_REFERENCES.
*/
static
{
CACHED_REFERENCES[0] = new SoftReference(MIN_VALUE);
CACHED_REFERENCES[0 - Short.MIN_VALUE] = new SoftReference(ZERO);
CACHED_REFERENCES[1 - Short.MIN_VALUE] = new SoftReference(ONE);
CACHED_REFERENCES[Short.MAX_VALUE - Short.MIN_VALUE] = new SoftReference(MAX_VALUE);
for (int ctr1 = 0; ctr1 < 16; ctr1++)
{
String firstDigit = String.valueOf(HEX_DIGITS[ctr1]);
for (int ctr2 = 0; ctr2 < 16; ctr2++)
HEX_PAIRS[(ctr1 << 4) | ctr2] = firstDigit + HEX_DIGITS[ctr2];
}
}
/**
* Constructs a TWord with the given value.
*/
private TWord(short value)
{
char op, d, s, t;
op = HEX_DIGITS[(value >> 12) & 0xF];
d = HEX_DIGITS[(value >> 8) & 0xF];
s = HEX_DIGITS[(value >> 4) & 0xF];
t = HEX_DIGITS[(value ) & 0xF];
this.value = value;
isInitialized = true;
// Pre-calculate the representation strings
StringBuffer buffer = new StringBuffer(10 * BIT_COUNT);
for (int ctr = BIT_COUNT - 1; ctr >= 0; ctr--)
{
if (((value >> ctr) & 1) != 0)
buffer.append('1');
else
buffer.append('0');
}
binaryString = buffer.toString();
buffer.delete(0, buffer.length());
for (int ctr = BIT_COUNT - 1; ctr >= 0; ctr--)
{
if (ctr != BIT_COUNT - 1 && ctr % 4 == 3)
buffer.append(' ');
if (((value >> ctr) & 1) != 0)
buffer.append('1');
else
buffer.append('0');
}
formattedBinaryString = buffer.toString();
buffer.delete(0, buffer.length());
decimalString = String.valueOf(value);
for (int ctr = decimalString.length(); ctr < 6; ctr++)
buffer.append(' ');
buffer.append(decimalString);
decimalString = buffer.toString();
buffer.delete(0, buffer.length());
buffer.append(op);
buffer.append(d);
buffer.append(s);
buffer.append(t);
hexString = buffer.toString();
switch (op)
{
case '0':
pseudoCodeString = "halt";
break;
case '1':
if (d == '0')
pseudoCodeString = "no-op";
else if (s == '0' && d == t)
pseudoCodeString = "no-op";
else if (t == '0' && d == s)
pseudoCodeString = "no-op";
else if (s == '0' && t != '0')
pseudoCodeString = "R[" + d + "] <- R[" + t + "]";
else if (s != '0' && t == '0')
pseudoCodeString = "R[" + d + "] <- R[" + s + "]";
else if (s == '0' && t == '0')
pseudoCodeString = "R[" + d + "] <- 0000";
else
pseudoCodeString = "R[" + d + "] <- R[" + s + "] + R[" + t + "]";
break;
case '2':
if (d == '0')
pseudoCodeString = "no-op";
else if (t == '0' && d == s)
pseudoCodeString = "no-op";
else if (s == '0' && t != '0')
pseudoCodeString = "R[" + d + "] <- -R[" + t + "]";
else if (s != '0' && t == '0')
pseudoCodeString = "R[" + d + "] <- R[" + s + "]";
else if (s == '0' && t == '0')
pseudoCodeString = "R[" + d + "] <- 0000";
else
pseudoCodeString = "R[" + d + "] <- R[" + s + "] - R[" + t + "]";
break;
case '3':
if (d == '0')
pseudoCodeString = "no-op";
else if (d == s && s == t)
pseudoCodeString = "no-op";
else if (s == '0' || t == '0')
pseudoCodeString = "R[" + d + "] <- 0000";
else if (s == t)
pseudoCodeString = "R[" + d + "] <- R[" + s + "]";
else
pseudoCodeString = "R[" + d + "] <- R[" + s + "] & R[" + t + "]";
break;
case '4':
if (d == '0')
pseudoCodeString = "no-op";
else if (s == '0' && t != '0')
pseudoCodeString = "R[" + d + "] <- R[" + t + "]";
else if (s != '0' && t == '0')
pseudoCodeString = "R[" + d + "] <- R[" + s + "]";
else if (s == '0' && t == '0')
pseudoCodeString = "R[" + d + "] <- 0000";
else
pseudoCodeString = "R[" + d + "] <- R[" + s + "] ^ R[" + t + "]";
break;
case '5':
if (d == '0')
pseudoCodeString = "no-op";
else if (t == '0' && d == s)
pseudoCodeString = "no-op";
else if (s == '0')
pseudoCodeString = "R[" + d + "] <- 0000";
else if (t == '0')
pseudoCodeString = "R[" + d + "] <- R[" + s + "]";
else
pseudoCodeString = "R[" + d + "] <- R[" + s + "] << R[" + t + "]";
break;
case '6':
if (d == '0')
pseudoCodeString = "no-op";
else if (t == '0' && d == s)
pseudoCodeString = "no-op";
else if (s == '0')
pseudoCodeString = "R[" + d + "] <- 0000";
else if (t == '0')
pseudoCodeString = "R[" + d + "] <- R[" + s + "]";
else
pseudoCodeString = "R[" + d + "] <- R[" + s + "] >> R[" + t + "]";
break;
case '7':
if (d == '0')
pseudoCodeString = "no-op";
else
pseudoCodeString = "R[" + d + "] <- 00" + s + t;
break;
case '8':
if (s == 'F' && t == 'F')
pseudoCodeString = "read R[" + d + "]";
else if (d == '0')
pseudoCodeString = "no-op";
else
pseudoCodeString = "R[" + d + "] <- M[" + s + t + "]";
break;
case '9':
if (s == 'F' && t == 'F')
pseudoCodeString = "write R[" + d + "]";
else
pseudoCodeString = "M[" + s + t + "] <- R[" + d + "]";
break;
case 'A':
if (d == '0')
pseudoCodeString = "no-op";
else
pseudoCodeString = "R[" + d + "] <- M[R[" + t + "]]";
break;
case 'B':
pseudoCodeString = "M[R[" + t + "]] <- R[" + d + "]";
break;
case 'C':
if (d == '0')
pseudoCodeString = "goto " + s + t;
else
pseudoCodeString = "if (R[" + d + "] == 0) goto " + s + t;
break;
case 'D':
if (d == '0')
pseudoCodeString = "no-op";
else
pseudoCodeString = "if (R[" + d + "] > 0) goto " + s + t;
break;
case 'E':
pseudoCodeString = "goto R[" + d + "]";
break;
case 'F':
if (d == '0')
pseudoCodeString = "goto " + s + t;
else
pseudoCodeString = "R[" + d + "] <- PC; goto " + s + t;
break;
default:
throw new RuntimeException();
}
buffer.delete(0, buffer.length());
buffer.append(hexString);
buffer.append(" (");
buffer.append(formattedBinaryString);
buffer.append(", ");
buffer.append(decimalString);
buffer.append(')');
detailedString = buffer.toString();
}
/**
* Constructs an uninitialized TWord.
*/
private TWord()
{
this((short)0);
isInitialized = false;
}
/**
* checks if the given parameter is a valid TOY instruction
*/
public static boolean isCommand(String cmd) {
if (cmd.length() != 8)
return false;
for (int i = 0; i < 8; i++) {
if ((i < 2 || i > 3) &&
(!TWord.isHexDigit(cmd.charAt(i))))
return false;
else if (i == 2 && cmd.charAt(i) != ':')
return false;
else if (i == 3 && cmd.charAt(i) != ' ')
return false;
}
return true;
}
/** takes a line that has an instruction and inserts a comment into the line
* preserving what ever user comments there are. If what follows the instruction
* is a pseudocode string, this pseudocode is replaced with the new one.
*/
public static String commentLine(String line) {
int lineLength = line.length();
// preserve whatever is after the psuedocode (if there is)
int extraStart = 8;
int end = TProgramDocument.COMMENT_COLUMN;
if (end > lineLength)
end = lineLength;
String extra = "";
if (TWord.isPseudoCode(line.substring(8, end))) {
extraStart = end;
}
if (lineLength > extraStart)
extra = line.substring(extraStart, lineLength);
int arrayLength = TProgramDocument.COMMENT_COLUMN - 8;
char array[] = new char[arrayLength];
// Generate PseudoCode
String pseudoCodeString;
// check if this is a constant (memory locations 0 - F)
if (line.charAt(0) == '0' &&
line.charAt(1) >= '0' &&
line.charAt(1) <= 'F') {
pseudoCodeString = "constant 0x" + line.substring(4, 8);
} else {
TWord command = TWord.parseWord(line.substring(4, 8), 16);
pseudoCodeString = command.toPseudoCodeString(false);
}
int pseudoCodeStringLength = pseudoCodeString.length();
pseudoCodeString.getChars(0, pseudoCodeStringLength, array, 3);
array[0] = ' ';
array[1] = ' ';
array[2] = ' ';
// Pad PseudoCode with trailing spaces
for (int ctr = pseudoCodeStringLength + 3; ctr < arrayLength; ctr++) {
array[ctr] = ' ';
}
return line.substring(0, 8) + new String(array) + extra;
}
/**
* Checks if the given string is a valid TOY pseudocode
*/
public static boolean isPseudoCode(String str) {
str = str.trim();
boolean match =
str.matches("constant 0x[0-9A-F][0-9A-F][0-9A-F][0-9A-F]") ||
str.matches("R\\[[0-9A-F]] <- R\\[[0-9A-F]] ([+\\-&^]|<<|>>) R\\[[0-9A-F]]") ||
str.matches("((read)|(write)) R\\[[0-9A-F]]") ||
str.matches("goto [0-9A-F][0-9A-F]") ||
str.matches("R\\[[0-9A-F]] <- PC; goto [0-9A-F][0-9A-F]") ||
str.matches("R\\[[0-9A-F]] <- 00[0-9A-F][0-9A-F]") ||
str.matches("R\\[[0-9A-F]] <- M\\[[0-9A-F][0-9A-F]]") ||
str.matches("M\\[[0-9A-F][0-9A-F]] <- R\\[[0-9A-F]]") ||
str.matches("R\\[[0-9A-F]] <- M\\[R\\[[0-9A-F]]]") ||
str.matches("M\\[R\\[[0-9A-F]]] <- R\\[[0-9A-F]]") ||
str.matches("if \\(R\\[[0-9A-F]] ((==)|>) 0\\) goto [0-9A-F][0-9A-F]") ||
str.matches("goto R\\[[0-9A-F]]") ||
str.matches("R\\[[0-9A-F]] <- R\\[[0-9A-F]]") ||
str.matches("R\\[[0-9A-F]] <- -R\\[[0-9A-F]]") ||
str.equals("halt") || str.equals("no-op");
return match;
}
/**
* Returns wheter or not this word has been defined yet.
*
* @return True iff this word is not UNINITIALIZED_VALUE.
*/
public boolean isInitialized()
{
return isInitialized;
}
/**
* Returns the short primitive to which this TWord corresponds.
*
* @return The value of this TWord. Note that both getWord(0) and UNINITIALIZED_VALUE have the
* same value.
*/
public short getValue()
{
return value;
}
/**
* Returns the leftmost/most-significant four bits of the TWord.
*
* @return (byte)((getValue() >> 12) & 0xF)
*/
public byte getOp()
{
return (byte)((value >> 12) & 0xF);
}
/**
* Returns the second leftmost/most-significant four bits of the TWord.
*
* @return (byte)((getValue() >> 8) & 0xF)
*/
public byte getD()
{
return (byte)((value >> 8) & 0xF);
}
/**
* Returns the third leftmost/most-significant four bits of the TWord.
*
* @return (byte)((getValue() >> 4) & 0xF)
*/
public byte getS()
{
return (byte)((value >> 4) & 0xF);
}
/**
* Returns the rightmost/least-significant four bits of the TWord.
*
* @return (byte)(getValue() & 0xF)
*/
public byte getT()
{
return (byte)((value >> 0) & 0xF);
}
/**
* Returns the initialized equivalent of this word.
*
* @return The initialized equivalent of this word.
*/
public TWord initializedValue()
{
if (!isInitialized)
return ZERO;
else
return this;
}
/**
* Returns the rightmost/least-significant eight bits of the TWord.
*
* @return (short)(getValue() & 0xFF)
*/
public short getImm()
{
return (short)((value >> 0) & 0xFF);
}
/**
* Returns a TWord initialize to the given value.
*
* @param value The value which the TWord should take.
* @return The TWord with the given value. Note that getWord(n).isInitialized() should always
* evaluate to true for any n.
*/
public static TWord getWord(short value)
{
TWord answer = null;
Reference reference = CACHED_REFERENCES[value - Short.MIN_VALUE];
if (reference == null)
{
answer = new TWord(value);
CACHED_REFERENCES[value - Short.MIN_VALUE] = new SoftReference(answer);
}
else {
answer = (TWord)reference.get();
if (answer == null)
{
answer = new TWord(value);
CACHED_REFERENCES[value - Short.MIN_VALUE] = new SoftReference(answer);
}
}
return answer;
}
/**
* Parses a TWord from a string.
*
* @param string The string to parse.
* @param radix The base of the number being parsed (probably 2, 10, or 16).
* @return getWord(Short.parseShort(string, radix)).
*/
public static TWord parseWord(String string, int radix) throws NumberFormatException
{
int n = Integer.parseInt(string, radix);
if ((n & 0xFFFF0000) != 0 && (n & 0xFFFF0000) != 0xFFFF0000)
throw new NumberFormatException();
return getWord((short)n);
}
/**
* Evaluates wheter or not two TWords have the same values. Due to the instance sharing
* properties of TWord, word1.equals(word2) should behave exactly like word1 == word2.
*
* @param obj The object being compared to this TWord.
* @return True iff obj is an instance of TWord with the same initialized state and value as
* this TWord.
*/
public boolean equals(Object obj)
{
if (obj instanceof TWord)
{
return ((TWord)obj).isInitialized == isInitialized &&
((TWord)obj).value == value;
}
else
return false;
}
/**
* Returns the binary representation of this TWord. Eg. "0101101001101100"
*
* @param distinguishUninitialized Wheter or not to return a string of question marks if this
* TWord is UNINITIALIZED_VALUE.
* @return The binary representation of this TWord. Note that the string will be exactly
* 16 characters long and also that the leading zeros will be shown.
*/
public String toBinaryString(boolean distinguishUninitialized)
{
if (isInitialized || !distinguishUninitialized)
return binaryString;
else
return "????????????????";
}
/**
* Returns the formatted binary representation of this TWord in which every four bits are
* separated by a space. Eg. "0101 1010 0110 1100"
*
* @param distinguishUninitialized Wheter or not to return a string of question marks if this
* TWord is UNINITIALIZED_VALUE.
* @return The formatted binary representation of this TWord. Note that the string will be
* exactly 19 characters long and also that the leading zeros will
* be shown.
*/
public String toFormattedBinaryString(boolean distinguishUninitialized)
{
if (isInitialized || !distinguishUninitialized)
return formattedBinaryString;
else
return "???? ???? ???? ????";
}
/**
* Returns the decimal representation of this TWord. Eg. " 23148"
*
* @param distinguishUninitialized Wheter or not to return a string of question marks if this
* TWord is UNINITIALIZED_VALUE.
* @return The decimal representation of this TWord. This string will have exactly 6
* characters; left padding will be done with spaces.
*/
public String toDecimalString(boolean distinguishUninitialized)
{
if (isInitialized || !distinguishUninitialized)
return decimalString;
else
return ("??????");
}
/**
* Returns the hexidecimal representation of this TWord. Eg. "5A6C"
*
* @param distinguishUninitialized Wheter or not to return a string of question marks if this
* TWord is UNINITIALIZED_VALUE.
* @return The decimal representation of this TWord. Note that the string will be exactly
* 4 characters long and also that the leading zeros will be shown.
*/
public String toHexString(boolean distinguishUninitialized)
{
if (isInitialized || !distinguishUninitialized)
return hexString;
else
return "????";
}
/**
* Returns the detailed representation of this TWord. Eg.
* "5A6C (0101 1010 0110 1100, 23148"
*
* @return toString(false);
*/
public String toString()
{
return detailedString;
}
/**
* Returns the detailed representation of this TWord. Eg.
* "5A6C (0101 1010 0110 1100, 23148"
*
* @param distinguishUninitialized Wheter or not to return a string of question marks if this
* TWord is UNINITIALIZED_VALUE.
* @return The detailed representation of this TWord. Note that the string will be exactly
* 33 characters long and also that the leading zeros will be shown.
*/
public String toString(boolean distinguishUninitialized)
{
if (isInitialized || !distinguishUninitialized)
return detailedString;
else
return "???? (Uninitialized Value)";
}
/**
* Returns the pseudo-code form of the TWord. Eg. "R[A] <- R[6] << R[C]"
*
* @param distinguishUninitialized Wheter or not to return "Uninitialized Value" if
* this TWord is UNINITIALIZED_VALUE.
* @return The pesudo-code representation of this TWord. Note that the length of the returned
* string is variable.
*/
public String toPseudoCodeString(boolean distinguishUninitialized)
{
if (isInitialized || !distinguishUninitialized)
return pseudoCodeString;
else
return "Uninitialized Value";
}
/**
* Implements the addition operator for the TWord type. This could result in either a
* TException of type REGISTER_UNINITIALIZED or OVERFLOW.
*
* @param a The left operand.
* @param b The right operand.
* @param exceptionHandler The hander for any exceptional conditions which might be raised. If
* the exceptionHandler is null, all exceptions will be ignored.
* @return a + b.
* @see TExceptionType#REGISTER_UNINITIALIZED
* @see TExceptionType#OVERFLOW
*/
public static TWord add(TWord a, TWord b, TExceptionHandler exceptionHandler) throws TException
{
// We add the values as ints so we can check for overflow
int sum = a.value + b.value;
if ((!a.isInitialized || !b.isInitialized) && exceptionHandler != null)
exceptionHandler.raise(TExceptionType.REGISTER_UNINITIALIZED);
if ((sum < Short.MIN_VALUE || sum > Short.MAX_VALUE) && exceptionHandler != null)
exceptionHandler.raise(TExceptionType.OVERFLOW);
return getWord((short)sum);
}
/**
* Implements the subtraction operator for the TWord type. This could result in either a
* TException of type REGISTER_UNINITIALIZED or OVERFLOW.
*
* @param a The left operand.
* @param b The right operand.
* @param exceptionHandler The hander for any exceptional conditions which might be raised. If
* the exceptionHandler is null, all exceptions will be ignored.
* @return a - b.
* @see TExceptionType#REGISTER_UNINITIALIZED
* @see TExceptionType#OVERFLOW
*/
public static TWord subtract(TWord a, TWord b, TExceptionHandler exceptionHandler)
throws TException
{
if ((!a.isInitialized || !b.isInitialized) && exceptionHandler != null)
exceptionHandler.raise(TExceptionType.REGISTER_UNINITIALIZED);
// We subtract the values as ints so we can check for overflow
int difference = a.value - b.value;
if ((difference < Short.MIN_VALUE || difference > Short.MAX_VALUE) &&
exceptionHandler != null)
exceptionHandler.raise(TExceptionType.OVERFLOW);
return getWord((short)difference);
}
/**
* Implements the bitwise-and operator for the TWord type. This could result in a
* TException of type REGISTER_UNINITIALIZED.
*
* @param a The left operand.
* @param b The right operand.
* @param exceptionHandler The hander for any exceptional conditions which might be raised. If
* the exceptionHandler is null, all exceptions will be ignored.
* @return a & b.
* @see TExceptionType#REGISTER_UNINITIALIZED
* @see TExceptionType#OVERFLOW
*/
public static TWord and(TWord a, TWord b, TExceptionHandler exceptionHandler) throws TException
{
if ((!a.isInitialized() || !b.isInitialized()) && exceptionHandler != null)
exceptionHandler.raise(TExceptionType.REGISTER_UNINITIALIZED);
return getWord((short)(a.getValue() & b.getValue()));
}
/**
* Implements the bitwise-xor operator for the TWord type. This could result in a
* TException of type REGISTER_UNINITIALIZED.
*
* @param a The left operand.
* @param b The right operand.
* @param exceptionHandler The hander for any exceptional conditions which might be raised. If
* the exceptionHandler is null, all exceptions will be ignored.
* @return a ^ b.
* @see TExceptionType#REGISTER_UNINITIALIZED
* @see TExceptionType#OVERFLOW
*/
public static TWord xor(TWord a, TWord b, TExceptionHandler exceptionHandler) throws TException
{
if ((!a.isInitialized() || !b.isInitialized()) && exceptionHandler != null)
exceptionHandler.raise(TExceptionType.REGISTER_UNINITIALIZED);
return getWord((short)(a.getValue() ^ b.getValue()));
}
/**
* Implements the logical-left-shift operator for the TWord type. This could result in either a
* TException of type REGISTER_UNINITIALIZED or SHIFT_OUT_OF_BOUNDS.
*
* @param a The left operand.
* @param b The right operand.
* @param exceptionHandler The hander for any exceptional conditions which might be raised. If
* the exceptionHandler is null, all exceptions will be ignored.
* @return a << b.
* @see TExceptionType#REGISTER_UNINITIALIZED
* @see TExceptionType#SHIFT_OUT_OF_BOUNDS
*/
public static TWord leftShift(TWord a, TWord b, TExceptionHandler exceptionHandler)
throws TException
{
if ((!a.isInitialized() || !b.isInitialized()) && exceptionHandler != null)
exceptionHandler.raise(TExceptionType.REGISTER_UNINITIALIZED);
if ((b.getValue() & 0xF) != b.getValue() && exceptionHandler != null)
exceptionHandler.raise(TExceptionType.SHIFT_OUT_OF_BOUNDS);
return getWord((short)(a.getValue() << (b.getValue() & 0xF)));
}
/**
* Implements the arithmatic-right-shift operator for the TWord type. This could result in
* either a TException of type REGISTER_UNINITIALIZED or SHIFT_OUT_OF_BOUNDS.
*
* @param a The left operand.
* @param b The right operand.
* @param exceptionHandler The hander for any exceptional conditions which might be raised. If
* the exceptionHandler is null, all exceptions will be ignored.
* @return a >>> b.
* @see TExceptionType#REGISTER_UNINITIALIZED
* @see TExceptionType#SHIFT_OUT_OF_BOUNDS
*/
public static TWord rightShift(TWord a, TWord b, TExceptionHandler exceptionHandler)
throws TException
{
if ((!a.isInitialized() || !b.isInitialized()) && exceptionHandler != null)
exceptionHandler.raise(TExceptionType.REGISTER_UNINITIALIZED);
if ((b.getValue() & 0xF) != b.getValue() && exceptionHandler != null)
exceptionHandler.raise(TExceptionType.SHIFT_OUT_OF_BOUNDS);
return getWord((short)(a.getValue() >> (b.getValue() & 0xF)));
}
/**
* Returns whether or not a character is a hexidecimal digit. This test is case-insensitive.
*
* @param c The character to test.
* @return True iff the c is a hexidecimal digit.
*/
public static boolean isHexDigit(char c)
{
return c >= '0' && c <= '9' ||
c >= 'A' && c <= 'F' ||
c >= 'a' && c <= 'f';
}
/**
* Returns the hexidecimal value of a character. This function is case-insensitive.
*
* @param c The character to convert. If this character is not a hex digit, an
* IllegalArgumentException will be thrown.
* @return The value c interpreted as a hexidecimal digit.
*/
public static int hexDigitToInt(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
throw new IllegalArgumentException();
}
}