Source code of MARS Assembler
First commit of the 4.5 version (latest version available)
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user