0da1c5dcca
First commit of the 4.5 version (latest version available)
199 lines
9.1 KiB
Java
199 lines
9.1 KiB
Java
package mars.assembler;
|
|
import mars.*;
|
|
import mars.util.Binary;
|
|
import mars.mips.instructions.*;
|
|
import java.util.*;
|
|
|
|
/*
|
|
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
|
|
|
|
Developed by Pete Sanderson (psanderson@otterbein.edu)
|
|
and Kenneth Vollmar (kenvollmar@missouristate.edu)
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
a copy of this software and associated documentation files (the
|
|
"Software"), to deal in the Software without restriction, including
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
permit persons to whom the Software is furnished to do so, subject
|
|
to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be
|
|
included in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
|
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
(MIT license, http://www.opensource.org/licenses/mit-license.html)
|
|
*/
|
|
|
|
/**
|
|
* Provides utility method related to MIPS operand formats.
|
|
*
|
|
* @author Pete Sanderson
|
|
* @version August 2003
|
|
*/
|
|
|
|
|
|
public class OperandFormat {
|
|
|
|
private OperandFormat() {
|
|
}
|
|
|
|
/*
|
|
* Syntax test for correct match in both numbers and types of operands.
|
|
*
|
|
* @param candidateList List of tokens generated from programmer's MIPS statement.
|
|
* @param spec The (resumably best matched) MIPS instruction.
|
|
* @param errors ErrorList into which any error messages generated here will be added.
|
|
*
|
|
* @return Returns <tt>true</tt> if the programmer's statement matches the MIPS
|
|
* specification, else returns <tt>false</tt>.
|
|
*/
|
|
|
|
static boolean tokenOperandMatch(TokenList candidateList, Instruction inst, ErrorList errors) {
|
|
if (!numOperandsCheck(candidateList, inst, errors))
|
|
return false;
|
|
if (!operandTypeCheck(candidateList, inst, errors))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* If candidate operator token matches more than one instruction mnemonic, then select
|
|
* first such Instruction that has an exact operand match. If none match,
|
|
* return the first Instruction and let client deal with operand mismatches.
|
|
*/
|
|
static Instruction bestOperandMatch(TokenList tokenList, ArrayList instrMatches) {
|
|
if (instrMatches == null)
|
|
return null;
|
|
if (instrMatches.size() == 1)
|
|
return (Instruction) instrMatches.get(0);
|
|
for (int i=0; i<instrMatches.size(); i++) {
|
|
Instruction potentialMatch = (Instruction) instrMatches.get(i);
|
|
if (tokenOperandMatch(tokenList, potentialMatch, new ErrorList()))
|
|
return potentialMatch;
|
|
}
|
|
return (Instruction) instrMatches.get(0);
|
|
}
|
|
|
|
// Simply check to see if numbers of operands are correct and generate error message if not.
|
|
private static boolean numOperandsCheck(TokenList cand, Instruction spec, ErrorList errors) {
|
|
int numOperands = cand.size()-1;
|
|
int reqNumOperands = spec.getTokenList().size()-1;
|
|
Token operator = cand.get(0);
|
|
if (numOperands == reqNumOperands) {
|
|
return true;
|
|
}
|
|
else if (numOperands < reqNumOperands) {
|
|
String mess = "Too few or incorrectly formatted operands. Expected: "+spec.getExampleFormat();
|
|
generateMessage(operator, mess, errors);
|
|
}
|
|
else {
|
|
String mess = "Too many or incorrectly formatted operands. Expected: "+spec.getExampleFormat();
|
|
generateMessage(operator, mess, errors);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Generate error message if operand is not of correct type for this operation & operand position
|
|
private static boolean operandTypeCheck(TokenList cand, Instruction spec, ErrorList errors) {
|
|
Token candToken, specToken;
|
|
TokenTypes candType, specType;
|
|
for (int i=1; i<spec.getTokenList().size(); i++) {
|
|
candToken = cand.get(i);
|
|
specToken = spec.getTokenList().get(i);
|
|
candType = candToken.getType();
|
|
specType = specToken.getType();
|
|
// Type mismatch is error EXCEPT when (1) spec calls for register name and candidate is
|
|
// register number, (2) spec calls for register number, candidate is register name and
|
|
// names are permitted, (3)spec calls for integer of specified max bit length and
|
|
// candidate is integer of smaller bit length.
|
|
// Type match is error when spec calls for register name, candidate is register name, and
|
|
// names are not permitted.
|
|
|
|
// added 2-July-2010 DPS
|
|
// Not an error if spec calls for identifier and candidate is operator, since operator names can be used as labels.
|
|
if (specType == TokenTypes.IDENTIFIER && candType == TokenTypes.OPERATOR) {
|
|
Token replacement = new Token(TokenTypes.IDENTIFIER, candToken.getValue(), candToken.getSourceMIPSprogram(), candToken.getSourceLine(), candToken.getStartPos());
|
|
cand.set(i, replacement);
|
|
continue;
|
|
}
|
|
// end 2-July-2010 addition
|
|
|
|
if ((specType == TokenTypes.REGISTER_NAME || specType == TokenTypes.REGISTER_NUMBER) &&
|
|
candType == TokenTypes.REGISTER_NAME) {
|
|
if (Globals.getSettings().getBareMachineEnabled()) {
|
|
// On 10-Aug-2010, I noticed this cannot happen since the IDE provides no access
|
|
// to this setting, whose default value is false.
|
|
generateMessage(candToken, "Use register number instead of name. See Settings.", errors);
|
|
return false;
|
|
}
|
|
else {
|
|
continue;
|
|
}
|
|
}
|
|
if (specType == TokenTypes.REGISTER_NAME &&
|
|
candType == TokenTypes.REGISTER_NUMBER)
|
|
continue;
|
|
if ((specType == TokenTypes.INTEGER_16 && candType == TokenTypes.INTEGER_5) ||
|
|
(specType == TokenTypes.INTEGER_16U && candType == TokenTypes.INTEGER_5) ||
|
|
(specType == TokenTypes.INTEGER_32 && candType == TokenTypes.INTEGER_5) ||
|
|
(specType == TokenTypes.INTEGER_32 && candType == TokenTypes.INTEGER_16U) ||
|
|
(specType == TokenTypes.INTEGER_32 && candType == TokenTypes.INTEGER_16))
|
|
continue;
|
|
if (candType == TokenTypes.INTEGER_16U || candType == TokenTypes.INTEGER_16) {
|
|
int temp = Binary.stringToInt(candToken.getValue());
|
|
if (specType == TokenTypes.INTEGER_16 && candType == TokenTypes.INTEGER_16U &&
|
|
temp>=DataTypes.MIN_HALF_VALUE && temp<=DataTypes.MAX_HALF_VALUE)
|
|
continue;
|
|
if (specType == TokenTypes.INTEGER_16U && candType == TokenTypes.INTEGER_16 &&
|
|
temp>=DataTypes.MIN_UHALF_VALUE && temp<=DataTypes.MAX_UHALF_VALUE)
|
|
continue;
|
|
}
|
|
if ((specType == TokenTypes.INTEGER_5 && candType == TokenTypes.INTEGER_16) ||
|
|
(specType == TokenTypes.INTEGER_5 && candType == TokenTypes.INTEGER_16U) ||
|
|
(specType == TokenTypes.INTEGER_5 && candType == TokenTypes.INTEGER_32) ||
|
|
(specType == TokenTypes.INTEGER_16 && candType == TokenTypes.INTEGER_16U) ||
|
|
(specType == TokenTypes.INTEGER_16U && candType == TokenTypes.INTEGER_16) ||
|
|
(specType == TokenTypes.INTEGER_16U && candType == TokenTypes.INTEGER_32) ||
|
|
(specType == TokenTypes.INTEGER_16 && candType == TokenTypes.INTEGER_32)) {
|
|
generateMessage(candToken, "operand is out of range", errors);
|
|
return false;
|
|
}
|
|
if (candType != specType) {
|
|
generateMessage(candToken, "operand is of incorrect type", errors);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/******** nice little debugging code to see which operand format
|
|
******** the operands for this source code instruction matched.
|
|
System.out.print("Candidate: ");
|
|
for (int i=1; i<spec.size(); i++) {
|
|
System.out.print(cand.get(i).getValue()+" ");
|
|
}
|
|
System.out.print("Matched Spec: ");
|
|
for (int i=1; i<spec.size(); i++) {
|
|
System.out.print(spec.get(i).getValue()+" ");
|
|
}
|
|
System.out.println();
|
|
*/
|
|
|
|
return true;
|
|
}
|
|
|
|
// Handy utility for all parse errors...
|
|
private static void generateMessage(Token token, String mess, ErrorList errors) {
|
|
errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token.getStartPos(),
|
|
"\""+token.getValue()+"\": "+mess));
|
|
return;
|
|
}
|
|
|
|
}
|