diff --git a/src/mars/ErrorList.java b/src/mars/ErrorList.java
index 0b8dd28..080ca7c 100644
--- a/src/mars/ErrorList.java
+++ b/src/mars/ErrorList.java
@@ -1,6 +1,7 @@
- package mars;
- import java.util.*;
- import java.io.*;
+package mars;
+import java.util.*;
+import java.io.*;
+
/*
Copyright (c) 2003-2012, Pete Sanderson and Kenneth Vollmar
@@ -37,162 +38,160 @@ a copy of this software and associated documentation files (the
* @version August 2003
**/
- public class ErrorList {
- private ArrayList messages;
- private int errorCount;
- private int warningCount;
- public static final String ERROR_MESSAGE_PREFIX = "Error";
- public static final String WARNING_MESSAGE_PREFIX = "Warning";
- public static final String FILENAME_PREFIX = " in ";
- public static final String LINE_PREFIX = " line ";
- public static final String POSITION_PREFIX = " column ";
- public static final String MESSAGE_SEPARATOR = ": ";
-
-
- /**
- * Constructor for ErrorList
- **/
-
- public ErrorList() {
- messages = new ArrayList();
- errorCount = 0;
- warningCount = 0;
- }
-
- /**
- * Get ArrayList of error messages.
- * @return ArrayList of ErrorMessage objects
- */
- public ArrayList getErrorMessages() {
- return messages;
- }
-
- /**
- * Determine whether error has occured or not.
- * @return true if an error has occurred (does not include warnings), false otherwise.
- **/
- public boolean errorsOccurred() {
- return (errorCount != 0 );
- }
-
- /**
- * Determine whether warning has occured or not.
- * @return true if an warning has occurred, false otherwise.
- **/
- public boolean warningsOccurred() {
- return (warningCount != 0 );
- }
-
- /** Add new error message to end of list.
- * @param mess ErrorMessage object to be added to end of error list.
- **/
- public void add(ErrorMessage mess){
- add(mess, messages.size());
- }
-
- /** Add new error message at specified index position.
- * @param mess ErrorMessage object to be added to end of error list.
- * @param index position in error list
- **/
- public void add(ErrorMessage mess, int index) {
- if (errorCount > getErrorLimit()) {
+public class ErrorList {
+ private ArrayList messages;
+ private int errorCount;
+ private int warningCount;
+ public static final String ERROR_MESSAGE_PREFIX = "Error";
+ public static final String WARNING_MESSAGE_PREFIX = "Warning";
+ public static final String FILENAME_PREFIX = " in ";
+ public static final String LINE_PREFIX = " line ";
+ public static final String POSITION_PREFIX = " column ";
+ public static final String MESSAGE_SEPARATOR = ": ";
+
+ /**
+ * Constructor for ErrorList
+ **/
+
+ public ErrorList() {
+ messages = new ArrayList<>();
+ errorCount = 0;
+ warningCount = 0;
+ }
+
+ /**
+ * Get ArrayList of error messages.
+ * @return ArrayList of ErrorMessage objects
+ */
+ public ArrayList getErrorMessages() {
+ return messages;
+ }
+
+ /**
+ * Determine whether error has occured or not.
+ * @return true if an error has occurred (does not include warnings), false otherwise.
+ **/
+ public boolean errorsOccurred() {
+ return (errorCount != 0 );
+ }
+
+ /**
+ * Determine whether warning has occured or not.
+ * @return true if an warning has occurred, false otherwise.
+ **/
+ public boolean warningsOccurred() {
+ return (warningCount != 0 );
+ }
+
+ /** Add new error message to end of list.
+ * @param mess ErrorMessage object to be added to end of error list.
+ **/
+ public void add(ErrorMessage mess){
+ add(mess, messages.size());
+ }
+
+ /** Add new error message at specified index position.
+ * @param mess ErrorMessage object to be added to end of error list.
+ * @param index position in error list
+ **/
+ public void add(ErrorMessage mess, int index) {
+ if (errorCount > getErrorLimit()) {
return;
- }
- if (errorCount == getErrorLimit()) {
+ }
+ if (errorCount == getErrorLimit()) {
messages.add(new ErrorMessage((MIPSprogram)null, mess.getLine(), mess.getPosition(),"Error Limit of "+getErrorLimit()+" exceeded."));
errorCount++; // subsequent errors will not be added; see if statement above
return;
- }
- messages.add(index, mess);
- if (mess.isWarning()) {
+ }
+ messages.add(index, mess);
+ if (mess.isWarning()) {
warningCount++;
- }
- else {
+ }
+ else {
errorCount++;
- }
- }
-
-
- /**
- * Count of number of error messages in list.
- * @return Number of error messages in list.
- **/
-
- public int errorCount() {
- return this.errorCount;
- }
-
- /**
- * Count of number of warning messages in list.
- * @return Number of warning messages in list.
- **/
-
- public int warningCount() {
- return this.warningCount;
- }
-
- /**
- * Check to see if error limit has been exceeded.
- * @return True if error limit exceeded, false otherwise.
- **/
-
- public boolean errorLimitExceeded() {
- return this.errorCount > getErrorLimit();
- }
-
- /**
- * Get limit on number of error messages to be generated
- * by one assemble operation.
- * @return error limit.
- **/
-
- public int getErrorLimit() {
- return Globals.maximumErrorMessages;
- }
-
- /**
- * Produce error report.
- * @return String containing report.
- **/
- public String generateErrorReport() {
- return generateReport(ErrorMessage.ERROR);
- }
-
- /**
- * Produce warning report.
- * @return String containing report.
- **/
- public String generateWarningReport() {
- return generateReport(ErrorMessage.WARNING);
- }
-
- /**
- * Produce report containing both warnings and errors, warnings first.
- * @return String containing report.
- **/
- public String generateErrorAndWarningReport() {
- return generateWarningReport()+generateErrorReport();
- }
-
- // Produces either error or warning report.
- private String generateReport(boolean isWarning) {
- StringBuffer report = new StringBuffer("");
- String reportLine;
- for (int i = 0; i < messages.size(); i++) {
- ErrorMessage m = (ErrorMessage) messages.get(i);
+ }
+ }
+
+
+ /**
+ * Count of number of error messages in list.
+ * @return Number of error messages in list.
+ **/
+
+ public int errorCount() {
+ return this.errorCount;
+ }
+
+ /**
+ * Count of number of warning messages in list.
+ * @return Number of warning messages in list.
+ **/
+
+ public int warningCount() {
+ return this.warningCount;
+ }
+
+ /**
+ * Check to see if error limit has been exceeded.
+ * @return True if error limit exceeded, false otherwise.
+ **/
+
+ public boolean errorLimitExceeded() {
+ return this.errorCount > getErrorLimit();
+ }
+
+ /**
+ * Get limit on number of error messages to be generated
+ * by one assemble operation.
+ * @return error limit.
+ **/
+
+ public int getErrorLimit() {
+ return Globals.maximumErrorMessages;
+ }
+
+ /**
+ * Produce error report.
+ * @return String containing report.
+ **/
+ public String generateErrorReport() {
+ return generateReport(ErrorMessage.ERROR);
+ }
+
+ /**
+ * Produce warning report.
+ * @return String containing report.
+ **/
+ public String generateWarningReport() {
+ return generateReport(ErrorMessage.WARNING);
+ }
+
+ /**
+ * Produce report containing both warnings and errors, warnings first.
+ * @return String containing report.
+ **/
+ public String generateErrorAndWarningReport() {
+ return generateWarningReport()+generateErrorReport();
+ }
+
+ // Produces either error or warning report.
+ private String generateReport(boolean isWarning) {
+ StringBuffer report = new StringBuffer("");
+ String reportLine;
+ for (int i = 0; i < messages.size(); i++) {
+ ErrorMessage m = messages.get(i);
if ((isWarning && m.isWarning()) || (!isWarning && !m.isWarning())) {
- reportLine = ((isWarning) ? WARNING_MESSAGE_PREFIX : ERROR_MESSAGE_PREFIX) + FILENAME_PREFIX;
- if (m.getFilename().length() > 0)
- reportLine = reportLine + (new File(m.getFilename()).getPath()); //.getName());
- if (m.getLine() > 0)
- reportLine = reportLine + LINE_PREFIX +m.getMacroExpansionHistory()+ m.getLine();
- if (m.getPosition() > 0)
- reportLine = reportLine + POSITION_PREFIX + m.getPosition();
- reportLine = reportLine + MESSAGE_SEPARATOR + m.getMessage() + "\n";
- report.append(reportLine);
+ reportLine = ((isWarning) ? WARNING_MESSAGE_PREFIX : ERROR_MESSAGE_PREFIX) + FILENAME_PREFIX;
+ if (m.getFilename().length() > 0)
+ reportLine = reportLine + (new File(m.getFilename()).getPath()); //.getName());
+ if (m.getLine() > 0)
+ reportLine = reportLine + LINE_PREFIX +m.getMacroExpansionHistory()+ m.getLine();
+ if (m.getPosition() > 0)
+ reportLine = reportLine + POSITION_PREFIX + m.getPosition();
+ reportLine = reportLine + MESSAGE_SEPARATOR + m.getMessage() + "\n";
+ report.append(reportLine);
}
- }
- return report.toString();
- }
- } // ErrorList
-
+ }
+ return report.toString();
+ }
+} // ErrorList
diff --git a/src/mars/ErrorMessage.java b/src/mars/ErrorMessage.java
index 74d056b..d962216 100644
--- a/src/mars/ErrorMessage.java
+++ b/src/mars/ErrorMessage.java
@@ -1,8 +1,9 @@
- package mars;
-
- import java.util.regex.Pattern;
- import java.util.regex.Matcher;
- import java.util.ArrayList;
+package mars;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.ArrayList;
+
/*
Copyright (c) 2003-2012, Pete Sanderson and Kenneth Vollmar
@@ -37,249 +38,247 @@ a copy of this software and associated documentation files (the
* @version August 2003
**/
- public class ErrorMessage {
- private boolean isWarning; // allow for warnings too (added Nov 2006)
- private String filename; // name of source file (added Oct 2006)
- private int line; // line in source code where error detected
- private int position; // position in source line where error detected
- private String message;
- private String macroExpansionHistory;
-
- /**
- * Constant to indicate this message is warning not error
- */
- public static final boolean WARNING = true;
-
- /**
- * Constant to indicate this message is error not warning
- */
- public static final boolean ERROR = false;
-
- /**
- * Constructor for ErrorMessage.
- * @param filename String containing name of source file in which this error appears.
- * @param line Line number in source program being processed when error occurred.
- * @param position Position within line being processed when error occurred. Normally is starting
- * position of source token.
- * @param message String containing appropriate error message.
- * @deprecated Newer constructors replace the String filename parameter with a MIPSprogram parameter to provide more information.
- **/
+public class ErrorMessage {
+ private boolean isWarning; // allow for warnings too (added Nov 2006)
+ private String filename; // name of source file (added Oct 2006)
+ private int line; // line in source code where error detected
+ private int position; // position in source line where error detected
+ private String message;
+ private String macroExpansionHistory;
+
+ /**
+ * Constant to indicate this message is warning not error
+ */
+ public static final boolean WARNING = true;
+
+ /**
+ * Constant to indicate this message is error not warning
+ */
+ public static final boolean ERROR = false;
+
+ /**
+ * Constructor for ErrorMessage.
+ * @param filename String containing name of source file in which this error appears.
+ * @param line Line number in source program being processed when error occurred.
+ * @param position Position within line being processed when error occurred. Normally is starting
+ * position of source token.
+ * @param message String containing appropriate error message.
+ * @deprecated Newer constructors replace the String filename parameter with a MIPSprogram parameter to provide more information.
+ **/
// Added filename October 2006
- @Deprecated
- public ErrorMessage(String filename, int line, int position, String message) {
- this(ERROR, filename, line, position, message, "");
- }
-
- /**
- * Constructor for ErrorMessage.
- * @param filename String containing name of source file in which this error appears.
- * @param line Line number in source program being processed when error occurred.
- * @param position Position within line being processed when error occurred. Normally is starting
- * position of source token.
- * @param message String containing appropriate error message.
- * @param macroExpansionHistory
- * @deprecated Newer constructors replace the String filename parameter with a MIPSprogram parameter to provide more information.
- **/
+ @Deprecated
+ public ErrorMessage(String filename, int line, int position, String message) {
+ this(ERROR, filename, line, position, message, "");
+ }
+
+ /**
+ * Constructor for ErrorMessage.
+ * @param filename String containing name of source file in which this error appears.
+ * @param line Line number in source program being processed when error occurred.
+ * @param position Position within line being processed when error occurred. Normally is starting
+ * position of source token.
+ * @param message String containing appropriate error message.
+ * @param macroExpansionHistory
+ * @deprecated Newer constructors replace the String filename parameter with a MIPSprogram parameter to provide more information.
+ **/
// Added macroExpansionHistory Dec 2012
-
- @Deprecated
- public ErrorMessage(String filename, int line, int position, String message, String macroExpansionHistory) {
- this(ERROR, filename, line, position, message, macroExpansionHistory);
- }
-
- /**
- * Constructor for ErrorMessage.
- * @param isWarning set to WARNING if message is a warning not error, else set to ERROR or omit.
- * @param filename String containing name of source file in which this error appears.
- * @param line Line number in source program being processed when error occurred.
- * @param position Position within line being processed when error occurred. Normally is starting
- * position of source token.
- * @param message String containing appropriate error message.
- * @param macroExpansionHistory provided so message for macro can include both definition and usage line numbers
- * @deprecated Newer constructors replace the String filename parameter with a MIPSprogram parameter to provide more information.
- **/
- @Deprecated
- public ErrorMessage(boolean isWarning, String filename, int line, int position, String message, String macroExpansionHistory) {
- this.isWarning = isWarning;
- this.filename = filename;
- this.line = line;
- this.position = position;
- this.message = message;
- this.macroExpansionHistory=macroExpansionHistory;
- }
-
-
- /**
- * Constructor for ErrorMessage. Assumes line number is calculated after any .include files expanded, and
- * if there were, it will adjust filename and line number so message reflects original file and line number.
- * @param sourceMIPSprogram MIPSprogram object of source file in which this error appears.
- * @param line Line number in source program being processed when error occurred.
- * @param position Position within line being processed when error occurred. Normally is starting
- * position of source token.
- * @param message String containing appropriate error message.
- **/
-
- public ErrorMessage(MIPSprogram sourceMIPSprogram, int line, int position, String message) {
- this(ERROR, sourceMIPSprogram, line, position, message);
- }
-
-
- /**
- * Constructor for ErrorMessage. Assumes line number is calculated after any .include files expanded, and
- * if there were, it will adjust filename and line number so message reflects original file and line number.
- * @param isWarning set to WARNING if message is a warning not error, else set to ERROR or omit.
- * @param sourceMIPSprogram MIPSprogram object of source file in which this error appears.
- * @param line Line number in source program being processed when error occurred.
- * @param position Position within line being processed when error occurred. Normally is starting
- * position of source token.
- * @param message String containing appropriate error message.
- **/
-
- public ErrorMessage(boolean isWarning, MIPSprogram sourceMIPSprogram, int line, int position, String message) {
- this.isWarning = isWarning;
- if (sourceMIPSprogram == null) {
+
+ @Deprecated
+ public ErrorMessage(String filename, int line, int position, String message, String macroExpansionHistory) {
+ this(ERROR, filename, line, position, message, macroExpansionHistory);
+ }
+
+ /**
+ * Constructor for ErrorMessage.
+ * @param isWarning set to WARNING if message is a warning not error, else set to ERROR or omit.
+ * @param filename String containing name of source file in which this error appears.
+ * @param line Line number in source program being processed when error occurred.
+ * @param position Position within line being processed when error occurred. Normally is starting
+ * position of source token.
+ * @param message String containing appropriate error message.
+ * @param macroExpansionHistory provided so message for macro can include both definition and usage line numbers
+ * @deprecated Newer constructors replace the String filename parameter with a MIPSprogram parameter to provide more information.
+ **/
+ @Deprecated
+ public ErrorMessage(boolean isWarning, String filename, int line, int position, String message, String macroExpansionHistory) {
+ this.isWarning = isWarning;
+ this.filename = filename;
+ this.line = line;
+ this.position = position;
+ this.message = message;
+ this.macroExpansionHistory=macroExpansionHistory;
+ }
+
+ /**
+ * Constructor for ErrorMessage. Assumes line number is calculated after any .include files expanded, and
+ * if there were, it will adjust filename and line number so message reflects original file and line number.
+ * @param sourceMIPSprogram MIPSprogram object of source file in which this error appears.
+ * @param line Line number in source program being processed when error occurred.
+ * @param position Position within line being processed when error occurred. Normally is starting
+ * position of source token.
+ * @param message String containing appropriate error message.
+ **/
+
+ public ErrorMessage(MIPSprogram sourceMIPSprogram, int line, int position, String message) {
+ this(ERROR, sourceMIPSprogram, line, position, message);
+ }
+
+ /**
+ * Constructor for ErrorMessage. Assumes line number is calculated after any .include files expanded, and
+ * if there were, it will adjust filename and line number so message reflects original file and line number.
+ * @param isWarning set to WARNING if message is a warning not error, else set to ERROR or omit.
+ * @param sourceMIPSprogram MIPSprogram object of source file in which this error appears.
+ * @param line Line number in source program being processed when error occurred.
+ * @param position Position within line being processed when error occurred. Normally is starting
+ * position of source token.
+ * @param message String containing appropriate error message.
+ **/
+
+ public ErrorMessage(boolean isWarning, MIPSprogram sourceMIPSprogram, int line, int position, String message) {
+ this.isWarning = isWarning;
+ if (sourceMIPSprogram == null) {
this.filename = "";
this.line = line;
- }
- else {
+ }
+ else {
if (sourceMIPSprogram.getSourceLineList() == null) {
- this.filename = sourceMIPSprogram.getFilename();
- this.line = line;
+ this.filename = sourceMIPSprogram.getFilename();
+ this.line = line;
}
else {
- mars.assembler.SourceLine sourceLine = sourceMIPSprogram.getSourceLineList().get(line-1);
- this.filename = sourceLine.getFilename();
- this.line = sourceLine.getLineNumber();
+ mars.assembler.SourceLine sourceLine = sourceMIPSprogram.getSourceLineList().get(line-1);
+ this.filename = sourceLine.getFilename();
+ this.line = sourceLine.getLineNumber();
}
- }
- this.position = position;
- this.message = message;
- this.macroExpansionHistory = getExpansionHistory(sourceMIPSprogram);
- }
-
- /**
- * Constructor for ErrorMessage, to be used for runtime exceptions.
- * @param statement The ProgramStatement object for the instruction causing the runtime error
- * @param message String containing appropriate error message.
- **/
- // Added January 2013
-
- public ErrorMessage(ProgramStatement statement, String message) {
- this.isWarning = ERROR;
- this.filename = (statement.getSourceMIPSprogram() == null)
- ? "" : statement.getSourceMIPSprogram().getFilename();
- this.position = 0;
- this.message = message;
- // Somewhere along the way we lose the macro history, but can
- // normally recreate it here. The line number for macro use (in the
- // expansion) comes with the ProgramStatement.getSourceLine().
- // The line number for the macro definition comes embedded in
- // the source code from ProgramStatement.getSource(), which is
- // displayed in the Text Segment display. It would previously
- // have had the macro definition line prepended in brackets,
- // e.g. "<13> syscall # finished". So I'll extract that
- // bracketed number here and include it in the error message.
- // Looks bass-ackwards, but to get the line numbers to display correctly
- // for runtime error occurring in macro expansion (expansion->definition), need
- // to assign to the opposite variables.
- ArrayList defineLine = parseMacroHistory(statement.getSource());
- if (defineLine.size() == 0) {
+ }
+ this.position = position;
+ this.message = message;
+ this.macroExpansionHistory = getExpansionHistory(sourceMIPSprogram);
+ }
+
+ /**
+ * Constructor for ErrorMessage, to be used for runtime exceptions.
+ * @param statement The ProgramStatement object for the instruction causing the runtime error
+ * @param message String containing appropriate error message.
+ **/
+ // Added January 2013
+
+ public ErrorMessage(ProgramStatement statement, String message) {
+ this.isWarning = ERROR;
+ this.filename = (statement.getSourceMIPSprogram() == null)
+ ? "" : statement.getSourceMIPSprogram().getFilename();
+ this.position = 0;
+ this.message = message;
+ // Somewhere along the way we lose the macro history, but can
+ // normally recreate it here. The line number for macro use (in the
+ // expansion) comes with the ProgramStatement.getSourceLine().
+ // The line number for the macro definition comes embedded in
+ // the source code from ProgramStatement.getSource(), which is
+ // displayed in the Text Segment display. It would previously
+ // have had the macro definition line prepended in brackets,
+ // e.g. "<13> syscall # finished". So I'll extract that
+ // bracketed number here and include it in the error message.
+ // Looks bass-ackwards, but to get the line numbers to display correctly
+ // for runtime error occurring in macro expansion (expansion->definition), need
+ // to assign to the opposite variables.
+ ArrayList defineLine = parseMacroHistory(statement.getSource());
+ if (defineLine.size() == 0) {
this.line = statement.getSourceLine();
this.macroExpansionHistory = "";
- }
- else {
+ }
+ else {
this.line = defineLine.get(0);
this.macroExpansionHistory = ""+statement.getSourceLine();
- }
- }
-
- private ArrayList parseMacroHistory(String string) {
- Pattern pattern = Pattern.compile("<\\d+>");
- Matcher matcher = pattern.matcher(string);
- String verify = new String(string).trim();
- ArrayList macroHistory = new ArrayList();
- while (matcher.find()) {
+ }
+ }
+
+ private ArrayList parseMacroHistory(String string) {
+ Pattern pattern = Pattern.compile("<\\d+>");
+ Matcher matcher = pattern.matcher(string);
+ String verify = new String(string).trim();
+ ArrayList macroHistory = new ArrayList<>();
+ while (matcher.find()) {
String match = matcher.group();
if (verify.indexOf(match)==0) {
- try {
- int line = Integer.parseInt(match.substring(1,match.length()-1));
- macroHistory.add(line);
- }
- catch (NumberFormatException e) {
- break;
- }
- verify = verify.substring(match.length()).trim();
+ try {
+ int line = Integer.parseInt(match.substring(1,match.length()-1));
+ macroHistory.add(line);
+ }
+ catch (NumberFormatException e) {
+ break;
+ }
+ verify = verify.substring(match.length()).trim();
}
else {
- break;
+ break;
}
- }
- return macroHistory;
- }
-
- /**
- * Produce name of file containing error.
- * @return Returns String containing name of source file containing the error.
- */
- // Added October 2006
-
- public String getFilename() {
- return filename;
- }
-
- /**
- * Produce line number of error.
- * @return Returns line number in source program where error occurred.
- */
-
- public int getLine() {
- return line;
- }
-
- /**
- * Produce position within erroneous line.
- * @return Returns position within line of source program where error occurred.
- */
-
- public int getPosition() {
- return position;
- }
-
- /**
- * Produce error message.
- * @return Returns String containing textual error message.
- */
-
- public String getMessage() {
- return message;
- }
-
- /**
- * Determine whether this message represents error or warning.
- * @return Returns true if this message reflects warning, false if error.
- */
+ }
+ return macroHistory;
+ }
+
+ /**
+ * Produce name of file containing error.
+ * @return Returns String containing name of source file containing the error.
+ */
+ // Added October 2006
+
+ public String getFilename() {
+ return filename;
+ }
+
+ /**
+ * Produce line number of error.
+ * @return Returns line number in source program where error occurred.
+ */
+
+ public int getLine() {
+ return line;
+ }
+
+ /**
+ * Produce position within erroneous line.
+ * @return Returns position within line of source program where error occurred.
+ */
+
+ public int getPosition() {
+ return position;
+ }
+
+ /**
+ * Produce error message.
+ * @return Returns String containing textual error message.
+ */
+
+ public String getMessage() {
+ return message;
+ }
+
+ /**
+ * Determine whether this message represents error or warning.
+ * @return Returns true if this message reflects warning, false if error.
+ */
// Method added 28 Nov 2006
- public boolean isWarning() {
- return this.isWarning;
- }
-
- /**
- * Returns string describing macro expansion. Empty string if none.
- * @return string describing macro expansion
- */
+ public boolean isWarning() {
+ return this.isWarning;
+ }
+
+ /**
+ * Returns string describing macro expansion. Empty string if none.
+ * @return string describing macro expansion
+ */
// Method added by Mohammad Sekavat Dec 2012
-
- public String getMacroExpansionHistory() {
- if (macroExpansionHistory==null || macroExpansionHistory.length()==0)
+
+ public String getMacroExpansionHistory() {
+ if (macroExpansionHistory==null || macroExpansionHistory.length()==0)
return "";
- return macroExpansionHistory+"->";
- }
-
- // Added by Mohammad Sekavat Dec 2012
- private static String getExpansionHistory(MIPSprogram sourceMIPSprogram) {
- if (sourceMIPSprogram==null || sourceMIPSprogram.getLocalMacroPool()==null)
+ return macroExpansionHistory+"->";
+ }
+
+ // Added by Mohammad Sekavat Dec 2012
+ private static String getExpansionHistory(MIPSprogram sourceMIPSprogram) {
+ if (sourceMIPSprogram==null || sourceMIPSprogram.getLocalMacroPool()==null)
return "";
- return sourceMIPSprogram.getLocalMacroPool().getExpansionHistory();
- }
-
- } // ErrorMessage
\ No newline at end of file
+ return sourceMIPSprogram.getLocalMacroPool().getExpansionHistory();
+ }
+
+} // ErrorMessage
diff --git a/src/mars/Globals.java b/src/mars/Globals.java
index d7aa115..6fdee07 100644
--- a/src/mars/Globals.java
+++ b/src/mars/Globals.java
@@ -1,13 +1,13 @@
- package mars;
- import mars.mips.instructions.syscalls.*;
- import mars.mips.instructions.*;
- import mars.mips.hardware.*;
- import mars.assembler.*;
- import mars.venus.*;
- import mars.util.*;
- import java.io.*;
- import java.util.*;
-
+package mars;
+import mars.mips.instructions.syscalls.*;
+import mars.mips.instructions.*;
+import mars.mips.hardware.*;
+import mars.assembler.*;
+import mars.venus.*;
+import mars.util.*;
+import java.io.*;
+import java.util.*;
+
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -76,7 +76,7 @@ public class Globals
/** The current MARS version number. Can't wait for "initialize()" call to get it. */
public static final String version = "4.5";
/** List of accepted file extensions for MIPS assembly source files. */
- public static final ArrayList fileExtensions = getFileExtensions();
+ public static final ArrayList fileExtensions = getFileExtensions();
/** Maximum length of scrolled message window (MARS Messages and Run I/O) */
public static final int maximumMessageCharacters = getMessageLimit();
/** Maximum number of assembler errors produced by one assemble operation */
@@ -188,8 +188,8 @@ private static int getIntegerProperty(String propertiesFile, String propertyName
// Read assembly language file extensions from properties file. Resulting
// string is tokenized into array list (assume StringTokenizer default delimiters).
- private static ArrayList getFileExtensions() {
- ArrayList extensionsList = new ArrayList();
+ private static ArrayList getFileExtensions() {
+ ArrayList extensionsList = new ArrayList<>();
String extensions = getPropertyEntry(configPropertiesFile,"Extensions");
if (extensions != null) {
StringTokenizer st = new StringTokenizer(extensions);
@@ -207,8 +207,8 @@ private static ArrayList getFileExtensions() {
* @return ArrayList. Each item is file path to .class file
* of a class that implements MarsTool. If none, returns empty list.
*/
- public static ArrayList getExternalTools() {
- ArrayList toolsList = new ArrayList();
+ public static ArrayList getExternalTools() {
+ ArrayList toolsList = new ArrayList<>();
String delimiter = ";";
String tools = getPropertyEntry(configPropertiesFile,"ExternalTools");
if (tools != null) {
@@ -235,10 +235,10 @@ public static String getPropertyEntry(String propertiesFile, String propertyName
* Read any syscall number assignment overrides from config file.
* @return ArrayList of SyscallNumberOverride objects
*/
- public ArrayList getSyscallOverrides() {
- ArrayList overrides = new ArrayList();
+ public ArrayList getSyscallOverrides() {
+ ArrayList overrides = new ArrayList<>();
Properties properties = PropertiesFile.loadPropertiesFromFile(syscallPropertiesFile);
- Enumeration keys = properties.keys();
+ Enumeration> keys = properties.keys();
while (keys.hasMoreElements()) {
String key = (String) keys.nextElement();
overrides.add(new SyscallNumberOverride(key,properties.getProperty(key)));
diff --git a/src/mars/assembler/Assembler.java b/src/mars/assembler/Assembler.java
index 6bd85e0..141ae2a 100644
--- a/src/mars/assembler/Assembler.java
+++ b/src/mars/assembler/Assembler.java
@@ -1,22 +1,22 @@
- package mars.assembler;
-
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.Comparator;
-
- import mars.ErrorList;
- import mars.ErrorMessage;
- import mars.Globals;
- import mars.MIPSprogram;
- import mars.ProcessingException;
- import mars.ProgramStatement;
- import mars.mips.hardware.AddressErrorException;
- import mars.mips.hardware.Memory;
- import mars.mips.instructions.BasicInstruction;
- import mars.mips.instructions.ExtendedInstruction;
- import mars.mips.instructions.Instruction;
- import mars.util.Binary;
- import mars.util.SystemIO;
+package mars.assembler;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+import mars.ErrorList;
+import mars.ErrorMessage;
+import mars.Globals;
+import mars.MIPSprogram;
+import mars.ProcessingException;
+import mars.ProgramStatement;
+import mars.mips.hardware.AddressErrorException;
+import mars.mips.hardware.Memory;
+import mars.mips.instructions.BasicInstruction;
+import mars.mips.instructions.ExtendedInstruction;
+import mars.mips.instructions.Instruction;
+import mars.util.Binary;
+import mars.util.SystemIO;
/*
Copyright (c) 2003-2012, Pete Sanderson and Kenneth Vollmar
@@ -55,1461 +55,1417 @@ a copy of this software and associated documentation files (the
* @version August 2003
**/
- public class Assembler {
- private ArrayList machineList;
- private ErrorList errors;
- private boolean inDataSegment; // status maintained by parser
- private boolean inMacroSegment; // status maintained by parser, true if in
- // macro definition segment
- private int externAddress;
- private boolean autoAlign;
- private Directives currentDirective;
- private Directives dataDirective;
- private MIPSprogram fileCurrentlyBeingAssembled;
- private TokenList globalDeclarationList;
- private UserKernelAddressSpace textAddress;
- private UserKernelAddressSpace dataAddress;
- private DataSegmentForwardReferences currentFileDataSegmentForwardReferences,
- accumulatedDataSegmentForwardReferences;
-
- /**
- * Parse and generate machine code for the given MIPS program. It must have
- * already been tokenized. Warnings are not considered errors.
- *
- * @param p
- * A MIPSprogram object representing the program source.
- * @param extendedAssemblerEnabled
- * A boolean value that if true permits use of extended (pseudo)
- * instructions in the source code. If false, these are flagged
- * as errors.
- * @return An ArrayList representing the assembled program. Each member of
- * the list is a ProgramStatement object containing the source,
- * intermediate, and machine binary representations of a program
- * statement.
- *
- * @see ProgramStatement
- **/
- public ArrayList assemble(MIPSprogram p, boolean extendedAssemblerEnabled)
- throws ProcessingException {
- return assemble(p, extendedAssemblerEnabled, false);
- }
-
- /**
- * Parse and generate machine code for the given MIPS program. It must have
- * already been tokenized.
- *
- * @param p
- * A MIPSprogram object representing the program source.
- * @param extendedAssemblerEnabled
- * A boolean value that if true permits use of extended (pseudo)
- * instructions in the source code. If false, these are flagged
- * as errors.
- * @param warningsAreErrors
- * A boolean value - true means assembler warnings will be
- * considered errors and terminate the assemble; false means the
- * assembler will produce warning message but otherwise ignore
- * warnings.
- * @return An ArrayList representing the assembled program. Each member of
- * the list is a ProgramStatement object containing the source,
- * intermediate, and machine binary representations of a program
- * statement.
- *
- * @see ProgramStatement
- **/
- public ArrayList assemble(MIPSprogram p, boolean extendedAssemblerEnabled,
- boolean warningsAreErrors) throws ProcessingException {
- ArrayList programFiles = new ArrayList();
- programFiles.add(p);
- return this.assemble(programFiles, extendedAssemblerEnabled, warningsAreErrors);
- }
-
- /**
- * Get list of assembler errors and warnings
- *
- * @return ErrorList of any assembler errors and warnings.
- */
- public ErrorList getErrorList() {
- return errors;
- }
-
- /**
- * Parse and generate machine code for the given MIPS program. All source
- * files must have already been tokenized. Warnings will not be considered
- * errors.
- *
- * @param tokenizedProgramFiles
- * An ArrayList of MIPSprogram objects, each produced from a
- * different source code file, representing the program source.
- * @param extendedAssemblerEnabled
- * A boolean value that if true permits use of extended (pseudo)
- * instructions in the source code. If false, these are flagged
- * as errors.
- * @return An ArrayList representing the assembled program. Each member of
- * the list is a ProgramStatement object containing the source,
- * intermediate, and machine binary representations of a program
- * statement. Returns null if incoming array list is null or empty.
- *
- * @see ProgramStatement
- **/
- public ArrayList assemble(ArrayList tokenizedProgramFiles, boolean extendedAssemblerEnabled)
- throws ProcessingException {
- return assemble(tokenizedProgramFiles, extendedAssemblerEnabled, false);
- }
-
- /**
- * Parse and generate machine code for the given MIPS program. All source
- * files must have already been tokenized.
- *
- * @param tokenizedProgramFiles
- * An ArrayList of MIPSprogram objects, each produced from a
- * different source code file, representing the program source.
- * @param extendedAssemblerEnabled
- * A boolean value that if true permits use of extended (pseudo)
- * instructions in the source code. If false, these are flagged
- * as errors.
- * @param warningsAreErrors
- * A boolean value - true means assembler warnings will be
- * considered errors and terminate the assemble; false means the
- * assembler will produce warning message but otherwise ignore
- * warnings.
- * @return An ArrayList representing the assembled program. Each member of
- * the list is a ProgramStatement object containing the source,
- * intermediate, and machine binary representations of a program
- * statement. Returns null if incoming array list is null or empty.
- *
- * @see ProgramStatement
- **/
- public ArrayList assemble(ArrayList tokenizedProgramFiles, boolean extendedAssemblerEnabled,
- boolean warningsAreErrors) throws ProcessingException {
-
- if (tokenizedProgramFiles == null || tokenizedProgramFiles.size() == 0)
+public class Assembler {
+ private ArrayList machineList;
+ private ErrorList errors;
+ private boolean inDataSegment; // status maintained by parser
+ private boolean inMacroSegment; // status maintained by parser, true if in
+ // macro definition segment
+ private int externAddress;
+ private boolean autoAlign;
+ private Directives currentDirective;
+ private Directives dataDirective;
+ private MIPSprogram fileCurrentlyBeingAssembled;
+ private TokenList globalDeclarationList;
+ private UserKernelAddressSpace textAddress;
+ private UserKernelAddressSpace dataAddress;
+ private DataSegmentForwardReferences currentFileDataSegmentForwardReferences,
+ accumulatedDataSegmentForwardReferences;
+
+ /**
+ * Parse and generate machine code for the given MIPS program. It must have
+ * already been tokenized. Warnings are not considered errors.
+ *
+ * @param p A MIPSprogram object representing the program
+ * source.
+ * @param extendedAssemblerEnabled A boolean value that if true permits use of
+ * extended (pseudo) instructions in the source
+ * code. If false, these are flagged as errors.
+ * @return An ArrayList representing the assembled program. Each member of
+ * the list is a ProgramStatement object containing the source,
+ * intermediate, and machine binary representations of a program
+ * statement.
+ *
+ * @see ProgramStatement
+ **/
+ public ArrayList assemble(MIPSprogram p, boolean extendedAssemblerEnabled)
+ throws ProcessingException {
+ return assemble(p, extendedAssemblerEnabled, false);
+ }
+
+ /**
+ * Parse and generate machine code for the given MIPS program. It must have
+ * already been tokenized.
+ *
+ * @param p A MIPSprogram object representing the program
+ * source.
+ * @param extendedAssemblerEnabled A boolean value that if true permits use of
+ * extended (pseudo) instructions in the source
+ * code. If false, these are flagged as errors.
+ * @param warningsAreErrors A boolean value - true means assembler warnings
+ * will be considered errors and terminate the
+ * assemble; false means the assembler will
+ * produce warning message but otherwise ignore
+ * warnings.
+ * @return An ArrayList representing the assembled program. Each member of
+ * the list is a ProgramStatement object containing the source,
+ * intermediate, and machine binary representations of a program
+ * statement.
+ *
+ * @see ProgramStatement
+ **/
+ public ArrayList assemble(MIPSprogram p, boolean extendedAssemblerEnabled,
+ boolean warningsAreErrors) throws ProcessingException {
+ ArrayList programFiles = new ArrayList<>();
+ programFiles.add(p);
+ return this.assemble(programFiles, extendedAssemblerEnabled, warningsAreErrors);
+ }
+
+ /**
+ * Get list of assembler errors and warnings
+ *
+ * @return ErrorList of any assembler errors and warnings.
+ */
+ public ErrorList getErrorList() {
+ return errors;
+ }
+
+ /**
+ * Parse and generate machine code for the given MIPS program. All source
+ * files must have already been tokenized. Warnings will not be considered
+ * errors.
+ *
+ * @param tokenizedProgramFiles An ArrayList of MIPSprogram objects, each
+ * produced from a different source code file,
+ * representing the program source.
+ * @param extendedAssemblerEnabled A boolean value that if true permits use of
+ * extended (pseudo) instructions in the source
+ * code. If false, these are flagged as errors.
+ * @return An ArrayList representing the assembled program. Each member of
+ * the list is a ProgramStatement object containing the source,
+ * intermediate, and machine binary representations of a program
+ * statement. Returns null if incoming array list is null or empty.
+ *
+ * @see ProgramStatement
+ **/
+ public ArrayList assemble(ArrayList tokenizedProgramFiles,
+ boolean extendedAssemblerEnabled) throws ProcessingException {
+ return assemble(tokenizedProgramFiles, extendedAssemblerEnabled, false);
+ }
+
+ /**
+ * Parse and generate machine code for the given MIPS program. All source
+ * files must have already been tokenized.
+ *
+ * @param tokenizedProgramFiles An ArrayList of MIPSprogram objects, each
+ * produced from a different source code file,
+ * representing the program source.
+ * @param extendedAssemblerEnabled A boolean value that if true permits use of
+ * extended (pseudo) instructions in the source
+ * code. If false, these are flagged as errors.
+ * @param warningsAreErrors A boolean value - true means assembler warnings
+ * will be considered errors and terminate the
+ * assemble; false means the assembler will
+ * produce warning message but otherwise ignore
+ * warnings.
+ * @return An ArrayList representing the assembled program. Each member of
+ * the list is a ProgramStatement object containing the source,
+ * intermediate, and machine binary representations of a program
+ * statement. Returns null if incoming array list is null or empty.
+ *
+ * @see ProgramStatement
+ **/
+ public ArrayList assemble(ArrayList tokenizedProgramFiles,
+ boolean extendedAssemblerEnabled, boolean warningsAreErrors) throws ProcessingException {
+
+ if (tokenizedProgramFiles == null || tokenizedProgramFiles.size() == 0)
return null;
- textAddress = new UserKernelAddressSpace(Memory.textBaseAddress,
- Memory.kernelTextBaseAddress);
- dataAddress = new UserKernelAddressSpace(Memory.dataBaseAddress,
- Memory.kernelDataBaseAddress);
- externAddress = Memory.externBaseAddress;
- currentFileDataSegmentForwardReferences = new DataSegmentForwardReferences();
- accumulatedDataSegmentForwardReferences = new DataSegmentForwardReferences();
- Globals.symbolTable.clear();
- Globals.memory.clear();
- this.machineList = new ArrayList();
- this.errors = new ErrorList();
- if (Globals.debug)
+ textAddress = new UserKernelAddressSpace(Memory.textBaseAddress,
+ Memory.kernelTextBaseAddress);
+ dataAddress = new UserKernelAddressSpace(Memory.dataBaseAddress,
+ Memory.kernelDataBaseAddress);
+ externAddress = Memory.externBaseAddress;
+ currentFileDataSegmentForwardReferences = new DataSegmentForwardReferences();
+ accumulatedDataSegmentForwardReferences = new DataSegmentForwardReferences();
+ Globals.symbolTable.clear();
+ Globals.memory.clear();
+ this.machineList = new ArrayList<>();
+ this.errors = new ErrorList();
+ if (Globals.debug)
System.out.println("Assembler first pass begins:");
- // PROCESS THE FIRST ASSEMBLY PASS FOR ALL SOURCE FILES BEFORE PROCEEDING
- // TO SECOND PASS. THIS ASSURES ALL SYMBOL TABLES ARE CORRECTLY BUILT.
- // THERE IS ONE GLOBAL SYMBOL TABLE (for identifiers declared .globl) PLUS
- // ONE LOCAL SYMBOL TABLE FOR EACH SOURCE FILE.
- for (int fileIndex = 0; fileIndex < tokenizedProgramFiles.size(); fileIndex++) {
+ // PROCESS THE FIRST ASSEMBLY PASS FOR ALL SOURCE FILES BEFORE PROCEEDING
+ // TO SECOND PASS. THIS ASSURES ALL SYMBOL TABLES ARE CORRECTLY BUILT.
+ // THERE IS ONE GLOBAL SYMBOL TABLE (for identifiers declared .globl) PLUS
+ // ONE LOCAL SYMBOL TABLE FOR EACH SOURCE FILE.
+ for (int fileIndex = 0; fileIndex < tokenizedProgramFiles.size(); fileIndex++) {
if (errors.errorLimitExceeded())
- break;
- this.fileCurrentlyBeingAssembled = (MIPSprogram) tokenizedProgramFiles.get(fileIndex);
- // List of labels declared ".globl". new list for each file assembled
+ break;
+ this.fileCurrentlyBeingAssembled = tokenizedProgramFiles.get(fileIndex);
+ // List of labels declared ".globl". new list for each file assembled
this.globalDeclarationList = new TokenList();
- // Parser begins by default in text segment until directed otherwise.
+ // Parser begins by default in text segment until directed otherwise.
this.inDataSegment = false;
- // Macro segment will be started by .macro directive
+ // Macro segment will be started by .macro directive
this.inMacroSegment = false;
- // Default is to align data from directives on appropriate boundary (word, half, byte)
- // This can be turned off for remainder of current data segment with ".align 0"
+ // Default is to align data from directives on appropriate boundary (word, half, byte)
+ // This can be turned off for remainder of current data segment with ".align 0"
this.autoAlign = true;
- // Default data directive is .word for 4 byte data items
+ // Default data directive is .word for 4 byte data items
this.dataDirective = Directives.WORD;
- // Clear out (initialize) symbol table related structures.
+ // Clear out (initialize) symbol table related structures.
fileCurrentlyBeingAssembled.getLocalSymbolTable().clear();
currentFileDataSegmentForwardReferences.clear();
- // sourceList is an ArrayList of String objects, one per source line.
- // tokenList is an ArrayList of TokenList objects, one per source line;
- // each ArrayList in tokenList consists of Token objects.
+ // sourceList is an ArrayList of String objects, one per source line.
+ // tokenList is an ArrayList of TokenList objects, one per source line;
+ // each ArrayList in tokenList consists of Token objects.
ArrayList sourceLineList = fileCurrentlyBeingAssembled.getSourceLineList();
- ArrayList tokenList = fileCurrentlyBeingAssembled.getTokenList();
- ArrayList parsedList = fileCurrentlyBeingAssembled.createParsedList();
- // each file keeps its own macro definitions
+ ArrayList tokenList = fileCurrentlyBeingAssembled.getTokenList();
+ ArrayList parsedList = fileCurrentlyBeingAssembled.createParsedList();
+ // each file keeps its own macro definitions
MacroPool macroPool = fileCurrentlyBeingAssembled.createMacroPool();
- // FIRST PASS OF ASSEMBLER VERIFIES SYNTAX, GENERATES SYMBOL TABLE,
- // INITIALIZES DATA SEGMENT
+ // FIRST PASS OF ASSEMBLER VERIFIES SYNTAX, GENERATES SYMBOL TABLE,
+ // INITIALIZES DATA SEGMENT
ArrayList statements;
for (int i = 0; i < tokenList.size(); i++) {
- if (errors.errorLimitExceeded())
- break;
- for (int z=0; z<((TokenList)tokenList.get(i)).size(); z++) {
- Token t = ((TokenList) tokenList.get(i)).get(z);
- // record this token's original source program and line #. Differs from final, if .include used
- t.setOriginal(sourceLineList.get(i).getMIPSprogram(),sourceLineList.get(i).getLineNumber());
- }
- statements = this.parseLine((TokenList) tokenList.get(i),
- sourceLineList.get(i).getSource(),
- sourceLineList.get(i).getLineNumber(),
- extendedAssemblerEnabled);
- if (statements != null) {
- parsedList.addAll(statements);
- }
+ if (errors.errorLimitExceeded())
+ break;
+ for (int z = 0; z < tokenList.get(i).size(); z++) {
+ Token t = tokenList.get(i).get(z);
+ // record this token's original source program and line #. Differs from final, if .include used
+ t.setOriginal(sourceLineList.get(i).getMIPSprogram(), sourceLineList.get(i).getLineNumber());
+ }
+ statements = this.parseLine(tokenList.get(i),
+ sourceLineList.get(i).getSource(),
+ sourceLineList.get(i).getLineNumber(),
+ extendedAssemblerEnabled);
+ if (statements != null) {
+ parsedList.addAll(statements);
+ }
}
if (inMacroSegment) {
- errors.add(new ErrorMessage(fileCurrentlyBeingAssembled,
- fileCurrentlyBeingAssembled.getLocalMacroPool().getCurrent().getFromLine(),
- 0, "Macro started but not ended (no .end_macro directive)"));
+ errors.add(new ErrorMessage(fileCurrentlyBeingAssembled,
+ fileCurrentlyBeingAssembled.getLocalMacroPool().getCurrent().getFromLine(),
+ 0, "Macro started but not ended (no .end_macro directive)"));
}
- // move ".globl" symbols from local symtab to global
+ // move ".globl" symbols from local symtab to global
this.transferGlobals();
- // Attempt to resolve forward label references that were discovered in operand fields
- // of data segment directives in current file. Those that are not resolved after this
- // call are either references to global labels not seen yet, or are undefined.
- // Cannot determine which until all files are parsed, so copy unresolved entries
- // into accumulated list and clear out this one for re-use with the next source file.
+ // Attempt to resolve forward label references that were discovered in operand fields
+ // of data segment directives in current file. Those that are not resolved after this
+ // call are either references to global labels not seen yet, or are undefined.
+ // Cannot determine which until all files are parsed, so copy unresolved entries
+ // into accumulated list and clear out this one for re-use with the next source file.
currentFileDataSegmentForwardReferences.resolve(fileCurrentlyBeingAssembled
- .getLocalSymbolTable());
+ .getLocalSymbolTable());
accumulatedDataSegmentForwardReferences.add(currentFileDataSegmentForwardReferences);
currentFileDataSegmentForwardReferences.clear();
- } // end of first-pass loop for each MIPSprogram
-
-
-
- // Have processed all source files. Attempt to resolve any remaining forward label
- // references from global symbol table. Those that remain unresolved are undefined
- // and require error message.
- accumulatedDataSegmentForwardReferences.resolve(Globals.symbolTable);
- accumulatedDataSegmentForwardReferences.generateErrorMessages(errors);
-
- // Throw collection of errors accumulated through the first pass.
- if (errors.errorsOccurred()) {
+ } // end of first-pass loop for each MIPSprogram
+
+ // Have processed all source files. Attempt to resolve any remaining forward label
+ // references from global symbol table. Those that remain unresolved are undefined
+ // and require error message.
+ accumulatedDataSegmentForwardReferences.resolve(Globals.symbolTable);
+ accumulatedDataSegmentForwardReferences.generateErrorMessages(errors);
+
+ // Throw collection of errors accumulated through the first pass.
+ if (errors.errorsOccurred()) {
throw new ProcessingException(errors);
- }
- if (Globals.debug)
+ }
+ if (Globals.debug)
System.out.println("Assembler second pass begins");
- // SECOND PASS OF ASSEMBLER GENERATES BASIC ASSEMBLER THEN MACHINE CODE.
- // Generates basic assembler statements...
- for (int fileIndex = 0; fileIndex < tokenizedProgramFiles.size(); fileIndex++) {
+ // SECOND PASS OF ASSEMBLER GENERATES BASIC ASSEMBLER THEN MACHINE CODE.
+ // Generates basic assembler statements...
+ for (int fileIndex = 0; fileIndex < tokenizedProgramFiles.size(); fileIndex++) {
if (errors.errorLimitExceeded())
- break;
- this.fileCurrentlyBeingAssembled = (MIPSprogram) tokenizedProgramFiles.get(fileIndex);
- ArrayList parsedList = fileCurrentlyBeingAssembled.getParsedList();
+ break;
+ this.fileCurrentlyBeingAssembled = tokenizedProgramFiles.get(fileIndex);
+ ArrayList parsedList = fileCurrentlyBeingAssembled.getParsedList();
ProgramStatement statement;
for (int i = 0; i < parsedList.size(); i++) {
- statement = (ProgramStatement) parsedList.get(i);
- statement.buildBasicStatementFromBasicInstruction(errors);
- if (errors.errorsOccurred()) {
- throw new ProcessingException(errors);
- }
- if (statement.getInstruction() instanceof BasicInstruction) {
- this.machineList.add(statement);
- }
- else {
- // It is a pseudo-instruction:
- // 1. Fetch its basic instruction template list
- // 2. For each template in the list,
- // 2a. substitute operands from source statement
- // 2b. tokenize the statement generated by 2a.
- // 2d. call parseLine() to generate basic instrction
- // 2e. add returned programStatement to the list
- // The templates, and the instructions generated by filling
- // in the templates, are specified
- // in basic format (e.g. mnemonic register reference $zero
- // already translated to $0).
- // So the values substituted into the templates need to be
- // in this format. Since those
- // values come from the original source statement, they need
- // to be translated before
- // substituting. The next method call will perform this
- // translation on the original
- // source statement. Despite the fact that the original
- // statement is a pseudo
- // instruction, this method performs the necessary
- // translation correctly.
- ExtendedInstruction inst = (ExtendedInstruction) statement.getInstruction();
- String basicAssembly = statement.getBasicAssemblyStatement();
- int sourceLine = statement.getSourceLine();
- TokenList theTokenList = new Tokenizer().tokenizeLine(sourceLine,
- basicAssembly, errors, false);
-
- // ////////////////////////////////////////////////////////////////////////////
- // If we are using compact memory config and there is a compact expansion, use it
- ArrayList templateList;
- if (compactTranslationCanBeApplied(statement)) {
- templateList = inst.getCompactBasicIntructionTemplateList();
- }
- else {
- templateList = inst.getBasicIntructionTemplateList();
- }
-
- // subsequent ProgramStatement constructor needs the correct text segment address.
- textAddress.set(statement.getAddress());
- // Will generate one basic instruction for each template in the list.
- for (int instrNumber = 0; instrNumber < templateList.size(); instrNumber++) {
- String instruction = ExtendedInstruction.makeTemplateSubstitutions(
- this.fileCurrentlyBeingAssembled,
- (String) templateList.get(instrNumber), theTokenList);
- // 23 Jan 2008 by DPS. Template substitution may result in no instruction.
- // If this is the case, skip remainder of loop iteration. This should only
- // happen if template substitution was for "nop" instruction but delayed branching
- // is disabled so the "nop" is not generated.
- if (instruction == null || instruction == "") {
- continue;
- }
-
- // All substitutions have been made so we have generated
- // a valid basic instruction!
- if (Globals.debug)
- System.out.println("PSEUDO generated: " + instruction);
- // For generated instruction: tokenize, build program
- // statement, add to list.
- TokenList newTokenList = new Tokenizer().tokenizeLine(sourceLine,
- instruction, errors,false);
- ArrayList instrMatches = this.matchInstruction(newTokenList.get(0));
- Instruction instr = OperandFormat.bestOperandMatch(newTokenList,
- instrMatches);
- // Only first generated instruction is linked to original source
- ProgramStatement ps = new ProgramStatement(
- this.fileCurrentlyBeingAssembled,
- (instrNumber == 0) ? statement.getSource() : "", newTokenList,
- newTokenList, instr, textAddress.get(), statement.getSourceLine());
- textAddress.increment(Instruction.INSTRUCTION_LENGTH);
- ps.buildBasicStatementFromBasicInstruction(errors);
- this.machineList.add(ps);
- } // end of FOR loop, repeated for each template in list.
- } // end of ELSE part for extended instruction.
-
+ statement = parsedList.get(i);
+ statement.buildBasicStatementFromBasicInstruction(errors);
+ if (errors.errorsOccurred()) {
+ throw new ProcessingException(errors);
+ }
+ if (statement.getInstruction() instanceof BasicInstruction) {
+ this.machineList.add(statement);
+ } else {
+ // It is a pseudo-instruction:
+ // 1. Fetch its basic instruction template list
+ // 2. For each template in the list,
+ // 2a. substitute operands from source statement
+ // 2b. tokenize the statement generated by 2a.
+ // 2d. call parseLine() to generate basic instrction
+ // 2e. add returned programStatement to the list
+ // The templates, and the instructions generated by filling
+ // in the templates, are specified
+ // in basic format (e.g. mnemonic register reference $zero
+ // already translated to $0).
+ // So the values substituted into the templates need to be
+ // in this format. Since those
+ // values come from the original source statement, they need
+ // to be translated before
+ // substituting. The next method call will perform this
+ // translation on the original
+ // source statement. Despite the fact that the original
+ // statement is a pseudo
+ // instruction, this method performs the necessary
+ // translation correctly.
+ ExtendedInstruction inst = (ExtendedInstruction) statement.getInstruction();
+ String basicAssembly = statement.getBasicAssemblyStatement();
+ int sourceLine = statement.getSourceLine();
+ TokenList theTokenList = new Tokenizer().tokenizeLine(sourceLine,
+ basicAssembly, errors, false);
+
+ // ////////////////////////////////////////////////////////////////////////////
+ // If we are using compact memory config and there is a compact expansion, use it
+ ArrayList templateList;
+ if (compactTranslationCanBeApplied(statement)) {
+ templateList = inst.getCompactBasicIntructionTemplateList();
+ } else {
+ templateList = inst.getBasicIntructionTemplateList();
+ }
+
+ // subsequent ProgramStatement constructor needs the correct text segment address.
+ textAddress.set(statement.getAddress());
+ // Will generate one basic instruction for each template in the list.
+ for (int instrNumber = 0; instrNumber < templateList.size(); instrNumber++) {
+ String instruction = ExtendedInstruction.makeTemplateSubstitutions(
+ this.fileCurrentlyBeingAssembled,
+ templateList.get(instrNumber), theTokenList);
+ // 23 Jan 2008 by DPS. Template substitution may result in no instruction.
+ // If this is the case, skip remainder of loop iteration. This should only
+ // happen if template substitution was for "nop" instruction but delayed branching
+ // is disabled so the "nop" is not generated.
+ if (instruction == null || instruction == "") {
+ continue;
+ }
+
+ // All substitutions have been made so we have generated
+ // a valid basic instruction!
+ if (Globals.debug)
+ System.out.println("PSEUDO generated: " + instruction);
+ // For generated instruction: tokenize, build program
+ // statement, add to list.
+ TokenList newTokenList = new Tokenizer().tokenizeLine(sourceLine,
+ instruction, errors, false);
+ ArrayList instrMatches = this.matchInstruction(newTokenList.get(0));
+ Instruction instr = OperandFormat.bestOperandMatch(newTokenList,
+ instrMatches);
+ // Only first generated instruction is linked to original source
+ ProgramStatement ps = new ProgramStatement(
+ this.fileCurrentlyBeingAssembled,
+ (instrNumber == 0) ? statement.getSource() : "", newTokenList,
+ newTokenList, instr, textAddress.get(), statement.getSourceLine());
+ textAddress.increment(Instruction.INSTRUCTION_LENGTH);
+ ps.buildBasicStatementFromBasicInstruction(errors);
+ this.machineList.add(ps);
+ } // end of FOR loop, repeated for each template in list.
+ } // end of ELSE part for extended instruction.
+
} // end of assembler second pass.
- }
- if (Globals.debug)
+ }
+ if (Globals.debug)
System.out.println("Code generation begins");
- ///////////// THIRD MAJOR STEP IS PRODUCE MACHINE CODE FROM ASSEMBLY //////////
- // Generates machine code statements from the list of basic assembler statements
- // and writes the statement to memory.
- ProgramStatement statement;
- for (int i = 0; i < this.machineList.size(); i++) {
+ ///////////// THIRD MAJOR STEP IS PRODUCE MACHINE CODE FROM ASSEMBLY //////////
+ // Generates machine code statements from the list of basic assembler statements
+ // and writes the statement to memory.
+ ProgramStatement statement;
+ for (int i = 0; i < this.machineList.size(); i++) {
if (errors.errorLimitExceeded())
- break;
- statement = (ProgramStatement) this.machineList.get(i);
+ break;
+ statement = this.machineList.get(i);
statement.buildMachineStatementFromBasicStatement(errors);
if (Globals.debug)
- System.out.println(statement);
+ System.out.println(statement);
try {
- Globals.memory.setStatement(statement.getAddress(), statement);
- }
- catch (AddressErrorException e) {
- Token t = statement.getOriginalTokenList().get(0);
- errors.add(new ErrorMessage(t.getSourceMIPSprogram(), t.getSourceLine(), t
- .getStartPos(), "Invalid address for text segment: " + e.getAddress()));
- }
- }
- // Aug. 24, 2005 Ken Vollmar
- // Ensure that I/O "file descriptors" are initialized for a new program run
- SystemIO.resetFiles();
- // DPS 6 Dec 2006:
- // We will now sort the ArrayList of ProgramStatements by getAddress() value.
- // This is for display purposes, since they have already been stored to Memory.
- // Use of .ktext and .text with address operands has two implications:
- // (1) the addresses may not be ordered at this point. Requires unsigned int
- // sort because kernel addresses are negative. See special Comparator.
- // (2) It is possible for two instructions to be placed at the same address.
- // Such occurances will be flagged as errors.
- // Yes, I would not have to sort here if I used SortedSet rather than ArrayList
- // but in case of duplicate I like having both statements handy for error message.
- Collections.sort(this.machineList, new ProgramStatementComparator());
- catchDuplicateAddresses(this.machineList, errors);
- if (errors.errorsOccurred() || errors.warningsOccurred() && warningsAreErrors) {
+ Globals.memory.setStatement(statement.getAddress(), statement);
+ } catch (AddressErrorException e) {
+ Token t = statement.getOriginalTokenList().get(0);
+ errors.add(new ErrorMessage(t.getSourceMIPSprogram(), t.getSourceLine(), t
+ .getStartPos(), "Invalid address for text segment: " + e.getAddress()));
+ }
+ }
+ // Aug. 24, 2005 Ken Vollmar
+ // Ensure that I/O "file descriptors" are initialized for a new program run
+ SystemIO.resetFiles();
+ // DPS 6 Dec 2006:
+ // We will now sort the ArrayList of ProgramStatements by getAddress() value.
+ // This is for display purposes, since they have already been stored to Memory.
+ // Use of .ktext and .text with address operands has two implications:
+ // (1) the addresses may not be ordered at this point. Requires unsigned int
+ // sort because kernel addresses are negative. See special Comparator.
+ // (2) It is possible for two instructions to be placed at the same address.
+ // Such occurances will be flagged as errors.
+ // Yes, I would not have to sort here if I used SortedSet rather than ArrayList
+ // but in case of duplicate I like having both statements handy for error message.
+ Collections.sort(this.machineList, new ProgramStatementComparator());
+ catchDuplicateAddresses(this.machineList, errors);
+ if (errors.errorsOccurred() || errors.warningsOccurred() && warningsAreErrors) {
throw new ProcessingException(errors);
- }
- return this.machineList;
- } // assemble()
-
- // //////////////////////////////////////////////////////////////////////
- // Will check for duplicate text addresses, which can happen inadvertantly when using
- // operand on .text directive. Will generate error message for each one that occurs.
- private void catchDuplicateAddresses(ArrayList instructions, ErrorList errors) {
- for (int i = 0; i < instructions.size() - 1; i++) {
- ProgramStatement ps1 = (ProgramStatement) instructions.get(i);
- ProgramStatement ps2 = (ProgramStatement) instructions.get(i + 1);
+ }
+ return this.machineList;
+ } // assemble()
+
+ // //////////////////////////////////////////////////////////////////////
+ // Will check for duplicate text addresses, which can happen inadvertantly when using
+ // operand on .text directive. Will generate error message for each one that occurs.
+ private void catchDuplicateAddresses(ArrayList instructions, ErrorList errors) {
+ for (int i = 0; i < instructions.size() - 1; i++) {
+ ProgramStatement ps1 = instructions.get(i);
+ ProgramStatement ps2 = instructions.get(i + 1);
if (ps1.getAddress() == ps2.getAddress()) {
- errors.add(new ErrorMessage(ps2.getSourceMIPSprogram(), ps2.getSourceLine(), 0,
- "Duplicate text segment address: "
- + mars.venus.NumberDisplayBaseChooser.formatUnsignedInteger(ps2
- .getAddress(), (Globals.getSettings()
- .getDisplayAddressesInHex()) ? 16 : 10)
- + " already occupied by " + ps1.getSourceFile() + " line "
- + ps1.getSourceLine() + " (caused by use of "
- + ((Memory.inTextSegment(ps2.getAddress())) ? ".text" : ".ktext")
- + " operand)"));
+ errors.add(new ErrorMessage(ps2.getSourceMIPSprogram(), ps2.getSourceLine(), 0,
+ "Duplicate text segment address: "
+ + mars.venus.NumberDisplayBaseChooser.formatUnsignedInteger(ps2
+ .getAddress(), (Globals.getSettings()
+ .getDisplayAddressesInHex()) ? 16 : 10)
+ + " already occupied by " + ps1.getSourceFile() + " line "
+ + ps1.getSourceLine() + " (caused by use of "
+ + ((Memory.inTextSegment(ps2.getAddress())) ? ".text" : ".ktext")
+ + " operand)"));
}
- }
- }
-
- /**
- * This method parses one line of MIPS source code. It works with the list
- * of tokens, but original source is also provided. It also carries out
- * directives, which includes initializing the data segment. This method is
- * invoked in the assembler first pass.
- *
- * @param tokenList
- * @param source
- * @param sourceLineNumber
- * @param extendedAssemblerEnabled
- * @return ArrayList of ProgramStatements because parsing a macro expansion
- * request will return a list of ProgramStatements expanded
- */
- private ArrayList parseLine(TokenList tokenList, String source,
- int sourceLineNumber, boolean extendedAssemblerEnabled) {
-
- ArrayList ret = new ArrayList();
-
- ProgramStatement programStatement;
- TokenList tokens = this.stripComment(tokenList);
-
- // Labels should not be processed in macro definition segment.
- MacroPool macroPool = fileCurrentlyBeingAssembled.getLocalMacroPool();
- if (inMacroSegment) {
+ }
+ }
+
+ /**
+ * This method parses one line of MIPS source code. It works with the list
+ * of tokens, but original source is also provided. It also carries out
+ * directives, which includes initializing the data segment. This method is
+ * invoked in the assembler first pass.
+ *
+ * @param tokenList
+ * @param source
+ * @param sourceLineNumber
+ * @param extendedAssemblerEnabled
+ * @return ArrayList of ProgramStatements because parsing a macro expansion
+ * request will return a list of ProgramStatements expanded
+ */
+ private ArrayList parseLine(TokenList tokenList, String source,
+ int sourceLineNumber, boolean extendedAssemblerEnabled) {
+
+ ArrayList ret = new ArrayList<>();
+
+ ProgramStatement programStatement;
+ TokenList tokens = this.stripComment(tokenList);
+
+ // Labels should not be processed in macro definition segment.
+ MacroPool macroPool = fileCurrentlyBeingAssembled.getLocalMacroPool();
+ if (inMacroSegment) {
detectLabels(tokens, macroPool.getCurrent());
- }
- else {
+ } else {
stripLabels(tokens);
- }
- if (tokens.isEmpty())
+ }
+ if (tokens.isEmpty())
return null;
- // Grab first (operator) token...
- Token token = tokens.get(0);
- TokenTypes tokenType = token.getType();
-
- // Let's handle the directives here...
- if (tokenType == TokenTypes.DIRECTIVE) {
+ // Grab first (operator) token...
+ Token token = tokens.get(0);
+ TokenTypes tokenType = token.getType();
+
+ // Let's handle the directives here...
+ if (tokenType == TokenTypes.DIRECTIVE) {
this.executeDirective(tokens);
return null;
- }
-
- // don't parse if in macro segment
- if (inMacroSegment)
+ }
+
+ // don't parse if in macro segment
+ if (inMacroSegment)
return null;
-
- // SPIM-style macro calling:
- TokenList parenFreeTokens = tokens;
- if (tokens.size() > 2 && tokens.get(1).getType() == TokenTypes.LEFT_PAREN
- && tokens.get(tokens.size() - 1).getType() == TokenTypes.RIGHT_PAREN) {
+
+ // SPIM-style macro calling:
+ TokenList parenFreeTokens = tokens;
+ if (tokens.size() > 2 && tokens.get(1).getType() == TokenTypes.LEFT_PAREN
+ && tokens.get(tokens.size() - 1).getType() == TokenTypes.RIGHT_PAREN) {
parenFreeTokens = (TokenList) tokens.clone();
parenFreeTokens.remove(tokens.size() - 1);
parenFreeTokens.remove(1);
- }
- Macro macro = macroPool.getMatchingMacro(parenFreeTokens, sourceLineNumber);//parenFreeTokens.get(0).getSourceLine());
-
- // expand macro if this line is a macro expansion call
- if (macro != null) {
+ }
+ Macro macro = macroPool.getMatchingMacro(parenFreeTokens, sourceLineNumber);// parenFreeTokens.get(0).getSourceLine());
+
+ // expand macro if this line is a macro expansion call
+ if (macro != null) {
tokens = parenFreeTokens;
- // get unique id for this expansion
+ // get unique id for this expansion
int counter = macroPool.getNextCounter();
if (macroPool.pushOnCallStack(token)) {
- errors.add(new ErrorMessage(fileCurrentlyBeingAssembled, tokens.get(0)
- .getSourceLine(), 0, "Detected a macro expansion loop (recursive reference). "));
- }
- else {
- // for (int i = macro.getFromLine() + 1; i < macro.getToLine(); i++) {
- // String substituted = macro.getSubstitutedLine(i, tokens, counter, errors);
- // TokenList tokenList2 = fileCurrentlyBeingAssembled.getTokenizer().tokenizeLine(
- // i, substituted, errors);
- // // If token list getProcessedLine() is not empty, then .eqv was performed and it contains the modified source.
- // // Put it into the line to be parsed, so it will be displayed properly in text segment display. DPS 23 Jan 2013
- // if (tokenList2.getProcessedLine().length() > 0)
- // substituted = tokenList2.getProcessedLine();
- // // recursively parse lines of expanded macro
- // ArrayList statements = parseLine(tokenList2, "<" + (i-macro.getFromLine()+macro.getOriginalFromLine()) + "> "
- // + substituted.trim(), sourceLineNumber, extendedAssemblerEnabled);
- // if (statements != null)
- // ret.addAll(statements);
- // }
- for (int i = macro.getFromLine() + 1; i < macro.getToLine(); i++) {
-
- String substituted = macro.getSubstitutedLine(i, tokens, counter, errors);
- TokenList tokenList2 = fileCurrentlyBeingAssembled.getTokenizer().tokenizeLine(
- i, substituted, errors);
-
- // If token list getProcessedLine() is not empty, then .eqv was performed and it contains the modified source.
- // Put it into the line to be parsed, so it will be displayed properly in text segment display. DPS 23 Jan 2013
- if (tokenList2.getProcessedLine().length() > 0)
- substituted = tokenList2.getProcessedLine();
-
- // recursively parse lines of expanded macro
- ArrayList statements = parseLine(tokenList2, "<" + (i-macro.getFromLine()+macro.getOriginalFromLine()) + "> "
- + substituted.trim(), sourceLineNumber, extendedAssemblerEnabled);
- if (statements != null)
- ret.addAll(statements);
- }
- macroPool.popFromCallStack();
+ errors.add(new ErrorMessage(fileCurrentlyBeingAssembled, tokens.get(0)
+ .getSourceLine(), 0, "Detected a macro expansion loop (recursive reference). "));
+ } else {
+ // for (int i = macro.getFromLine() + 1; i < macro.getToLine(); i++) {
+ // String substituted = macro.getSubstitutedLine(i, tokens, counter, errors);
+ // TokenList tokenList2 =
+ // fileCurrentlyBeingAssembled.getTokenizer().tokenizeLine(
+ // i, substituted, errors);
+ // // If token list getProcessedLine() is not empty, then .eqv was performed and
+ // it contains the modified source.
+ // // Put it into the line to be parsed, so it will be displayed properly in text
+ // segment display. DPS 23 Jan 2013
+ // if (tokenList2.getProcessedLine().length() > 0)
+ // substituted = tokenList2.getProcessedLine();
+ // // recursively parse lines of expanded macro
+ // ArrayList statements = parseLine(tokenList2, "<" + (i -
+ // macro.getFromLine() + macro.getOriginalFromLine()) + "> "
+ // + substituted.trim(), sourceLineNumber, extendedAssemblerEnabled);
+ // if (statements != null)
+ // ret.addAll(statements);
+ // }
+ for (int i = macro.getFromLine() + 1; i < macro.getToLine(); i++) {
+
+ String substituted = macro.getSubstitutedLine(i, tokens, counter, errors);
+ TokenList tokenList2 = fileCurrentlyBeingAssembled.getTokenizer().tokenizeLine(
+ i, substituted, errors);
+
+ // If token list getProcessedLine() is not empty, then .eqv was performed and it
+ // contains the modified source.
+ // Put it into the line to be parsed, so it will be displayed properly in text
+ // segment display. DPS 23 Jan 2013
+ if (tokenList2.getProcessedLine().length() > 0)
+ substituted = tokenList2.getProcessedLine();
+
+ // recursively parse lines of expanded macro
+ ArrayList statements = parseLine(tokenList2, "<"
+ + (i - macro.getFromLine() + macro.getOriginalFromLine()) + "> "
+ + substituted.trim(), sourceLineNumber, extendedAssemblerEnabled);
+ if (statements != null)
+ ret.addAll(statements);
+ }
+ macroPool.popFromCallStack();
}
return ret;
- }
-
- // DPS 14-July-2008
- // Yet Another Hack: detect unrecognized directive. MARS recognizes the same directives
- // as SPIM but other MIPS assemblers recognize additional directives. Compilers such
- // as MIPS-directed GCC generate assembly code containing these directives. We'd like
- // the opportunity to ignore them and continue. Tokenizer would categorize an unrecognized
- // directive as an TokenTypes.IDENTIFIER because it would not be matched as a directive and
- // MIPS labels can start with '.' NOTE: this can also be handled by including the
- // ignored directive in the Directives.java list. There is already a mechanism in place
- // for generating a warning there. But I cannot anticipate the names of all directives
- // so this will catch anything, including a misspelling of a valid directive (which is
- // a nice thing to do).
- if (tokenType == TokenTypes.IDENTIFIER && token.getValue().charAt(0) == '.') {
+ }
+
+ // DPS 14-July-2008
+ // Yet Another Hack: detect unrecognized directive. MARS recognizes the same directives
+ // as SPIM but other MIPS assemblers recognize additional directives. Compilers such
+ // as MIPS-directed GCC generate assembly code containing these directives. We'd like
+ // the opportunity to ignore them and continue. Tokenizer would categorize an unrecognized
+ // directive as an TokenTypes.IDENTIFIER because it would not be matched as a directive and
+ // MIPS labels can start with '.' NOTE: this can also be handled by including the
+ // ignored directive in the Directives.java list. There is already a mechanism in place
+ // for generating a warning there. But I cannot anticipate the names of all directives
+ // so this will catch anything, including a misspelling of a valid directive (which is
+ // a nice thing to do).
+ if (tokenType == TokenTypes.IDENTIFIER && token.getValue().charAt(0) == '.') {
errors.add(new ErrorMessage(ErrorMessage.WARNING, token.getSourceMIPSprogram(), token
- .getSourceLine(), token.getStartPos(), "MARS does not recognize the "
- + token.getValue() + " directive. Ignored."));
+ .getSourceLine(), token.getStartPos(), "MARS does not recognize the "
+ + token.getValue() + " directive. Ignored."));
return null;
- }
-
- // The directives with lists (.byte, .double, .float, .half, .word, .ascii, .asciiz)
- // should be able to extend the list over several lines. Since this method assembles
- // only one source line, state information must be stored from one invocation to
- // the next, to sense the context of this continuation line. That state information
- // is contained in this.dataDirective (the current data directive).
- //
- if (this.inDataSegment && // 30-Dec-09 DPS Added data segment guard...
- (tokenType == TokenTypes.PLUS
- || // because invalid instructions were being caught...
- tokenType == TokenTypes.MINUS
- || // here and reported as a directive in text segment!
- tokenType == TokenTypes.QUOTED_STRING || tokenType == TokenTypes.IDENTIFIER
- || TokenTypes.isIntegerTokenType(tokenType) || TokenTypes
- .isFloatingTokenType(tokenType))) {
+ }
+
+ // The directives with lists (.byte, .double, .float, .half, .word, .ascii, .asciiz)
+ // should be able to extend the list over several lines. Since this method assembles
+ // only one source line, state information must be stored from one invocation to
+ // the next, to sense the context of this continuation line. That state information
+ // is contained in this.dataDirective (the current data directive).
+ //
+ if (this.inDataSegment && // 30-Dec-09 DPS Added data segment guard...
+ (tokenType == TokenTypes.PLUS
+ || // because invalid instructions were being caught...
+ tokenType == TokenTypes.MINUS
+ || // here and reported as a directive in text segment!
+ tokenType == TokenTypes.QUOTED_STRING || tokenType == TokenTypes.IDENTIFIER
+ || TokenTypes.isIntegerTokenType(tokenType) || TokenTypes
+ .isFloatingTokenType(tokenType))) {
this.executeDirectiveContinuation(tokens);
return null;
- }
-
- // If we are in the text segment, the variable "token" must now refer to
- // an OPERATOR
- // token. If not, it is either a syntax error or the specified operator
- // is not
- // yet implemented.
- if (!this.inDataSegment) {
- ArrayList instrMatches = this.matchInstruction(token);
+ }
+
+ // If we are in the text segment, the variable "token" must now refer to
+ // an OPERATOR
+ // token. If not, it is either a syntax error or the specified operator
+ // is not
+ // yet implemented.
+ if (!this.inDataSegment) {
+ ArrayList instrMatches = this.matchInstruction(token);
if (instrMatches == null)
- return ret;
- // OK, we've got an operator match, let's check the operands.
+ return ret;
+ // OK, we've got an operator match, let's check the operands.
Instruction inst = OperandFormat.bestOperandMatch(tokens, instrMatches);
- // Here's the place to flag use of extended (pseudo) instructions
- // when setting disabled.
+ // Here's the place to flag use of extended (pseudo) instructions
+ // when setting disabled.
if (inst instanceof ExtendedInstruction && !extendedAssemblerEnabled) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(),
- "Extended (pseudo) instruction or format not permitted. See Settings."));
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(),
+ "Extended (pseudo) instruction or format not permitted. See Settings."));
}
if (OperandFormat.tokenOperandMatch(tokens, inst, errors)) {
- programStatement = new ProgramStatement(this.fileCurrentlyBeingAssembled, source,
- tokenList, tokens, inst, textAddress.get(), sourceLineNumber);
- // instruction length is 4 for all basic instruction, varies for extended instruction
- // Modified to permit use of compact expansion if address fits
- // in 15 bits. DPS 4-Aug-2009
- int instLength = inst.getInstructionLength();
- if (compactTranslationCanBeApplied(programStatement)) {
- instLength = ((ExtendedInstruction) inst).getCompactInstructionLength();
- }
- textAddress.increment(instLength);
- ret.add(programStatement);
- return ret;
+ programStatement = new ProgramStatement(this.fileCurrentlyBeingAssembled, source,
+ tokenList, tokens, inst, textAddress.get(), sourceLineNumber);
+ // instruction length is 4 for all basic instruction, varies for extended instruction
+ // Modified to permit use of compact expansion if address fits
+ // in 15 bits. DPS 4-Aug-2009
+ int instLength = inst.getInstructionLength();
+ if (compactTranslationCanBeApplied(programStatement)) {
+ instLength = ((ExtendedInstruction) inst).getCompactInstructionLength();
+ }
+ textAddress.increment(instLength);
+ ret.add(programStatement);
+ return ret;
}
- }
- return null;
- } // parseLine()
-
- private void detectLabels(TokenList tokens, Macro current) {
- if (tokenListBeginsWithLabel(tokens))
+ }
+ return null;
+ } // parseLine()
+
+ private void detectLabels(TokenList tokens, Macro current) {
+ if (tokenListBeginsWithLabel(tokens))
current.addLabel(tokens.get(0).getValue());
- }
-
- // Determine whether or not a compact (16-bit) translation from
- // pseudo-instruction to basic instruction can be applied. If
- // the argument is a basic instruction, obviously not. If an
- // extended instruction, we have to be operating under a 16-bit
- // memory model and the instruction has to have defined an
- // alternate compact translation.
- private boolean compactTranslationCanBeApplied(ProgramStatement statement) {
- return (statement.getInstruction() instanceof ExtendedInstruction
- && Globals.memory.usingCompactMemoryConfiguration() && ((ExtendedInstruction) statement
- .getInstruction()).hasCompactTranslation());
- }
-
- // //////////////////////////////////////////////////////////////////////////////////
- // Pre-process the token list for a statement by stripping off any comment.
- // NOTE: the ArrayList parameter is not modified; a new one is cloned and
- // returned.
- private TokenList stripComment(TokenList tokenList) {
- if (tokenList.isEmpty())
+ }
+
+ // Determine whether or not a compact (16-bit) translation from
+ // pseudo-instruction to basic instruction can be applied. If
+ // the argument is a basic instruction, obviously not. If an
+ // extended instruction, we have to be operating under a 16-bit
+ // memory model and the instruction has to have defined an
+ // alternate compact translation.
+ private boolean compactTranslationCanBeApplied(ProgramStatement statement) {
+ return (statement.getInstruction() instanceof ExtendedInstruction
+ && Globals.memory.usingCompactMemoryConfiguration() && ((ExtendedInstruction) statement
+ .getInstruction()).hasCompactTranslation());
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // Pre-process the token list for a statement by stripping off any comment.
+ // NOTE: the ArrayList parameter is not modified; a new one is cloned and
+ // returned.
+ private TokenList stripComment(TokenList tokenList) {
+ if (tokenList.isEmpty())
return tokenList;
- TokenList tokens = (TokenList) tokenList.clone();
- // If there is a comment, strip it off.
- int last = tokens.size() - 1;
- if (tokens.get(last).getType() == TokenTypes.COMMENT) {
+ TokenList tokens = (TokenList) tokenList.clone();
+ // If there is a comment, strip it off.
+ int last = tokens.size() - 1;
+ if (tokens.get(last).getType() == TokenTypes.COMMENT) {
tokens.remove(last);
- }
- return tokens;
- } // stripComment()
-
- /**
- * Pre-process the token list for a statement by stripping off any label, if
- * either are present. Any label definition will be recorded in the symbol
- * table. NOTE: the ArrayList parameter will be modified.
- */
- private void stripLabels(TokenList tokens) {
- // If there is a label, handle it here and strip it off.
- boolean thereWasLabel = this.parseAndRecordLabel(tokens);
- if (thereWasLabel) {
+ }
+ return tokens;
+ } // stripComment()
+
+ /**
+ * Pre-process the token list for a statement by stripping off any label, if
+ * either are present. Any label definition will be recorded in the symbol
+ * table. NOTE: the ArrayList parameter will be modified.
+ */
+ private void stripLabels(TokenList tokens) {
+ // If there is a label, handle it here and strip it off.
+ boolean thereWasLabel = this.parseAndRecordLabel(tokens);
+ if (thereWasLabel) {
tokens.remove(0); // Remove the IDENTIFIER.
tokens.remove(0); // Remove the COLON, shifted to 0 by previous remove
- }
- }
-
- // //////////////////////////////////////////////////////////////////////////////////
- // Parse and record label, if there is one. Note the identifier and its colon are
- // two separate tokens, since they may be separated by spaces in source code.
- private boolean parseAndRecordLabel(TokenList tokens) {
- if (tokens.size() < 2) {
+ }
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // Parse and record label, if there is one. Note the identifier and its colon are
+ // two separate tokens, since they may be separated by spaces in source code.
+ private boolean parseAndRecordLabel(TokenList tokens) {
+ if (tokens.size() < 2) {
return false;
- }
- else {
+ } else {
Token token = tokens.get(0);
if (tokenListBeginsWithLabel(tokens)) {
- if (token.getType() == TokenTypes.OPERATOR) {
- // an instruction name was used as label (e.g. lw:), so change its token type
- token.setType(TokenTypes.IDENTIFIER);
- }
- fileCurrentlyBeingAssembled.getLocalSymbolTable().addSymbol(token,
- (this.inDataSegment) ? dataAddress.get() : textAddress.get(),
- this.inDataSegment, this.errors);
- return true;
- }
- else {
- return false;
+ if (token.getType() == TokenTypes.OPERATOR) {
+ // an instruction name was used as label (e.g. lw:), so change its token type
+ token.setType(TokenTypes.IDENTIFIER);
+ }
+ fileCurrentlyBeingAssembled.getLocalSymbolTable().addSymbol(token,
+ (this.inDataSegment) ? dataAddress.get() : textAddress.get(),
+ this.inDataSegment, this.errors);
+ return true;
+ } else {
+ return false;
}
- }
- } // parseLabel()
-
- private boolean tokenListBeginsWithLabel(TokenList tokens) {
- // 2-July-2010. DPS. Remove prohibition of operator names as labels
- if (tokens.size() < 2)
+ }
+ } // parseLabel()
+
+ private boolean tokenListBeginsWithLabel(TokenList tokens) {
+ // 2-July-2010. DPS. Remove prohibition of operator names as labels
+ if (tokens.size() < 2)
return false;
- return (tokens.get(0).getType() == TokenTypes.IDENTIFIER || tokens.get(0).getType() == TokenTypes.OPERATOR)
- && tokens.get(1).getType() == TokenTypes.COLON;
- }
-
- // //////////////////////////////////////////////////////////////////////////////////
- // This source code line is a directive, not a MIPS instruction. Let's carry it out.
- private void executeDirective(TokenList tokens) {
- Token token = tokens.get(0);
- Directives direct = Directives.matchDirective(token.getValue());
- if (Globals.debug)
+ return (tokens.get(0).getType() == TokenTypes.IDENTIFIER || tokens.get(0).getType() == TokenTypes.OPERATOR)
+ && tokens.get(1).getType() == TokenTypes.COLON;
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // This source code line is a directive, not a MIPS instruction. Let's carry it out.
+ private void executeDirective(TokenList tokens) {
+ Token token = tokens.get(0);
+ Directives direct = Directives.matchDirective(token.getValue());
+ if (Globals.debug)
System.out.println("line " + token.getSourceLine() + " is directive " + direct);
- if (direct == null) {
+ if (direct == null) {
errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token
- .getStartPos(), "\"" + token.getValue()
- + "\" directive is invalid or not implemented in MARS"));
+ .getStartPos(), "\"" + token.getValue()
+ + "\" directive is invalid or not implemented in MARS"));
return;
- }
- else if (direct == Directives.EQV) { /* EQV added by DPS 11 July 2012 */
- // Do nothing. This was vetted and processed during tokenizing.
- }
- else if (direct == Directives.MACRO) {
+ } else if (direct == Directives.EQV) { /* EQV added by DPS 11 July 2012 */
+ // Do nothing. This was vetted and processed during tokenizing.
+ } else if (direct == Directives.MACRO) {
if (tokens.size() < 2) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "\"" + token.getValue()
- + "\" directive requires at least one argument."));
- return;
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "\"" + token.getValue()
+ + "\" directive requires at least one argument."));
+ return;
}
if (tokens.get(1).getType() != TokenTypes.IDENTIFIER) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- tokens.get(1).getStartPos(), "Invalid Macro name \""
- + tokens.get(1).getValue() + "\""));
- return;
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ tokens.get(1).getStartPos(), "Invalid Macro name \""
+ + tokens.get(1).getValue() + "\""));
+ return;
}
if (inMacroSegment) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "Nested macros are not allowed"));
- return;
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "Nested macros are not allowed"));
+ return;
}
inMacroSegment = true;
MacroPool pool = fileCurrentlyBeingAssembled.getLocalMacroPool();
pool.beginMacro(tokens.get(1));
for (int i = 2; i < tokens.size(); i++) {
- Token arg = tokens.get(i);
- if (arg.getType() == TokenTypes.RIGHT_PAREN
- || arg.getType() == TokenTypes.LEFT_PAREN)
- continue;
- if (!Macro.tokenIsMacroParameter(arg.getValue(), true)) {
- errors.add(new ErrorMessage(arg.getSourceMIPSprogram(), arg.getSourceLine(),
- arg.getStartPos(), "Invalid macro argument '" + arg.getValue() + "'"));
- return;
- }
- pool.getCurrent().addArg(arg.getValue());
+ Token arg = tokens.get(i);
+ if (arg.getType() == TokenTypes.RIGHT_PAREN
+ || arg.getType() == TokenTypes.LEFT_PAREN)
+ continue;
+ if (!Macro.tokenIsMacroParameter(arg.getValue(), true)) {
+ errors.add(new ErrorMessage(arg.getSourceMIPSprogram(), arg.getSourceLine(),
+ arg.getStartPos(), "Invalid macro argument '" + arg.getValue() + "'"));
+ return;
+ }
+ pool.getCurrent().addArg(arg.getValue());
}
- }
- else if (direct == Directives.END_MACRO) {
+ } else if (direct == Directives.END_MACRO) {
if (tokens.size() > 1) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "invalid text after .END_MACRO"));
- return;
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "invalid text after .END_MACRO"));
+ return;
}
if (!inMacroSegment) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), ".END_MACRO without .MACRO"));
- return;
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), ".END_MACRO without .MACRO"));
+ return;
}
inMacroSegment = false;
fileCurrentlyBeingAssembled.getLocalMacroPool().commitMacro(token);
- }
- else if (inMacroSegment) {
- // should not parse lines even directives in macro segment
+ } else if (inMacroSegment) {
+ // should not parse lines even directives in macro segment
return;
- }
- else if (direct == Directives.DATA || direct == Directives.KDATA) {
+ } else if (direct == Directives.DATA || direct == Directives.KDATA) {
this.inDataSegment = true;
this.autoAlign = true;
this.dataAddress.setAddressSpace((direct == Directives.DATA) ? this.dataAddress.USER
- : this.dataAddress.KERNEL);
+ : this.dataAddress.KERNEL);
if (tokens.size() > 1 && TokenTypes.isIntegerTokenType(tokens.get(1).getType())) {
- this.dataAddress.set(Binary.stringToInt(tokens.get(1).getValue())); // KENV 1/6/05
+ this.dataAddress.set(Binary.stringToInt(tokens.get(1).getValue())); // KENV 1/6/05
}
- }
- else if (direct == Directives.TEXT || direct == Directives.KTEXT) {
+ } else if (direct == Directives.TEXT || direct == Directives.KTEXT) {
this.inDataSegment = false;
this.textAddress.setAddressSpace((direct == Directives.TEXT) ? this.textAddress.USER
- : this.textAddress.KERNEL);
+ : this.textAddress.KERNEL);
if (tokens.size() > 1 && TokenTypes.isIntegerTokenType(tokens.get(1).getType())) {
- this.textAddress.set(Binary.stringToInt(tokens.get(1).getValue())); // KENV 1/6/05
+ this.textAddress.set(Binary.stringToInt(tokens.get(1).getValue())); // KENV 1/6/05
}
- }
- else if (direct == Directives.WORD || direct == Directives.HALF
- || direct == Directives.BYTE || direct == Directives.FLOAT
- || direct == Directives.DOUBLE) {
+ } else if (direct == Directives.WORD || direct == Directives.HALF
+ || direct == Directives.BYTE || direct == Directives.FLOAT
+ || direct == Directives.DOUBLE) {
this.dataDirective = direct;
if (passesDataSegmentCheck(token) && tokens.size() > 1) { // DPS
- // 11/20/06, added text segment prohibition
- storeNumeric(tokens, direct, errors);
+ // 11/20/06, added text segment prohibition
+ storeNumeric(tokens, direct, errors);
}
- }
- else if (direct == Directives.ASCII || direct == Directives.ASCIIZ) {
+ } else if (direct == Directives.ASCII || direct == Directives.ASCIIZ) {
this.dataDirective = direct;
if (passesDataSegmentCheck(token)) {
- storeStrings(tokens, direct, errors);
+ storeStrings(tokens, direct, errors);
}
- }
- else if (direct == Directives.ALIGN) {
+ } else if (direct == Directives.ALIGN) {
if (passesDataSegmentCheck(token)) {
- if (tokens.size() != 2) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
- token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
- + "\" requires one operand"));
- return;
- }
- if (!TokenTypes.isIntegerTokenType(tokens.get(1).getType())
- || Binary.stringToInt(tokens.get(1).getValue()) < 0) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
- token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
- + "\" requires a non-negative integer"));
- return;
- }
- int value = Binary.stringToInt(tokens.get(1).getValue()); // KENV 1/6/05
- if (value == 0) {
- this.autoAlign = false;
- }
- else {
- this.dataAddress.set(this.alignToBoundary(this.dataAddress.get(),
- (int) Math.pow(2, value)));
- }
+ if (tokens.size() != 2) {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
+ token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
+ + "\" requires one operand"));
+ return;
+ }
+ if (!TokenTypes.isIntegerTokenType(tokens.get(1).getType())
+ || Binary.stringToInt(tokens.get(1).getValue()) < 0) {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
+ token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
+ + "\" requires a non-negative integer"));
+ return;
+ }
+ int value = Binary.stringToInt(tokens.get(1).getValue()); // KENV 1/6/05
+ if (value == 0) {
+ this.autoAlign = false;
+ } else {
+ this.dataAddress.set(this.alignToBoundary(this.dataAddress.get(),
+ (int) Math.pow(2, value)));
+ }
}
- }
- else if (direct == Directives.SPACE) {
+ } else if (direct == Directives.SPACE) {
if (passesDataSegmentCheck(token)) {
- if (tokens.size() != 2) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
- token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
- + "\" requires one operand"));
- return;
- }
- if (!TokenTypes.isIntegerTokenType(tokens.get(1).getType())
- || Binary.stringToInt(tokens.get(1).getValue()) < 0) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
- token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
- + "\" requires a non-negative integer"));
- return;
- }
- int value = Binary.stringToInt(tokens.get(1).getValue()); // KENV 1/6/05
- this.dataAddress.increment(value);
+ if (tokens.size() != 2) {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
+ token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
+ + "\" requires one operand"));
+ return;
+ }
+ if (!TokenTypes.isIntegerTokenType(tokens.get(1).getType())
+ || Binary.stringToInt(tokens.get(1).getValue()) < 0) {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
+ token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
+ + "\" requires a non-negative integer"));
+ return;
+ }
+ int value = Binary.stringToInt(tokens.get(1).getValue()); // KENV 1/6/05
+ this.dataAddress.increment(value);
}
- }
- else if (direct == Directives.EXTERN) {
+ } else if (direct == Directives.EXTERN) {
if (tokens.size() != 3) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "\"" + token.getValue()
- + "\" directive requires two operands (label and size)."));
- return;
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "\"" + token.getValue()
+ + "\" directive requires two operands (label and size)."));
+ return;
}
if (!TokenTypes.isIntegerTokenType(tokens.get(2).getType())
- || Binary.stringToInt(tokens.get(2).getValue()) < 0) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "\"" + token.getValue()
- + "\" requires a non-negative integer size"));
- return;
+ || Binary.stringToInt(tokens.get(2).getValue()) < 0) {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "\"" + token.getValue()
+ + "\" requires a non-negative integer size"));
+ return;
}
int size = Binary.stringToInt(tokens.get(2).getValue());
- // If label already in global symtab, do nothing. If not, add it right now.
+ // If label already in global symtab, do nothing. If not, add it right now.
if (Globals.symbolTable.getAddress(tokens.get(1).getValue()) == SymbolTable.NOT_FOUND) {
- Globals.symbolTable.addSymbol(tokens.get(1), this.externAddress,
- Symbol.DATA_SYMBOL, errors);
- this.externAddress += size;
+ Globals.symbolTable.addSymbol(tokens.get(1), this.externAddress,
+ Symbol.DATA_SYMBOL, errors);
+ this.externAddress += size;
}
- }
- else if (direct == Directives.SET) {
+ } else if (direct == Directives.SET) {
errors.add(new ErrorMessage(ErrorMessage.WARNING, token.getSourceMIPSprogram(), token
- .getSourceLine(), token.getStartPos(),
- "MARS currently ignores the .set directive."));
- }
- else if (direct == Directives.GLOBL) {
+ .getSourceLine(), token.getStartPos(),
+ "MARS currently ignores the .set directive."));
+ } else if (direct == Directives.GLOBL) {
if (tokens.size() < 2) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "\"" + token.getValue()
- + "\" directive requires at least one argument."));
- return;
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "\"" + token.getValue()
+ + "\" directive requires at least one argument."));
+ return;
}
- // SPIM limits .globl list to one label, why not extend it to a list?
+ // SPIM limits .globl list to one label, why not extend it to a list?
for (int i = 1; i < tokens.size(); i++) {
- // Add it to a list of labels to be processed at the end of the
- // pass. At that point, transfer matching symbol definitions from
- // local symbol table to global symbol table.
- Token label = tokens.get(i);
- if (label.getType() != TokenTypes.IDENTIFIER) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
- token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
- + "\" directive argument must be label."));
- return;
- }
- globalDeclarationList.add(label);
+ // Add it to a list of labels to be processed at the end of the
+ // pass. At that point, transfer matching symbol definitions from
+ // local symbol table to global symbol table.
+ Token label = tokens.get(i);
+ if (label.getType() != TokenTypes.IDENTIFIER) {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
+ token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
+ + "\" directive argument must be label."));
+ return;
+ }
+ globalDeclarationList.add(label);
}
- }
- else {
+ } else {
errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token
- .getStartPos(), "\"" + token.getValue()
- + "\" directive recognized but not yet implemented."));
+ .getStartPos(), "\"" + token.getValue()
+ + "\" directive recognized but not yet implemented."));
return;
- }
- } // executeDirective()
-
- // //////////////////////////////////////////////////////////////////////////////
- // Process the list of .globl labels, if any, declared and defined in this file.
- // We'll just move their symbol table entries from local symbol table to global
- // symbol table at the end of the first assembly pass.
- private void transferGlobals() {
- for (int i = 0; i < globalDeclarationList.size(); i++) {
+ }
+ } // executeDirective()
+
+ // //////////////////////////////////////////////////////////////////////////////
+ // Process the list of .globl labels, if any, declared and defined in this file.
+ // We'll just move their symbol table entries from local symbol table to global
+ // symbol table at the end of the first assembly pass.
+ private void transferGlobals() {
+ for (int i = 0; i < globalDeclarationList.size(); i++) {
Token label = globalDeclarationList.get(i);
Symbol symtabEntry = fileCurrentlyBeingAssembled.getLocalSymbolTable().getSymbol(
- label.getValue());
+ label.getValue());
if (symtabEntry == null) {
- errors.add(new ErrorMessage(fileCurrentlyBeingAssembled, label.getSourceLine(),
- label.getStartPos(), "\"" + label.getValue()
- + "\" declared global label but not defined."));
- }
- else {
- if (Globals.symbolTable.getAddress(label.getValue()) != SymbolTable.NOT_FOUND) {
- errors.add(new ErrorMessage(fileCurrentlyBeingAssembled, label.getSourceLine(),
- label.getStartPos(), "\"" + label.getValue()
- + "\" already defined as global in a different file."));
- }
- else {
- fileCurrentlyBeingAssembled.getLocalSymbolTable().removeSymbol(label);
- Globals.symbolTable.addSymbol(label, symtabEntry.getAddress(),
- symtabEntry.getType(), errors);
- }
+ errors.add(new ErrorMessage(fileCurrentlyBeingAssembled, label.getSourceLine(),
+ label.getStartPos(), "\"" + label.getValue()
+ + "\" declared global label but not defined."));
+ } else {
+ if (Globals.symbolTable.getAddress(label.getValue()) != SymbolTable.NOT_FOUND) {
+ errors.add(new ErrorMessage(fileCurrentlyBeingAssembled, label.getSourceLine(),
+ label.getStartPos(), "\"" + label.getValue()
+ + "\" already defined as global in a different file."));
+ } else {
+ fileCurrentlyBeingAssembled.getLocalSymbolTable().removeSymbol(label);
+ Globals.symbolTable.addSymbol(label, symtabEntry.getAddress(),
+ symtabEntry.getType(), errors);
+ }
}
- }
- }
-
- // //////////////////////////////////////////////////////////////////////////////////
- // This source code line, if syntactically correct, is a continuation of a
- // directive list begun on on previous line.
- private void executeDirectiveContinuation(TokenList tokens) {
- Directives direct = this.dataDirective;
- if (direct == Directives.WORD || direct == Directives.HALF || direct == Directives.BYTE
- || direct == Directives.FLOAT || direct == Directives.DOUBLE) {
+ }
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // This source code line, if syntactically correct, is a continuation of a
+ // directive list begun on on previous line.
+ private void executeDirectiveContinuation(TokenList tokens) {
+ Directives direct = this.dataDirective;
+ if (direct == Directives.WORD || direct == Directives.HALF || direct == Directives.BYTE
+ || direct == Directives.FLOAT || direct == Directives.DOUBLE) {
if (tokens.size() > 0) {
- storeNumeric(tokens, direct, errors);
+ storeNumeric(tokens, direct, errors);
}
- }
- else if (direct == Directives.ASCII || direct == Directives.ASCIIZ) {
+ } else if (direct == Directives.ASCII || direct == Directives.ASCIIZ) {
if (passesDataSegmentCheck(tokens.get(0))) {
- storeStrings(tokens, direct, errors);
+ storeStrings(tokens, direct, errors);
}
- }
- } // executeDirectiveContinuation()
-
- // //////////////////////////////////////////////////////////////////////////////////
- // Given token, find the corresponding Instruction object. If token was not
- // recognized as OPERATOR, there is a problem.
- private ArrayList matchInstruction(Token token) {
- if (token.getType() != TokenTypes.OPERATOR) {
+ }
+ } // executeDirectiveContinuation()
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // Given token, find the corresponding Instruction object. If token was not
+ // recognized as OPERATOR, there is a problem.
+ private ArrayList matchInstruction(Token token) {
+ if (token.getType() != TokenTypes.OPERATOR) {
if (token.getSourceMIPSprogram().getLocalMacroPool()
- .matchesAnyMacroName(token.getValue()))
- this.errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token
- .getSourceLine(), token.getStartPos(), "forward reference or invalid parameters for macro \""
- + token.getValue() + "\""));
+ .matchesAnyMacroName(token.getValue()))
+ this.errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token
+ .getSourceLine(), token.getStartPos(), "forward reference or invalid parameters for macro \""
+ + token.getValue() + "\""));
else
- this.errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token
- .getSourceLine(), token.getStartPos(), "\"" + token.getValue()
- + "\" is not a recognized operator"));
+ this.errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token
+ .getSourceLine(), token.getStartPos(), "\"" + token.getValue()
+ + "\" is not a recognized operator"));
return null;
- }
- ArrayList inst = Globals.instructionSet.matchOperator(token.getValue());
- if (inst == null) { // This should NEVER happen...
+ }
+ ArrayList inst = Globals.instructionSet.matchOperator(token.getValue());
+ if (inst == null) { // This should NEVER happen...
this.errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "Internal Assembler error: \"" + token.getValue()
- + "\" tokenized OPERATOR then not recognized"));
- }
- return inst;
- } // matchInstruction()
-
- // //////////////////////////////////////////////////////////////////////////////////
- // Processes the .word/.half/.byte/.float/.double directive.
- // Can also handle "directive continuations", e.g. second or subsequent line
- // of a multiline list, which does not contain the directive token. Just pass the
- // current directive as argument.
- private void storeNumeric(TokenList tokens, Directives directive, ErrorList errors) {
- Token token = tokens.get(0);
- // A double-check; should have already been caught...removed ".word" exemption 11/20/06
- if (!passesDataSegmentCheck(token))
+ token.getStartPos(), "Internal Assembler error: \"" + token.getValue()
+ + "\" tokenized OPERATOR then not recognized"));
+ }
+ return inst;
+ } // matchInstruction()
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // Processes the .word/.half/.byte/.float/.double directive.
+ // Can also handle "directive continuations", e.g. second or subsequent line
+ // of a multiline list, which does not contain the directive token. Just pass the
+ // current directive as argument.
+ private void storeNumeric(TokenList tokens, Directives directive, ErrorList errors) {
+ Token token = tokens.get(0);
+ // A double-check; should have already been caught...removed ".word" exemption 11/20/06
+ if (!passesDataSegmentCheck(token))
return;
- // Correctly handles case where this is a "directive continuation" line.
- int tokenStart = 0;
- if (token.getType() == TokenTypes.DIRECTIVE)
+ // Correctly handles case where this is a "directive continuation" line.
+ int tokenStart = 0;
+ if (token.getType() == TokenTypes.DIRECTIVE)
tokenStart = 1;
-
- // Set byte length in memory of each number (e.g. WORD is 4, BYTE is 1, etc)
- int lengthInBytes = DataTypes.getLengthInBytes(directive);
-
- // Handle the "value : n" format, which replicates the value "n" times.
- if (tokens.size() == 4 && tokens.get(2).getType() == TokenTypes.COLON) {
+
+ // Set byte length in memory of each number (e.g. WORD is 4, BYTE is 1, etc)
+ int lengthInBytes = DataTypes.getLengthInBytes(directive);
+
+ // Handle the "value : n" format, which replicates the value "n" times.
+ if (tokens.size() == 4 && tokens.get(2).getType() == TokenTypes.COLON) {
Token valueToken = tokens.get(1);
Token repetitionsToken = tokens.get(3);
- // DPS 15-jul-08, allow ":" for repetition for all numeric
- // directives (originally just .word)
- // Conditions for correctly-formed replication:
- // (integer directive AND integer value OR floating directive AND
- // (integer value OR floating value))
- // AND integer repetition value
+ // DPS 15-jul-08, allow ":" for repetition for all numeric
+ // directives (originally just .word)
+ // Conditions for correctly-formed replication:
+ // (integer directive AND integer value OR floating directive AND
+ // (integer value OR floating value))
+ // AND integer repetition value
if (!(Directives.isIntegerDirective(directive)
- && TokenTypes.isIntegerTokenType(valueToken.getType()) || Directives
- .isFloatingDirective(directive)
- && (TokenTypes.isIntegerTokenType(valueToken.getType()) || TokenTypes
- .isFloatingTokenType(valueToken.getType())))
- || !TokenTypes.isIntegerTokenType(repetitionsToken.getType())) {
- errors.add(new ErrorMessage(fileCurrentlyBeingAssembled,
- valueToken.getSourceLine(), valueToken.getStartPos(),
- "malformed expression"));
- return;
+ && TokenTypes.isIntegerTokenType(valueToken.getType()) || Directives
+ .isFloatingDirective(directive)
+ && (TokenTypes.isIntegerTokenType(valueToken.getType()) || TokenTypes
+ .isFloatingTokenType(valueToken.getType())))
+ || !TokenTypes.isIntegerTokenType(repetitionsToken.getType())) {
+ errors.add(new ErrorMessage(fileCurrentlyBeingAssembled,
+ valueToken.getSourceLine(), valueToken.getStartPos(),
+ "malformed expression"));
+ return;
}
int repetitions = Binary.stringToInt(repetitionsToken.getValue()); // KENV 1/6/05
if (repetitions <= 0) {
- errors.add(new ErrorMessage(fileCurrentlyBeingAssembled, repetitionsToken
- .getSourceLine(), repetitionsToken.getStartPos(),
- "repetition factor must be positive"));
- return;
+ errors.add(new ErrorMessage(fileCurrentlyBeingAssembled, repetitionsToken
+ .getSourceLine(), repetitionsToken.getStartPos(),
+ "repetition factor must be positive"));
+ return;
}
if (this.inDataSegment) {
- if (this.autoAlign) {
- this.dataAddress
- .set(this.alignToBoundary(this.dataAddress.get(), lengthInBytes));
- }
- for (int i = 0; i < repetitions; i++) {
- if (Directives.isIntegerDirective(directive)) {
- storeInteger(valueToken, directive, errors);
- }
- else {
- storeRealNumber(valueToken, directive, errors);
- }
- }
+ if (this.autoAlign) {
+ this.dataAddress
+ .set(this.alignToBoundary(this.dataAddress.get(), lengthInBytes));
+ }
+ for (int i = 0; i < repetitions; i++) {
+ if (Directives.isIntegerDirective(directive)) {
+ storeInteger(valueToken, directive, errors);
+ } else {
+ storeRealNumber(valueToken, directive, errors);
+ }
+ }
} // WHAT ABOUT .KDATA SEGMENT?
- /***************************************************************************
- * /****** NOTE of 11/20/06. Below will always throw exception b/c
- * you cannot use Memory.set() with text segment addresses and the
- * "not valid address" produced here is misleading. Added data
- * segment check prior to this point, so this "else" will never be
- * executed. I'm leaving it in just in case MARS in the future adds
- * capability of writing to the text segment (e.g. ability to
- * de-assemble a binary value into its corresponding MIPS
- * instruction)
- *
- * else { // not in data segment...which we assume to mean in text
- * segment. try { for (int i=0; i < repetitions; i++) {
- * Globals.memory.set(this.textAddress.get(),
- * Binary.stringToInt(valueToken.getValue()), lengthInBytes);
- * this.textAddress.increment(lengthInBytes); } } catch
- * (AddressErrorException e) { errors.add(new
- * ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- * token.getStartPos(), "\""+this.textAddress.get()+
- * "\" is not a valid text segment address")); } }
- ************************************************************************/
+ /***************************************************************************
+ * /****** NOTE of 11/20/06. Below will always throw exception b/c
+ * you cannot use Memory.set() with text segment addresses and the
+ * "not valid address" produced here is misleading. Added data
+ * segment check prior to this point, so this "else" will never be
+ * executed. I'm leaving it in just in case MARS in the future adds
+ * capability of writing to the text segment (e.g. ability to
+ * de-assemble a binary value into its corresponding MIPS
+ * instruction)
+ *
+ * else { // not in data segment...which we assume to mean in text
+ * segment. try { for (int i=0; i < repetitions; i++) {
+ * Globals.memory.set(this.textAddress.get(),
+ * Binary.stringToInt(valueToken.getValue()), lengthInBytes);
+ * this.textAddress.increment(lengthInBytes); } } catch
+ * (AddressErrorException e) { errors.add(new
+ * ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ * token.getStartPos(), "\""+this.textAddress.get()+
+ * "\" is not a valid text segment address")); } }
+ ************************************************************************/
return;
- }
-
- // if not in ".word w : n" format, must just be list of one or more values.
- for (int i = tokenStart; i < tokens.size(); i++) {
+ }
+
+ // if not in ".word w : n" format, must just be list of one or more values.
+ for (int i = tokenStart; i < tokens.size(); i++) {
token = tokens.get(i);
if (Directives.isIntegerDirective(directive)) {
- storeInteger(token, directive, errors);
+ storeInteger(token, directive, errors);
}
if (Directives.isFloatingDirective(directive)) {
- storeRealNumber(token, directive, errors);
+ storeRealNumber(token, directive, errors);
}
- }
- return;
- } // storeNumeric()
-
- // //////////////////////////////////////////////////////////////////////////////
- // Store integer value given integer (word, half, byte) directive.
- // Called by storeNumeric()
- // NOTE: The token itself may be a label, in which case the correct action is
- // to store the address of that label (into however many bytes specified).
- private void storeInteger(Token token, Directives directive, ErrorList errors) {
- int lengthInBytes = DataTypes.getLengthInBytes(directive);
- if (TokenTypes.isIntegerTokenType(token.getType())) {
- int value = Binary.stringToInt(token.getValue());
+ }
+ return;
+ } // storeNumeric()
+
+ // //////////////////////////////////////////////////////////////////////////////
+ // Store integer value given integer (word, half, byte) directive.
+ // Called by storeNumeric()
+ // NOTE: The token itself may be a label, in which case the correct action is
+ // to store the address of that label (into however many bytes specified).
+ private void storeInteger(Token token, Directives directive, ErrorList errors) {
+ int lengthInBytes = DataTypes.getLengthInBytes(directive);
+ if (TokenTypes.isIntegerTokenType(token.getType())) {
+ int value = Binary.stringToInt(token.getValue());
int fullvalue = value;
- // DPS 4-Jan-2013. Overriding 6-Jan-2005 KENV changes.
- // If value is out of range for the directive, will simply truncate
- // the leading bits (includes sign bits). This is what SPIM does.
- // But will issue a warning (not error) which SPIM does not do.
+ // DPS 4-Jan-2013. Overriding 6-Jan-2005 KENV changes.
+ // If value is out of range for the directive, will simply truncate
+ // the leading bits (includes sign bits). This is what SPIM does.
+ // But will issue a warning (not error) which SPIM does not do.
if (directive == Directives.BYTE) {
- value = value & 0x000000FF;
- }
- else if (directive == Directives.HALF) {
- value = value & 0x0000FFFF;
+ value = value & 0x000000FF;
+ } else if (directive == Directives.HALF) {
+ value = value & 0x0000FFFF;
}
-
+
if (DataTypes.outOfRange(directive, fullvalue)) {
- errors.add(new ErrorMessage(ErrorMessage.WARNING, token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "\"" + token.getValue()
- + "\" is out-of-range for a signed value and possibly truncated"));
+ errors.add(new ErrorMessage(ErrorMessage.WARNING, token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "\"" + token.getValue()
+ + "\" is out-of-range for a signed value and possibly truncated"));
}
if (this.inDataSegment) {
- writeToDataSegment(value, lengthInBytes, token, errors);
+ writeToDataSegment(value, lengthInBytes, token, errors);
}
/******
- * NOTE of 11/20/06. "try" below will always throw exception b/c you
- * cannot use Memory.set() with text segment addresses and the
- * "not valid address" produced here is misleading. Added data
- * segment check prior to this point, so this "else" will never be
- * executed. I'm leaving it in just in case MARS in the future adds
- * capability of writing to the text segment (e.g. ability to
- * de-assemble a binary value into its corresponding MIPS
- * instruction)
- ********/
+ * NOTE of 11/20/06. "try" below will always throw exception b/c you
+ * cannot use Memory.set() with text segment addresses and the
+ * "not valid address" produced here is misleading. Added data
+ * segment check prior to this point, so this "else" will never be
+ * executed. I'm leaving it in just in case MARS in the future adds
+ * capability of writing to the text segment (e.g. ability to
+ * de-assemble a binary value into its corresponding MIPS
+ * instruction)
+ ********/
else {
- try {
- Globals.memory.set(this.textAddress.get(), value, lengthInBytes);
- }
- catch (AddressErrorException e) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
- token.getSourceLine(), token.getStartPos(), "\""
- + this.textAddress.get()
- + "\" is not a valid text segment address"));
- return;
- }
- this.textAddress.increment(lengthInBytes);
+ try {
+ Globals.memory.set(this.textAddress.get(), value, lengthInBytes);
+ } catch (AddressErrorException e) {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
+ token.getSourceLine(), token.getStartPos(), "\""
+ + this.textAddress.get()
+ + "\" is not a valid text segment address"));
+ return;
+ }
+ this.textAddress.increment(lengthInBytes);
}
- } // end of "if integer token type"
- else if (token.getType() == TokenTypes.IDENTIFIER) {
+ } // end of "if integer token type"
+ else if (token.getType() == TokenTypes.IDENTIFIER) {
if (this.inDataSegment) {
- int value = fileCurrentlyBeingAssembled.getLocalSymbolTable()
- .getAddressLocalOrGlobal(token.getValue());
- if (value == SymbolTable.NOT_FOUND) {
- // Record value 0 for now, then set up backpatch entry
- int dataAddress = writeToDataSegment(0, lengthInBytes, token, errors);
- currentFileDataSegmentForwardReferences.add(dataAddress, lengthInBytes, token);
- }
- else { // label already defined, so write its address
- writeToDataSegment(value, lengthInBytes, token, errors);
- }
+ int value = fileCurrentlyBeingAssembled.getLocalSymbolTable()
+ .getAddressLocalOrGlobal(token.getValue());
+ if (value == SymbolTable.NOT_FOUND) {
+ // Record value 0 for now, then set up backpatch entry
+ int dataAddress = writeToDataSegment(0, lengthInBytes, token, errors);
+ currentFileDataSegmentForwardReferences.add(dataAddress, lengthInBytes, token);
+ } else { // label already defined, so write its address
+ writeToDataSegment(value, lengthInBytes, token, errors);
+ }
} // Data segment check done previously, so this "else" will not be.
- // See 11/20/06 note above.
+ // See 11/20/06 note above.
else {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "\"" + token.getValue()
- + "\" label as directive operand not permitted in text segment"));
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "\"" + token.getValue()
+ + "\" label as directive operand not permitted in text segment"));
}
- } // end of "if label"
- else {
+ } // end of "if label"
+ else {
errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token
- .getStartPos(), "\"" + token.getValue()
- + "\" is not a valid integer constant or label"));
- }
- }// storeInteger
-
- // //////////////////////////////////////////////////////////////////////////////
- // Store real (fixed or floating point) value given floating (float, double) directive.
- // Called by storeNumeric()
- private void storeRealNumber(Token token, Directives directive, ErrorList errors) {
- int lengthInBytes = DataTypes.getLengthInBytes(directive);
- double value;
-
- if (TokenTypes.isIntegerTokenType(token.getType())
- || TokenTypes.isFloatingTokenType(token.getType())) {
+ .getStartPos(), "\"" + token.getValue()
+ + "\" is not a valid integer constant or label"));
+ }
+ }// storeInteger
+
+ // //////////////////////////////////////////////////////////////////////////////
+ // Store real (fixed or floating point) value given floating (float, double) directive.
+ // Called by storeNumeric()
+ private void storeRealNumber(Token token, Directives directive, ErrorList errors) {
+ int lengthInBytes = DataTypes.getLengthInBytes(directive);
+ double value;
+
+ if (TokenTypes.isIntegerTokenType(token.getType())
+ || TokenTypes.isFloatingTokenType(token.getType())) {
try {
- value = Double.parseDouble(token.getValue());
- }
- catch (NumberFormatException nfe) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "\"" + token.getValue()
- + "\" is not a valid floating point constant"));
- return;
- }
+ value = Double.parseDouble(token.getValue());
+ } catch (NumberFormatException nfe) {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "\"" + token.getValue()
+ + "\" is not a valid floating point constant"));
+ return;
+ }
if (DataTypes.outOfRange(directive, value)) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "\"" + token.getValue()
- + "\" is an out-of-range value"));
- return;
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "\"" + token.getValue()
+ + "\" is an out-of-range value"));
+ return;
}
- }
- else {
+ } else {
errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token
- .getStartPos(), "\"" + token.getValue()
- + "\" is not a valid floating point constant"));
+ .getStartPos(), "\"" + token.getValue()
+ + "\" is not a valid floating point constant"));
return;
- }
-
- // Value has been validated; let's store it.
-
- if (directive == Directives.FLOAT) {
+ }
+
+ // Value has been validated; let's store it.
+
+ if (directive == Directives.FLOAT) {
writeToDataSegment(Float.floatToIntBits((float) value), lengthInBytes, token, errors);
- }
- if (directive == Directives.DOUBLE) {
+ }
+ if (directive == Directives.DOUBLE) {
writeDoubleToDataSegment(value, token, errors);
- }
-
- } // storeRealNumber
-
- // //////////////////////////////////////////////////////////////////////////////////
- // Use directive argument to distinguish between ASCII and ASCIIZ. The
- // latter stores a terminating null byte. Can handle a list of one or more
- // strings on a single line.
- private void storeStrings(TokenList tokens, Directives direct, ErrorList errors) {
- Token token;
- // Correctly handles case where this is a "directive continuation" line.
- int tokenStart = 0;
- if (tokens.get(0).getType() == TokenTypes.DIRECTIVE) {
+ }
+
+ } // storeRealNumber
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // Use directive argument to distinguish between ASCII and ASCIIZ. The
+ // latter stores a terminating null byte. Can handle a list of one or more
+ // strings on a single line.
+ private void storeStrings(TokenList tokens, Directives direct, ErrorList errors) {
+ Token token;
+ // Correctly handles case where this is a "directive continuation" line.
+ int tokenStart = 0;
+ if (tokens.get(0).getType() == TokenTypes.DIRECTIVE) {
tokenStart = 1;
- }
- for (int i = tokenStart; i < tokens.size(); i++) {
+ }
+ for (int i = tokenStart; i < tokens.size(); i++) {
token = tokens.get(i);
if (token.getType() != TokenTypes.QUOTED_STRING) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "\"" + token.getValue()
- + "\" is not a valid character string"));
- }
- else {
- String quote = token.getValue();
- char theChar;
- for (int j = 1; j < quote.length() - 1; j++) {
- theChar = quote.charAt(j);
- if (theChar == '\\') {
- theChar = quote.charAt(++j);
- switch (theChar) {
- case 'n':
- theChar = '\n';
- break;
- case 't':
- theChar = '\t';
- break;
- case 'r':
- theChar = '\r';
- break;
- case '\\':
- theChar = '\\';
- break;
- case '\'':
- theChar = '\'';
- break;
- case '"':
- theChar = '"';
- break;
- case 'b':
- theChar = '\b';
- break;
- case 'f':
- theChar = '\f';
- break;
- case '0':
- theChar = '\0';
- break;
- // Not implemented: \ n = octal character (n is number)
- // \ x n = hex character (n is number)
- // \ u n = unicode character (n is number)
- // There are of course no spaces in these escape
- // codes...
- }
- }
- try {
- Globals.memory.set(this.dataAddress.get(), (int) theChar,
- DataTypes.CHAR_SIZE);
- }
- catch (AddressErrorException e) {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "\"" + token.getValue()
+ + "\" is not a valid character string"));
+ } else {
+ String quote = token.getValue();
+ char theChar;
+ for (int j = 1; j < quote.length() - 1; j++) {
+ theChar = quote.charAt(j);
+ if (theChar == '\\') {
+ theChar = quote.charAt(++j);
+ switch (theChar) {
+ case 'n':
+ theChar = '\n';
+ break;
+ case 't':
+ theChar = '\t';
+ break;
+ case 'r':
+ theChar = '\r';
+ break;
+ case '\\':
+ theChar = '\\';
+ break;
+ case '\'':
+ theChar = '\'';
+ break;
+ case '"':
+ theChar = '"';
+ break;
+ case 'b':
+ theChar = '\b';
+ break;
+ case 'f':
+ theChar = '\f';
+ break;
+ case '0':
+ theChar = '\0';
+ break;
+ // Not implemented: \ n = octal character (n is number)
+ // \ x n = hex character (n is number)
+ // \ u n = unicode character (n is number)
+ // There are of course no spaces in these escape
+ // codes...
+ }
+ }
+ try {
+ Globals.memory.set(this.dataAddress.get(), (int) theChar,
+ DataTypes.CHAR_SIZE);
+ } catch (AddressErrorException e) {
errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token
- .getSourceLine(), token.getStartPos(), "\""
- + this.dataAddress.get() + "\" is not a valid data segment address"));
- }
- this.dataAddress.increment(DataTypes.CHAR_SIZE);
- }
- if (direct == Directives.ASCIIZ) {
- try {
- Globals.memory.set(this.dataAddress.get(), 0, DataTypes.CHAR_SIZE);
- }
- catch (AddressErrorException e) {
+ .getSourceLine(), token.getStartPos(), "\""
+ + this.dataAddress.get() + "\" is not a valid data segment address"));
+ }
+ this.dataAddress.increment(DataTypes.CHAR_SIZE);
+ }
+ if (direct == Directives.ASCIIZ) {
+ try {
+ Globals.memory.set(this.dataAddress.get(), 0, DataTypes.CHAR_SIZE);
+ } catch (AddressErrorException e) {
errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token
- .getSourceLine(), token.getStartPos(), "\""
- + this.dataAddress.get() + "\" is not a valid data segment address"));
- }
- this.dataAddress.increment(DataTypes.CHAR_SIZE);
- }
+ .getSourceLine(), token.getStartPos(), "\""
+ + this.dataAddress.get() + "\" is not a valid data segment address"));
+ }
+ this.dataAddress.increment(DataTypes.CHAR_SIZE);
+ }
}
- }
- } // storeStrings()
-
- // //////////////////////////////////////////////////////////////////////////////////
- // Simply check to see if we are in data segment. Generate error if not.
- private boolean passesDataSegmentCheck(Token token) {
- if (!this.inDataSegment) {
+ }
+ } // storeStrings()
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // Simply check to see if we are in data segment. Generate error if not.
+ private boolean passesDataSegmentCheck(Token token) {
+ if (!this.inDataSegment) {
errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token
- .getStartPos(), "\"" + token.getValue()
- + "\" directive cannot appear in text segment"));
+ .getStartPos(), "\"" + token.getValue()
+ + "\" directive cannot appear in text segment"));
return false;
- }
- else {
+ } else {
return true;
- }
- }
-
- // //////////////////////////////////////////////////////////////////////////////////
- // Writes the given int value into current data segment address. Works for
- // all the integer types plus float (caller is responsible for doing floatToIntBits).
- // Returns address at which the value was stored.
- private int writeToDataSegment(int value, int lengthInBytes, Token token, ErrorList errors) {
- if (this.autoAlign) {
+ }
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // Writes the given int value into current data segment address. Works for
+ // all the integer types plus float (caller is responsible for doing floatToIntBits).
+ // Returns address at which the value was stored.
+ private int writeToDataSegment(int value, int lengthInBytes, Token token, ErrorList errors) {
+ if (this.autoAlign) {
this.dataAddress.set(this.alignToBoundary(this.dataAddress.get(), lengthInBytes));
- }
- try {
+ }
+ try {
Globals.memory.set(this.dataAddress.get(), value, lengthInBytes);
- }
- catch (AddressErrorException e) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token
- .getStartPos(), "\"" + this.dataAddress.get()
- + "\" is not a valid data segment address"));
- return this.dataAddress.get();
- }
- int address = this.dataAddress.get();
- this.dataAddress.increment(lengthInBytes);
- return address;
- }
-
- // //////////////////////////////////////////////////////////////////////////////////
- // Writes the given double value into current data segment address. Works
- // only for DOUBLE floating
- // point values -- Memory class doesn't have method for writing 8 bytes, so
- // use setWord twice.
- private void writeDoubleToDataSegment(double value, Token token, ErrorList errors) {
- int lengthInBytes = DataTypes.DOUBLE_SIZE;
- if (this.autoAlign) {
+ } catch (AddressErrorException e) {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token
+ .getStartPos(), "\"" + this.dataAddress.get()
+ + "\" is not a valid data segment address"));
+ return this.dataAddress.get();
+ }
+ int address = this.dataAddress.get();
+ this.dataAddress.increment(lengthInBytes);
+ return address;
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // Writes the given double value into current data segment address. Works
+ // only for DOUBLE floating
+ // point values -- Memory class doesn't have method for writing 8 bytes, so
+ // use setWord twice.
+ private void writeDoubleToDataSegment(double value, Token token, ErrorList errors) {
+ int lengthInBytes = DataTypes.DOUBLE_SIZE;
+ if (this.autoAlign) {
this.dataAddress.set(this.alignToBoundary(this.dataAddress.get(), lengthInBytes));
- }
- try {
+ }
+ try {
Globals.memory.setDouble(this.dataAddress.get(), value);
- }
- catch (AddressErrorException e) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token
- .getStartPos(), "\"" + this.dataAddress.get()
- + "\" is not a valid data segment address"));
- return;
- }
- this.dataAddress.increment(lengthInBytes);
- }
-
- // //////////////////////////////////////////////////////////////////////////////////
- // If address is multiple of byte boundary, returns address. Otherwise, returns address
- // which is next higher multiple of the byte boundary. Used for aligning data segment.
- // For instance if args are 6 and 4, returns 8 (next multiple of 4 higher than 6).
- // NOTE: it will fix any symbol table entries for this address too. See else part.
- private int alignToBoundary(int address, int byteBoundary) {
- int remainder = address % byteBoundary;
- if (remainder == 0) {
+ } catch (AddressErrorException e) {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token
+ .getStartPos(), "\"" + this.dataAddress.get()
+ + "\" is not a valid data segment address"));
+ return;
+ }
+ this.dataAddress.increment(lengthInBytes);
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // If address is multiple of byte boundary, returns address. Otherwise, returns address
+ // which is next higher multiple of the byte boundary. Used for aligning data segment.
+ // For instance if args are 6 and 4, returns 8 (next multiple of 4 higher than 6).
+ // NOTE: it will fix any symbol table entries for this address too. See else part.
+ private int alignToBoundary(int address, int byteBoundary) {
+ int remainder = address % byteBoundary;
+ if (remainder == 0) {
return address;
- }
- else {
+ } else {
int alignedAddress = address + byteBoundary - remainder;
fileCurrentlyBeingAssembled.getLocalSymbolTable().fixSymbolTableAddress(address,
- alignedAddress);
+ alignedAddress);
return alignedAddress;
- }
- }
-
- // ///////////////////////////////////////////////////////////////////////////////////
- // Private class used as Comparator to sort the final ArrayList of
- // ProgramStatements.
- // Sorting is based on unsigned integer value of
- // ProgramStatement.getAddress()
- private class ProgramStatementComparator implements Comparator {
- // Will be used to sort the collection. Unsigned int compare, because
- // all kernel 32-bit
- // addresses have 1 in high order bit, which makes the int negative.
- // "Unsigned" compare
- // is needed when signs of the two operands differ.
- public int compare(Object obj1, Object obj2) {
- if (obj1 instanceof ProgramStatement && obj2 instanceof ProgramStatement) {
- int addr1 = ((ProgramStatement) obj1).getAddress();
- int addr2 = ((ProgramStatement) obj2).getAddress();
- return (addr1 < 0 && addr2 >= 0 || addr1 >= 0 && addr2 < 0) ? addr2 : addr1 - addr2;
- }
- else {
- throw new ClassCastException();
- }
- }
-
- // Take a hard line.
- public boolean equals(Object obj) {
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////
+ // Private class used as Comparator to sort the final ArrayList of
+ // ProgramStatements.
+ // Sorting is based on unsigned integer value of
+ // ProgramStatement.getAddress()
+ private class ProgramStatementComparator implements Comparator {
+ // Will be used to sort the collection. Unsigned int compare, because
+ // all kernel 32-bit
+ // addresses have 1 in high order bit, which makes the int negative.
+ // "Unsigned" compare
+ // is needed when signs of the two operands differ.
+ public int compare(ProgramStatement ps1, ProgramStatement ps2) {
+ int addr1 = ps1.getAddress();
+ int addr2 = ps2.getAddress();
+ return (addr1 < 0 && addr2 >= 0 || addr1 >= 0 && addr2 < 0) ? addr2 : addr1 - addr2;
+ }
+
+ // Take a hard line.
+ public boolean equals(Object obj) {
return this == obj;
- }
- }
-
- // ///////////////////////////////////////////////////////////////////////////////////
- // Private class to simultaneously track addresses in both user and kernel
- // address spaces.
- // Instantiate one for data segment and one for text segment.
- private class UserKernelAddressSpace {
- int[] address;
- int currentAddressSpace;
- private final int USER = 0, KERNEL = 1;
-
- // Initially use user address space, not kernel.
- private UserKernelAddressSpace(int userBase, int kernelBase) {
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////
+ // Private class to simultaneously track addresses in both user and kernel
+ // address spaces.
+ // Instantiate one for data segment and one for text segment.
+ private class UserKernelAddressSpace {
+ int[] address;
+ int currentAddressSpace;
+ private final int USER = 0, KERNEL = 1;
+
+ // Initially use user address space, not kernel.
+ private UserKernelAddressSpace(int userBase, int kernelBase) {
address = new int[2];
address[USER] = userBase;
address[KERNEL] = kernelBase;
currentAddressSpace = USER;
- }
-
- private int get() {
+ }
+
+ private int get() {
return address[currentAddressSpace];
- }
-
- private void set(int value) {
+ }
+
+ private void set(int value) {
address[currentAddressSpace] = value;
- }
-
- private void increment(int increment) {
+ }
+
+ private void increment(int increment) {
address[currentAddressSpace] += increment;
- }
-
- private void setAddressSpace(int addressSpace) {
+ }
+
+ private void setAddressSpace(int addressSpace) {
if (addressSpace == USER || addressSpace == KERNEL) {
- currentAddressSpace = addressSpace;
- }
- else {
- throw new IllegalArgumentException();
+ currentAddressSpace = addressSpace;
+ } else {
+ throw new IllegalArgumentException();
}
- }
- }
-
- // //////////////////////////////////////////////////////////////////////////
- // Handy class to handle forward label references appearing as data
- // segment operands. This is needed because the data segment is comletely
- // processed by the end of the first assembly pass, and its directives may
- // contain labels as operands. When this occurs, the label's associated
- // address becomes the operand value. If it is a forward reference, we will
- // save the necessary information in this object for finding and patching in
- // the correct address at the end of the first pass (for this file or for all
- // files if more than one).
- //
- // If such a parsed label refers to a local or global label not defined yet,
- // pertinent information is added to this object:
- // - memory address that needs the label's address,
- // - number of bytes (addresses are 4 bytes but may be used with any of
- // the integer directives: .word, .half, .byte)
- // - the label's token. Normally need only the name but error message needs more.
- private class DataSegmentForwardReferences {
- private ArrayList forwardReferenceList;
-
- private DataSegmentForwardReferences() {
- forwardReferenceList = new ArrayList();
- }
-
- private int size() {
+ }
+ }
+
+ // //////////////////////////////////////////////////////////////////////////
+ // Handy class to handle forward label references appearing as data
+ // segment operands. This is needed because the data segment is comletely
+ // processed by the end of the first assembly pass, and its directives may
+ // contain labels as operands. When this occurs, the label's associated
+ // address becomes the operand value. If it is a forward reference, we will
+ // save the necessary information in this object for finding and patching in
+ // the correct address at the end of the first pass (for this file or for all
+ // files if more than one).
+ //
+ // If such a parsed label refers to a local or global label not defined yet,
+ // pertinent information is added to this object:
+ // - memory address that needs the label's address once resolved
+ // - number of bytes (addresses are 4 bytes but may be used with any of
+ // the integer directives: .word, .half, .byte)
+ // - the label's token. Normally need only the name but error message needs more.
+ private class DataSegmentForwardReferences {
+ private ArrayList forwardReferenceList;
+
+ private DataSegmentForwardReferences() {
+ forwardReferenceList = new ArrayList<>();
+ }
+
+ private int size() {
return forwardReferenceList.size();
- }
-
- // Add a new forward reference entry. Client must supply the following:
- // - memory address to receive the label's address once resolved
- // - number of address bytes to store (1 for .byte, 2 for .half, 4 for .word)
- // - the label's token. All its information will be needed if error message generated.
- private void add(int patchAddress, int length, Token token) {
+ }
+
+ // Add a new forward reference entry. Client must supply the following:
+ // - memory address to receive the label's address once resolved
+ // - number of address bytes to store (1 for .byte, 2 for .half, 4 for .word)
+ // - the label's token. All its information will be needed if error message generated.
+ private void add(int patchAddress, int length, Token token) {
forwardReferenceList.add(new DataSegmentForwardReference(patchAddress, length, token));
- }
-
- // Add the entries of another DataSegmentForwardReferences object to this one.
- // Can be used at the end of each source file to dump all unresolved references
- // into a common list to be processed after all source files parsed.
- private void add(DataSegmentForwardReferences another) {
+ }
+
+ // Add the entries of another DataSegmentForwardReferences object to this one.
+ // Can be used at the end of each source file to dump all unresolved references
+ // into a common list to be processed after all source files parsed.
+ private void add(DataSegmentForwardReferences another) {
forwardReferenceList.addAll(another.forwardReferenceList);
- }
-
- // Clear out the list. Allows you to re-use it.
- private void clear() {
+ }
+
+ // Clear out the list. Allows you to re-use it.
+ private void clear() {
forwardReferenceList.clear();
- }
-
- // Will traverse the list of forward references, attempting to resolve them.
- // For each entry it will first search the provided local symbol table and
- // failing that, the global one. If passed the global symbol table, it will
- // perform a second, redundant, search. If search is successful, the patch
- // is applied and the forward reference removed. If search is not successful,
- // the forward reference remains (it is either undefined or a global label
- // defined in a file not yet parsed).
- private int resolve(SymbolTable localSymtab) {
+ }
+
+ // Will traverse the list of forward references, attempting to resolve them.
+ // For each entry it will first search the provided local symbol table and
+ // failing that, the global one. If passed the global symbol table, it will
+ // perform a second, redundant, search. If search is successful, the patch
+ // is applied and the forward reference removed. If search is not successful,
+ // the forward reference remains (it is either undefined or a global label
+ // defined in a file not yet parsed).
+ private int resolve(SymbolTable localSymtab) {
int count = 0;
int labelAddress;
DataSegmentForwardReference entry;
for (int i = 0; i < forwardReferenceList.size(); i++) {
- entry = (DataSegmentForwardReference) forwardReferenceList.get(i);
- labelAddress = localSymtab.getAddressLocalOrGlobal(entry.token.getValue());
- if (labelAddress != SymbolTable.NOT_FOUND) {
- // patch address has to be valid b/c we already stored there...
- try {
- Globals.memory.set(entry.patchAddress, labelAddress, entry.length);
- }
- catch (AddressErrorException aee) {
- }
- forwardReferenceList.remove(i);
- i--; // needed because removal shifted the remaining list indices down
- count++;
- }
+ entry = forwardReferenceList.get(i);
+ labelAddress = localSymtab.getAddressLocalOrGlobal(entry.token.getValue());
+ if (labelAddress != SymbolTable.NOT_FOUND) {
+ // patch address has to be valid b/c we already stored there...
+ try {
+ Globals.memory.set(entry.patchAddress, labelAddress, entry.length);
+ } catch (AddressErrorException aee) {
+ }
+ forwardReferenceList.remove(i);
+ i--; // needed because removal shifted the remaining list indices down
+ count++;
+ }
}
return count;
- }
-
- // Call this when you are confident that remaining list entries are to
- // undefined labels.
- private void generateErrorMessages(ErrorList errors) {
+ }
+
+ // Call this when you are confident that remaining list entries are to
+ // undefined labels.
+ private void generateErrorMessages(ErrorList errors) {
DataSegmentForwardReference entry;
for (int i = 0; i < forwardReferenceList.size(); i++) {
- entry = (DataSegmentForwardReference) forwardReferenceList.get(i);
- errors.add(new ErrorMessage(entry.token.getSourceMIPSprogram(), entry.token
- .getSourceLine(), entry.token.getStartPos(), "Symbol \""
- + entry.token.getValue() + "\" not found in symbol table."));
+ entry = forwardReferenceList.get(i);
+ errors.add(new ErrorMessage(entry.token.getSourceMIPSprogram(), entry.token
+ .getSourceLine(), entry.token.getStartPos(), "Symbol \""
+ + entry.token.getValue() + "\" not found in symbol table."));
}
- }
-
- // inner-inner class to hold each entry of the forward reference list.
- private class DataSegmentForwardReference {
+ }
+
+ // inner-inner class to hold each entry of the forward reference list.
+ private class DataSegmentForwardReference {
int patchAddress;
int length;
Token token;
-
+
DataSegmentForwardReference(int patchAddress, int length, Token token) {
- this.patchAddress = patchAddress;
- this.length = length;
- this.token = token;
+ this.patchAddress = patchAddress;
+ this.length = length;
+ this.token = token;
}
- }
-
- }
- }
+ }
+
+ }
+}
diff --git a/src/mars/assembler/DataTypes.java b/src/mars/assembler/DataTypes.java
index 175e393..316d2b0 100644
--- a/src/mars/assembler/DataTypes.java
+++ b/src/mars/assembler/DataTypes.java
@@ -9,7 +9,7 @@ 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,
+but not limited to 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:
diff --git a/src/mars/assembler/Directives.java b/src/mars/assembler/Directives.java
index cc025ac..bb4c698 100644
--- a/src/mars/assembler/Directives.java
+++ b/src/mars/assembler/Directives.java
@@ -1,6 +1,6 @@
- package mars.assembler;
+package mars.assembler;
- import java.util.ArrayList;
+import java.util.ArrayList;
/*
Copyright (c) 2003-2012, Pete Sanderson and Kenneth Vollmar
@@ -40,151 +40,145 @@ a copy of this software and associated documentation files (the
* @version August 2003
**/
- public final class Directives {
-
- private static ArrayList directiveList = new ArrayList();
- public static final Directives DATA = new Directives(".data", "Subsequent items stored in Data segment at next available address");
- public static final Directives TEXT = new Directives(".text", "Subsequent items (instructions) stored in Text segment at next available address");
- public static final Directives WORD = new Directives(".word", "Store the listed value(s) as 32 bit words on word boundary");
- public static final Directives ASCII = new Directives(".ascii", "Store the string in the Data segment but do not add null terminator");
- public static final Directives ASCIIZ = new Directives(".asciiz", "Store the string in the Data segment and add null terminator");
- public static final Directives BYTE = new Directives(".byte", "Store the listed value(s) as 8 bit bytes");
- public static final Directives ALIGN = new Directives(".align", "Align next data item on specified byte boundary (0=byte, 1=half, 2=word, 3=double)");
- public static final Directives HALF = new Directives(".half", "Store the listed value(s) as 16 bit halfwords on halfword boundary");
- public static final Directives SPACE = new Directives(".space", "Reserve the next specified number of bytes in Data segment");
- public static final Directives DOUBLE = new Directives(".double", "Store the listed value(s) as double precision floating point");
- public static final Directives FLOAT = new Directives(".float", "Store the listed value(s) as single precision floating point");
- public static final Directives EXTERN = new Directives(".extern", "Declare the listed label and byte length to be a global data field");
- public static final Directives KDATA = new Directives(".kdata", "Subsequent items stored in Kernel Data segment at next available address");
- public static final Directives KTEXT = new Directives(".ktext", "Subsequent items (instructions) stored in Kernel Text segment at next available address");
- public static final Directives GLOBL = new Directives(".globl", "Declare the listed label(s) as global to enable referencing from other files");
- public static final Directives SET = new Directives(".set", "Set assembler variables. Currently ignored but included for SPIM compatability");
- /* EQV added by DPS 11 July 2012 */
- public static final Directives EQV = new Directives(".eqv", "Substitute second operand for first. First operand is symbol, second operand is expression (like #define)");
- /* MACRO and END_MACRO added by Mohammad Sekhavat Oct 2012 */
- public static final Directives MACRO = new Directives(".macro", "Begin macro definition. See .end_macro");
- public static final Directives END_MACRO = new Directives(".end_macro", "End macro definition. See .macro");
- /* INCLUDE added by DPS 11 Jan 2013 */
- public static final Directives INCLUDE = new Directives(".include", "Insert the contents of the specified file. Put filename in quotes.");
-
-
- private String descriptor;
- private String description; // help text
-
- private Directives() {
- // private ctor assures no objects can be created other than those above.
- this.descriptor = "generic";
- this.description = "";
- directiveList.add(this);
- }
-
- private Directives(String name, String description) {
- this.descriptor = name;
- this.description = description;
- directiveList.add(this);
- }
-
- /**
- * Find Directive object, if any, which matches the given String.
- *
- * @param str A String containing candidate directive name (e.g. ".ascii")
- * @return If match is found, returns matching Directives object, else returns null.
- **/
-
- public static Directives matchDirective(String str) {
- Directives match;
- for (int i=0; i directiveList = new ArrayList<>();
+ public static final Directives DATA = new Directives(".data", "Subsequent items stored in Data segment at next available address");
+ public static final Directives TEXT = new Directives(".text", "Subsequent items (instructions) stored in Text segment at next available address");
+ public static final Directives WORD = new Directives(".word", "Store the listed value(s) as 32 bit words on word boundary");
+ public static final Directives ASCII = new Directives(".ascii", "Store the string in the Data segment but do not add null terminator");
+ public static final Directives ASCIIZ = new Directives(".asciiz", "Store the string in the Data segment and add null terminator");
+ public static final Directives BYTE = new Directives(".byte", "Store the listed value(s) as 8 bit bytes");
+ public static final Directives ALIGN = new Directives(".align", "Align next data item on specified byte boundary (0=byte, 1=half, 2=word, 3=double)");
+ public static final Directives HALF = new Directives(".half", "Store the listed value(s) as 16 bit halfwords on halfword boundary");
+ public static final Directives SPACE = new Directives(".space", "Reserve the next specified number of bytes in Data segment");
+ public static final Directives DOUBLE = new Directives(".double", "Store the listed value(s) as double precision floating point");
+ public static final Directives FLOAT = new Directives(".float", "Store the listed value(s) as single precision floating point");
+ public static final Directives EXTERN = new Directives(".extern", "Declare the listed label and byte length to be a global data field");
+ public static final Directives KDATA = new Directives(".kdata", "Subsequent items stored in Kernel Data segment at next available address");
+ public static final Directives KTEXT = new Directives(".ktext", "Subsequent items (instructions) stored in Kernel Text segment at next available address");
+ public static final Directives GLOBL = new Directives(".globl", "Declare the listed label(s) as global to enable referencing from other files");
+ public static final Directives SET = new Directives(".set", "Set assembler variables. Currently ignored but included for SPIM compatability");
+ /* EQV added by DPS 11 July 2012 */
+ public static final Directives EQV = new Directives(".eqv", "Substitute second operand for first. First operand is symbol, second operand is expression (like #define)");
+ /* MACRO and END_MACRO added by Mohammad Sekhavat Oct 2012 */
+ public static final Directives MACRO = new Directives(".macro", "Begin macro definition. See .end_macro");
+ public static final Directives END_MACRO = new Directives(".end_macro", "End macro definition. See .macro");
+ /* INCLUDE added by DPS 11 Jan 2013 */
+ public static final Directives INCLUDE = new Directives(".include", "Insert the contents of the specified file. Put filename in quotes.");
+
+ private String descriptor;
+ private String description; // help text
+
+ private Directives() {
+ // private ctor assures no objects can be created other than those above.
+ this.descriptor = "generic";
+ this.description = "";
+ directiveList.add(this);
+ }
+
+ private Directives(String name, String description) {
+ this.descriptor = name;
+ this.description = description;
+ directiveList.add(this);
+ }
+
+ /**
+ * Find Directive object, if any, which matches the given String.
+ *
+ * @param str A String containing candidate directive name (e.g. ".ascii")
+ * @return If match is found, returns matching Directives object, else returns null.
+ **/
+
+ public static Directives matchDirective(String str) {
+ Directives match;
+ for (int i = 0; i < directiveList.size(); i++) {
+ match = directiveList.get(i);
if (str.equalsIgnoreCase(match.descriptor)) {
- return match;
+ return match;
}
- }
- return null;
- }
-
-
- /**
- * Find Directive object, if any, which contains the given string as a prefix. For example,
- * ".a" will match ".ascii", ".asciiz" and ".align"
+ }
+ return null;
+ }
+
+ /**
+ * Find Directive object, if any, which contains the given string as a prefix. For example,
+ * ".a" will match ".ascii", ".asciiz" and ".align"
+ *
+ * @param str A String
+ * @return If match is found, returns ArrayList of matching Directives objects, else returns null.
+ **/
+
+ public static ArrayList prefixMatchDirectives(String str) {
+ ArrayList matches = null;
+ for (int i = 0; i < directiveList.size(); i++) {
+ if (directiveList.get(i).descriptor.toLowerCase().startsWith(str.toLowerCase())) {
+ if (matches == null) {
+ matches = new ArrayList<>();
+ }
+ matches.add(directiveList.get(i));
+ }
+ }
+ return matches;
+ }
+
+ /**
+ * Produces String-ified version of Directive object
*
- * @param str A String
- * @return If match is found, returns ArrayList of matching Directives objects, else returns null.
+ * @return String representing Directive: its MIPS name
**/
-
- public static ArrayList prefixMatchDirectives(String str) {
- ArrayList matches = null;
- for (int i=0; i getDirectiveList() {
+ return directiveList;
+ }
+
+ /**
+ * Lets you know whether given directive is for integer (WORD,HALF,BYTE).
+ *
+ * @param direct a MIPS directive
+ * @return true if given directive is FLOAT or DOUBLE, false otherwise
+ **/
+ public static boolean isIntegerDirective(Directives direct) {
+ return direct == Directives.WORD || direct == Directives.HALF || direct == Directives.BYTE;
+ }
+
+ /**
+ * Lets you know whether given directive is for floating number (FLOAT,DOUBLE).
+ *
+ * @param direct a MIPS directive
+ * @return true if given directive is FLOAT or DOUBLE, false otherwise.
+ **/
+ public static boolean isFloatingDirective(Directives direct) {
+ return direct == Directives.FLOAT || direct == Directives.DOUBLE;
+ }
+
+}
diff --git a/src/mars/assembler/MacroPool.java b/src/mars/assembler/MacroPool.java
index c524309..f3a5d00 100644
--- a/src/mars/assembler/MacroPool.java
+++ b/src/mars/assembler/MacroPool.java
@@ -1,10 +1,10 @@
- package mars.assembler;
+package mars.assembler;
- import java.util.ArrayList;
- import java.util.Stack;
+import java.util.ArrayList;
+import java.util.Stack;
- import mars.ErrorList;
- import mars.MIPSprogram;
+import mars.ErrorList;
+import mars.MIPSprogram;
/*
Copyright (c) 2013.
@@ -46,157 +46,150 @@ a copy of this software and associated documentation files (the
*
* @author M.H.Sekhavat
*/
- public class MacroPool {
- private MIPSprogram program;
- /**
- * List of macros defined by now
- */
- private ArrayList macroList;
- /**
- * @see #BeginMacro(String, int)
- */
- private Macro current;
- private ArrayList callStack;
- private ArrayList callStackOrigLines;
- /**
- * @see #getNextCounter()
- */
- private int counter;
-
-
- /**
- * Create an empty MacroPool for given program
- * @param mipsProgram associated MIPS program
- */
- public MacroPool(MIPSprogram mipsProgram) {
- this.program = mipsProgram;
- macroList = new ArrayList();
- callStack=new ArrayList();
- callStackOrigLines=new ArrayList();
- current = null;
- counter = 0;
- }
-
- /**
- * This method will be called by parser when reached .macro
- * directive.
- * Instantiates a new {@link Macro} object and stores it in {@link #current}
- * . {@link #current} will be added to {@link #macroList} by
- * {@link #CommitMacro(int)}
- *
- * @param nameToken
- * Token containing name of macro after .macro
directive
- */
-
- public void beginMacro(Token nameToken) {
- current = new Macro();
- current.setName(nameToken.getValue());
- current.setFromLine(nameToken.getSourceLine());
- current.setOriginalFromLine(nameToken.getOriginalSourceLine());
- current.setProgram(program);
- }
-
- /**
- * This method will be called by parser when reached .end_macro
- * directive.
- * Adds/Replaces {@link #current} macro into the {@link #macroList}.
- *
- * @param endToken
- * Token containing .end_macro
directive in source code
- */
-
- public void commitMacro(Token endToken) {
- current.setToLine(endToken.getSourceLine());
- current.setOriginalToLine(endToken.getOriginalSourceLine());
- current.readyForCommit();
- macroList.add(current);
- current = null;
- }
-
- /**
- * Will be called by parser when reaches a macro expansion call
- *
- * @param tokens
- * tokens passed to macro expansion call
- * @return {@link Macro} object matching the name and argument count of
- * tokens passed
- */
- public Macro getMatchingMacro(TokenList tokens, int callerLine) {
- if (tokens.size() < 1)
+public class MacroPool {
+ private MIPSprogram program;
+ /**
+ * List of macros defined by now
+ */
+ private ArrayList macroList;
+ /**
+ * @see #BeginMacro(String, int)
+ */
+ private Macro current;
+ private ArrayList callStack;
+ private ArrayList callStackOrigLines;
+ /**
+ * @see #getNextCounter()
+ */
+ private int counter;
+
+ /**
+ * Create an empty MacroPool for given program
+ * @param mipsProgram associated MIPS program
+ */
+ public MacroPool(MIPSprogram mipsProgram) {
+ this.program = mipsProgram;
+ macroList = new ArrayList<>();
+ callStack = new ArrayList<>();
+ callStackOrigLines = new ArrayList<>();
+ current = null;
+ counter = 0;
+ }
+
+ /**
+ * This method will be called by parser when reached .macro
+ * directive.
+ * Instantiates a new {@link Macro} object and stores it in {@link #current}
+ * . {@link #current} will be added to {@link #macroList} by
+ * {@link #CommitMacro(int)}
+ *
+ * @param nameToken
+ * Token containing name of macro after .macro
directive
+ */
+ public void beginMacro(Token nameToken) {
+ current = new Macro();
+ current.setName(nameToken.getValue());
+ current.setFromLine(nameToken.getSourceLine());
+ current.setOriginalFromLine(nameToken.getOriginalSourceLine());
+ current.setProgram(program);
+ }
+
+ /**
+ * This method will be called by parser when reached .end_macro
+ * directive.
+ * Adds/Replaces {@link #current} macro into the {@link #macroList}.
+ *
+ * @param endToken
+ * Token containing .end_macro
directive in source code
+ */
+ public void commitMacro(Token endToken) {
+ current.setToLine(endToken.getSourceLine());
+ current.setOriginalToLine(endToken.getOriginalSourceLine());
+ current.readyForCommit();
+ macroList.add(current);
+ current = null;
+ }
+
+ /**
+ * Will be called by parser when reaches a macro expansion call
+ *
+ * @param tokens
+ * tokens passed to macro expansion call
+ * @return {@link Macro} object matching the name and argument count of
+ * tokens passed
+ */
+ public Macro getMatchingMacro(TokenList tokens, int callerLine) {
+ if (tokens.size() < 1)
return null;
- Macro ret = null;
- Token firstToken = tokens.get(0);
- for (Macro macro : macroList) {
+ Macro ret = null;
+ Token firstToken = tokens.get(0);
+ for (Macro macro : macroList) {
if (macro.getName().equals(firstToken.getValue())
- && macro.getArgs().size() + 1 == tokens.size()
- //&& macro.getToLine() < callerLine // condition removed; doesn't work nicely in conjunction with .include, and does not seem necessary. DPS 8-MAR-2013
- && (ret == null || ret.getFromLine() < macro.getFromLine()))
- ret = macro;
- }
- return ret;
- }
-
- /**
- * @param value
- * @return true if any macros have been defined with name value
- * by now, not concerning arguments count.
- */
- public boolean matchesAnyMacroName(String value) {
- for (Macro macro : macroList)
+ && macro.getArgs().size() + 1 == tokens.size()
+ //&& macro.getToLine() < callerLine // condition removed; doesn't work nicely in conjunction with .include, and does not seem necessary. DPS 8-MAR-2013
+ && (ret == null || ret.getFromLine() < macro.getFromLine()))
+ ret = macro;
+ }
+ return ret;
+ }
+
+ /**
+ * @param value
+ * @return true if any macros have been defined with name value
+ * by now, not concerning arguments count.
+ */
+ public boolean matchesAnyMacroName(String value) {
+ for (Macro macro : macroList)
if (macro.getName().equals(value))
- return true;
- return false;
- }
-
-
- public Macro getCurrent() {
- return current;
- }
-
- public void setCurrent(Macro current) {
- this.current = current;
- }
-
- /**
- * {@link #counter} will be set to 0 on construction of this class and will
- * be incremented by each call. parser calls this method once for every
- * expansions. it will be a unique id for each expansion of macro in a file
- *
- * @return counter value
- */
- public int getNextCounter() {
- return counter++;
- }
-
-
- public ArrayList getCallStack() {
- return callStack;
- }
-
-
- public boolean pushOnCallStack(Token token) { //returns true if detected expansion loop
- int sourceLine = token.getSourceLine();
- int origSourceLine = token.getOriginalSourceLine();
- if (callStack.contains(sourceLine))
+ return true;
+ return false;
+ }
+
+ public Macro getCurrent() {
+ return current;
+ }
+
+ public void setCurrent(Macro current) {
+ this.current = current;
+ }
+
+ /**
+ * {@link #counter} will be set to 0 on construction of this class and will
+ * be incremented by each call. parser calls this method once for every
+ * expansions. it will be a unique id for each expansion of macro in a file
+ *
+ * @return counter value
+ */
+ public int getNextCounter() {
+ return counter++;
+ }
+
+ public ArrayList getCallStack() {
+ return callStack;
+ }
+
+ public boolean pushOnCallStack(Token token) { //returns true if detected expansion loop
+ int sourceLine = token.getSourceLine();
+ int origSourceLine = token.getOriginalSourceLine();
+ if (callStack.contains(sourceLine))
return true;
- callStack.add(sourceLine);
- callStackOrigLines.add(origSourceLine);
- return false;
- }
-
- public void popFromCallStack() {
- callStack.remove(callStack.size()-1);
- callStackOrigLines.remove(callStackOrigLines.size()-1);
- }
-
-
- public String getExpansionHistory() {
- String ret="";
- for (int i=0; i0)
- ret+="->";
+ ret+="->";
ret+=callStackOrigLines.get(i).toString();
- }
- return ret;
- }
- }
+ }
+ return ret;
+ }
+}
diff --git a/src/mars/assembler/OperandFormat.java b/src/mars/assembler/OperandFormat.java
index 0965edc..a581f7d 100644
--- a/src/mars/assembler/OperandFormat.java
+++ b/src/mars/assembler/OperandFormat.java
@@ -69,17 +69,17 @@ static boolean tokenOperandMatch(TokenList candidateList, Instruction inst, Erro
* 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) {
+ static Instruction bestOperandMatch(TokenList tokenList, ArrayList instrMatches) {
if (instrMatches == null)
return null;
if (instrMatches.size() == 1)
- return (Instruction) instrMatches.get(0);
+ return instrMatches.get(0);
for (int i=0; i table;
+ // Note -1 is legal 32 bit address (0xFFFFFFFF) but it is the high address in
+ // kernel address space so highly unlikely that any symbol will have this as
+ // its associated address!
+ public static final int NOT_FOUND = -1;
- public class SymbolTable {
- private static String startLabel = "main";
- private String filename;
- private ArrayList table;
- // Note -1 is legal 32 bit address (0xFFFFFFFF) but it is the high address in
- // kernel address space so highly unlikely that any symbol will have this as
- // its associated address!
- public static final int NOT_FOUND = -1;
-
- /**
- * Create a new empty symbol table for given file
- * @param filename name of file this symbol table is associated with. Will be
- * used only for output/display so it can be any descriptive string.
- */
- public SymbolTable(String filename) {
- this.filename = filename;
- this.table = new ArrayList();
- }
- /**
- * Adds a Symbol object into the array of Symbols.
- * @param token The token representing the Symbol.
- * @param address The address of the Symbol.
- * @param b The type of Symbol, true for data, false for text.
- * @param errors List to which to add any processing errors that occur.
- **/
-
- public void addSymbol(Token token, int address, boolean b, ErrorList errors) {
- String label = token.getValue();
- if (getSymbol(label) != null) {
+ /**
+ * Create a new empty symbol table for given file
+ * @param filename name of file this symbol table is associated with. Will be
+ * used only for output/display so it can be any descriptive string.
+ */
+ public SymbolTable(String filename) {
+ this.filename = filename;
+ this.table = new ArrayList<>();
+ }
+ /**
+ * Adds a Symbol object into the array of Symbols.
+ * @param token The token representing the Symbol.
+ * @param address The address of the Symbol.
+ * @param b The type of Symbol, true for data, false for text.
+ * @param errors List to which to add any processing errors that occur.
+ **/
+
+ public void addSymbol(Token token, int address, boolean b, ErrorList errors) {
+ String label = token.getValue();
+ if (getSymbol(label) != null) {
errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),token.getStartPos(),"label \""+label+"\" already defined"));
- }
- else {
+ }
+ else {
Symbol s= new Symbol(label, address, b);
table.add(s);
if (Globals.debug) System.out.println("The symbol " + label + " with address " + address + " has been added to the "+this.filename+" symbol table.");
- }
- }
-
-
- /**
- * Removes a symbol from the Symbol table. If not found, it does nothing.
- * This will rarely happen (only when variable is declared .globl after already
- * being defined in the local symbol table).
- * @param token The token representing the Symbol.
- **/
-
- public void removeSymbol(Token token) {
- String label = token.getValue();
- for (int i=0; i < table.size(); i++) {
+ }
+ }
+
+
+ /**
+ * Removes a symbol from the Symbol table. If not found, it does nothing.
+ * This will rarely happen (only when variable is declared .globl after already
+ * being defined in the local symbol table).
+ * @param token The token representing the Symbol.
+ **/
+
+ public void removeSymbol(Token token) {
+ String label = token.getValue();
+ for (int i=0; i < table.size(); i++) {
if (((Symbol)(table.get(i))).getName().equals(label)){
- table.remove(i);
- if (Globals.debug) System.out.println("The symbol " + label + " has been removed from the "+this.filename+" symbol table.");
- break;
+ table.remove(i);
+ if (Globals.debug) System.out.println("The symbol " + label + " has been removed from the "+this.filename+" symbol table.");
+ break;
}
- }
- return;
- }
-
-
- /**
- * Method to return the address associated with the given label.
- * @param s The label.
- * @return The memory address of the label given, or NOT_FOUND if not found in symbol table.
- **/
- public int getAddress(String s){
- for(int i=0; i < table.size(); i++){
+ }
+ return;
+ }
+
+
+ /**
+ * Method to return the address associated with the given label.
+ * @param s The label.
+ * @return The memory address of the label given, or NOT_FOUND if not found in symbol table.
+ **/
+ public int getAddress(String s){
+ for(int i=0; i < table.size(); i++){
if (((Symbol)(table.get(i))).getName().equals(s)){
- return((Symbol) table.get(i)).getAddress();
+ return((Symbol) table.get(i)).getAddress();
}
- }
- return NOT_FOUND;
- }
-
- /**
- * Method to return the address associated with the given label. Look first
- * in this (local) symbol table then in symbol table of labels declared
- * global (.globl directive).
- * @param s The label.
- * @return The memory address of the label given, or NOT_FOUND if not found in symbol table.
- **/
- public int getAddressLocalOrGlobal(String s) {
- int address = this.getAddress(s);
- return (address==NOT_FOUND) ? Globals.symbolTable.getAddress(s) : address ;
- }
-
-
- /**
- * Produce Symbol object from symbol table that corresponds to given String.
- * @param s target String
- * @return Symbol object for requested target, null if not found in symbol table.
- **/
-
- public Symbol getSymbol(String s){
- for(int i=0; i < table.size(); i++){
+ }
+ return NOT_FOUND;
+ }
+
+ /**
+ * Method to return the address associated with the given label. Look first
+ * in this (local) symbol table then in symbol table of labels declared
+ * global (.globl directive).
+ * @param s The label.
+ * @return The memory address of the label given, or NOT_FOUND if not found in symbol table.
+ **/
+ public int getAddressLocalOrGlobal(String s) {
+ int address = this.getAddress(s);
+ return (address==NOT_FOUND) ? Globals.symbolTable.getAddress(s) : address ;
+ }
+
+
+ /**
+ * Produce Symbol object from symbol table that corresponds to given String.
+ * @param s target String
+ * @return Symbol object for requested target, null if not found in symbol table.
+ **/
+
+ public Symbol getSymbol(String s){
+ for(int i=0; i < table.size(); i++){
if (((Symbol)(table.get(i))).getName().equals(s)){
- return (Symbol) table.get(i);
+ return (Symbol) table.get(i);
}
- }
- return null;
- }
-
- /**
- * Produce Symbol object from symbol table that has the given address.
- * @param s String representing address
- * @return Symbol object having requested address, null if address not found in symbol table.
- **/
-
- public Symbol getSymbolGivenAddress(String s){
- int address = 0;
- try {
+ }
+ return null;
+ }
+
+ /**
+ * Produce Symbol object from symbol table that has the given address.
+ * @param s String representing address
+ * @return Symbol object having requested address, null if address not found in symbol table.
+ **/
+
+ public Symbol getSymbolGivenAddress(String s){
+ int address = 0;
+ try {
address = mars.util.Binary.stringToInt(s);// DPS 2-Aug-2010: was Integer.parseInt(s) but croaked on hex
- }
- catch (NumberFormatException e) {
- return null;
+ }
+ catch (NumberFormatException e) {
+ return null;
}
- for(int i=0; i < table.size(); i++){
+ for(int i=0; i < table.size(); i++){
if (((Symbol)(table.get(i))).getAddress() == address){
- return (Symbol) table.get(i);
+ return (Symbol) table.get(i);
}
- }
- return null;
- }
-
- /**
- * Produce Symbol object from either local or global symbol table that has the
- * given address.
- * @param s String representing address
- * @return Symbol object having requested address, null if address not found in symbol table.
- **/
- public Symbol getSymbolGivenAddressLocalOrGlobal(String s){
- Symbol sym = this.getSymbolGivenAddress(s);
- return (sym==null) ? Globals.symbolTable.getSymbolGivenAddress(s) : sym ;
- }
-
-
-
- /**
- * For obtaining the Data Symbols.
- * @return An ArrayList of Symbol objects.
- **/
-
- public ArrayList getDataSymbols(){
- ArrayList list= new ArrayList();
- for(int i=0; i getDataSymbols(){
+ ArrayList list= new ArrayList<>();
+ for(int i=0; i getTextSymbols(){
+ ArrayList list= new ArrayList<>();
+ for(int i=0; i getAllSymbols(){
+ ArrayList list= new ArrayList<>();
+ for(int i=0; i();
+ }
+
+/**
+ * Fix address in symbol table entry. Any and all entries that match the original
+ * address will be modified to contain the replacement address. There is no effect,
+ * if none of the addresses matches.
+ * @param originalAddress Address associated with 0 or more symtab entries.
+ * @param replacementAddress Any entry that has originalAddress will have its
+ * address updated to this value. Does nothing if none do.
+ */
+
+ public void fixSymbolTableAddress(int originalAddress, int replacementAddress) {
+ Symbol label = getSymbolGivenAddress(Integer.toString(originalAddress));
+ while (label != null) {
label.setAddress(replacementAddress);
label = getSymbolGivenAddress(Integer.toString(originalAddress));
- }
- return;
- }
-
- /**
- * Fetches the text segment label (symbol) which, if declared global, indicates
- * the starting address for execution.
- * @return String containing global label whose text segment address is starting address for program execution.
- **/
- public static String getStartLabel() {
- return startLabel;
- }
- }
\ No newline at end of file
+ }
+ return;
+ }
+
+ /**
+ * Fetches the text segment label (symbol) which, if declared global, indicates
+ * the starting address for execution.
+ * @return String containing global label whose text segment address is starting address for program execution.
+ **/
+ public static String getStartLabel() {
+ return startLabel;
+ }
+}
diff --git a/src/mars/assembler/TokenList.java b/src/mars/assembler/TokenList.java
index 1438000..0f7c44d 100644
--- a/src/mars/assembler/TokenList.java
+++ b/src/mars/assembler/TokenList.java
@@ -39,14 +39,14 @@ a copy of this software and associated documentation files (the
public class TokenList implements Cloneable {
- private ArrayList tokenList;
+ private ArrayList tokenList;
private String processedLine;// DPS 03-Jan-2013
/**
* Constructor for objects of class TokenList
*/
public TokenList() {
- tokenList = new ArrayList();
+ tokenList = new ArrayList<>();
processedLine = ""; // DPS 03-Jan-2013
}
@@ -79,7 +79,7 @@ public String getProcessedLine() {
* @return the requested token, or ArrayIndexOutOfBounds exception
*/
public Token get(int pos) {
- return (Token) tokenList.get(pos);
+ return tokenList.get(pos);
}
/**
@@ -156,7 +156,7 @@ public String toString() {
public String toTypeString() {
String stringified = "";
for (int i=0; i) tokenList.clone();
return t;
} catch (CloneNotSupportedException e) {
return null;
diff --git a/src/mars/assembler/TokenTypes.java b/src/mars/assembler/TokenTypes.java
index ed25b0e..bd7a17a 100644
--- a/src/mars/assembler/TokenTypes.java
+++ b/src/mars/assembler/TokenTypes.java
@@ -1,9 +1,10 @@
- package mars.assembler;
- import mars.*;
- import mars.util.*;
- import mars.mips.hardware.*;
-
- /*
+package mars.assembler;
+import mars.*;
+import mars.util.*;
+import mars.mips.hardware.*;
+import java.util.ArrayList;
+
+/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
Developed by Pete Sanderson (psanderson@otterbein.edu)
@@ -30,7 +31,7 @@ a copy of this software and associated documentation files (the
(MIT license, http://www.opensource.org/licenses/mit-license.html)
*/
-
+
/**
* Constants to identify the types of tokens found in MIPS programs. If Java had
* enumerated types, that's how these would probably be implemented.
@@ -39,57 +40,57 @@ a copy of this software and associated documentation files (the
* @version August 2003
**/
- public final class TokenTypes {
-
- public static final String TOKEN_DELIMITERS = "\t ,()";
- public static final TokenTypes COMMENT = new TokenTypes("COMMENT");
- public static final TokenTypes DIRECTIVE = new TokenTypes("DIRECTIVE");
- public static final TokenTypes OPERATOR = new TokenTypes("OPERATOR");
- public static final TokenTypes DELIMITER = new TokenTypes("DELIMITER");
- /** note: REGISTER_NAME is token of form $zero whereas REGISTER_NUMBER is token
- * of form $0. The former is part of extended assembler, and latter is part
- * of basic assembler.
- **/
- public static final TokenTypes REGISTER_NAME = new TokenTypes("REGISTER_NAME"); // mnemonic
- public static final TokenTypes REGISTER_NUMBER = new TokenTypes("REGISTER_NUMBER");
- public static final TokenTypes FP_REGISTER_NAME = new TokenTypes("FP_REGISTER_NAME");
- public static final TokenTypes IDENTIFIER = new TokenTypes("IDENTIFIER");
- public static final TokenTypes LEFT_PAREN = new TokenTypes("LEFT_PAREN");
- public static final TokenTypes RIGHT_PAREN = new TokenTypes("RIGHT_PAREN");
- //public static final TokenTypes INTEGER = new TokenTypes("INTEGER");
- public static final TokenTypes INTEGER_5 = new TokenTypes("INTEGER_5");
- public static final TokenTypes INTEGER_16 = new TokenTypes("INTEGER_16");
- public static final TokenTypes INTEGER_16U = new TokenTypes("INTEGER_16U");
- public static final TokenTypes INTEGER_32 = new TokenTypes("INTEGER_32");
- public static final TokenTypes REAL_NUMBER = new TokenTypes("REAL_NUMBER");
- public static final TokenTypes QUOTED_STRING = new TokenTypes("QUOTED_STRING");
- public static final TokenTypes PLUS = new TokenTypes("PLUS");
- public static final TokenTypes MINUS = new TokenTypes("MINUS");
- public static final TokenTypes COLON = new TokenTypes("COLON");
- public static final TokenTypes ERROR = new TokenTypes("ERROR");
- public static final TokenTypes MACRO_PARAMETER = new TokenTypes("MACRO_PARAMETER");
-
- private String descriptor;
-
- private TokenTypes() {
- // private ctor assures no objects can be created other than those above.
- descriptor = "generic";
- }
-
- private TokenTypes(String name) {
- descriptor = name;
- }
-
- /**
+public final class TokenTypes {
+
+ public static final String TOKEN_DELIMITERS = "\t ,()";
+ public static final TokenTypes COMMENT = new TokenTypes("COMMENT");
+ public static final TokenTypes DIRECTIVE = new TokenTypes("DIRECTIVE");
+ public static final TokenTypes OPERATOR = new TokenTypes("OPERATOR");
+ public static final TokenTypes DELIMITER = new TokenTypes("DELIMITER");
+ /** note: REGISTER_NAME is token of form $zero whereas REGISTER_NUMBER is token
+ * of form $0. The former is part of extended assembler, and latter is part
+ * of basic assembler.
+ **/
+ public static final TokenTypes REGISTER_NAME = new TokenTypes("REGISTER_NAME"); // mnemonic
+ public static final TokenTypes REGISTER_NUMBER = new TokenTypes("REGISTER_NUMBER");
+ public static final TokenTypes FP_REGISTER_NAME = new TokenTypes("FP_REGISTER_NAME");
+ public static final TokenTypes IDENTIFIER = new TokenTypes("IDENTIFIER");
+ public static final TokenTypes LEFT_PAREN = new TokenTypes("LEFT_PAREN");
+ public static final TokenTypes RIGHT_PAREN = new TokenTypes("RIGHT_PAREN");
+ //public static final TokenTypes INTEGER = new TokenTypes("INTEGER");
+ public static final TokenTypes INTEGER_5 = new TokenTypes("INTEGER_5");
+ public static final TokenTypes INTEGER_16 = new TokenTypes("INTEGER_16");
+ public static final TokenTypes INTEGER_16U = new TokenTypes("INTEGER_16U");
+ public static final TokenTypes INTEGER_32 = new TokenTypes("INTEGER_32");
+ public static final TokenTypes REAL_NUMBER = new TokenTypes("REAL_NUMBER");
+ public static final TokenTypes QUOTED_STRING = new TokenTypes("QUOTED_STRING");
+ public static final TokenTypes PLUS = new TokenTypes("PLUS");
+ public static final TokenTypes MINUS = new TokenTypes("MINUS");
+ public static final TokenTypes COLON = new TokenTypes("COLON");
+ public static final TokenTypes ERROR = new TokenTypes("ERROR");
+ public static final TokenTypes MACRO_PARAMETER = new TokenTypes("MACRO_PARAMETER");
+
+ private String descriptor;
+
+ private TokenTypes() {
+ // private ctor assures no objects can be created other than those above.
+ descriptor = "generic";
+ }
+
+ private TokenTypes(String name) {
+ descriptor = name;
+ }
+
+ /**
* Produces String equivalent of this token type, which is its name.
*
* @return String containing descriptive name for token type.
**/
- public String toString() {
- return descriptor;
- }
-
- /**
+ public String toString() {
+ return descriptor;
+ }
+
+ /**
* Classifies the given token into one of the MIPS types.
*
* @param value String containing candidate language element, extracted from MIPS program.
@@ -98,196 +99,196 @@ public String toString() {
* defined MIPS token type, else returns null.
**/
- public static TokenTypes matchTokenType(String value)
- {
-
- TokenTypes type = null;
- // If it starts with single quote ('), it is a mal-formed character literal
- // because a well-formed character literal was converted to string-ified
- // integer before getting here...
- if (value.charAt(0) == '\'')
- return TokenTypes.ERROR;
-
- // See if it is a comment
- if (value.charAt(0) == '#')
+ public static TokenTypes matchTokenType(String value)
+ {
+
+ TokenTypes type = null;
+ // If it starts with single quote ('), it is a mal-formed character literal
+ // because a well-formed character literal was converted to string-ified
+ // integer before getting here...
+ if (value.charAt(0) == '\'')
+ return TokenTypes.ERROR;
+
+ // See if it is a comment
+ if (value.charAt(0) == '#')
return TokenTypes.COMMENT;
-
- // See if it is one of the simple tokens
- if (value.length() == 1) {
+
+ // See if it is one of the simple tokens
+ if (value.length() == 1) {
switch (value.charAt(0)) {
- case '(' :
- return TokenTypes.LEFT_PAREN;
- case ')' :
- return TokenTypes.RIGHT_PAREN;
- case ':' :
- return TokenTypes.COLON;
- case '+' :
- return TokenTypes.PLUS;
- case '-' :
- return TokenTypes.MINUS;
+ case '(' :
+ return TokenTypes.LEFT_PAREN;
+ case ')' :
+ return TokenTypes.RIGHT_PAREN;
+ case ':' :
+ return TokenTypes.COLON;
+ case '+' :
+ return TokenTypes.PLUS;
+ case '-' :
+ return TokenTypes.MINUS;
}
- }
+ }
- // See if it is a macro parameter
- if (Macro.tokenIsMacroParameter(value, false))
- return TokenTypes.MACRO_PARAMETER;
-
- // See if it is a register
- Register reg = RegisterFile.getUserRegister(value);
- if (reg != null)
+ // See if it is a macro parameter
+ if (Macro.tokenIsMacroParameter(value, false))
+ return TokenTypes.MACRO_PARAMETER;
+
+ // See if it is a register
+ Register reg = RegisterFile.getUserRegister(value);
+ if (reg != null)
if (reg.getName().equals(value))
- return TokenTypes.REGISTER_NAME;
+ return TokenTypes.REGISTER_NAME;
else
- return TokenTypes.REGISTER_NUMBER;
-
- // See if it is a floating point register
-
- reg = Coprocessor1.getRegister(value);
- if (reg != null)
+ return TokenTypes.REGISTER_NUMBER;
+
+ // See if it is a floating point register
+
+ reg = Coprocessor1.getRegister(value);
+ if (reg != null)
return TokenTypes.FP_REGISTER_NAME;
-
- // See if it is an immediate (constant) integer value
- // Classify based on # bits needed to represent in binary
- // This is needed because most immediate operands limited to 16 bits
- // others limited to 5 bits unsigned (shift amounts) others 32 bits.
- try {
+
+ // See if it is an immediate (constant) integer value
+ // Classify based on # bits needed to represent in binary
+ // This is needed because most immediate operands limited to 16 bits
+ // others limited to 5 bits unsigned (shift amounts) others 32 bits.
+ try {
int i = Binary.stringToInt(value); // KENV 1/6/05
-
- /***************************************************************************
- * MODIFICATION AND COMMENT, DPS 3-July-2008
- *
- * The modifications of January 2005 documented below are being rescinded.
- * All hexadecimal immediate values are considered 32 bits in length and
- * their classification as INTEGER_5, INTEGER_16, INTEGER_16U (new)
- * or INTEGER_32 depends on their 32 bit value. So 0xFFFF will be
- * equivalent to 0x0000FFFF instead of 0xFFFFFFFF. This change, along with
- * the introduction of INTEGER_16U (adopted from Greg Gibeling of Berkeley),
- * required extensive changes to instruction templates especially for
- * pseudo-instructions.
- *
- * This modification also appears inbuildBasicStatementFromBasicInstruction()
- * in mars.ProgramStatement.
- *
- * ///// Begin modification 1/4/05 KENV ///////////////////////////////////////////
- * // We have decided to interpret non-signed (no + or -) 16-bit hexadecimal immediate
- * // operands as signed values in the range -32768 to 32767. So 0xffff will represent
- * // -1, not 65535 (bit 15 as sign bit), 0x8000 will represent -32768 not 32768.
- * // NOTE: 32-bit hexadecimal immediate operands whose values fall into this range
- * // will be likewise affected, but they are used only in pseudo-instructions. The
- * // code in ExtendedInstruction.java to split this number into upper 16 bits for "lui"
- * // and lower 16 bits for "ori" works with the original source code token, so it is
- * // not affected by this tweak. 32-bit immediates in data segment directives
- * // are also processed elsewhere so are not affected either.
- * ////////////////////////////////////////////////////////////////////////////////
- *
- * if ( Binary.isHex(value) &&
- * (i >= 32768) &&
- * (i <= 65535) ) // Range 0x8000 ... 0xffff
- * {
- * // Subtract the 0xffff bias, because strings in the
- * // range "0x8000" ... "0xffff" are used to represent
- * // 16-bit negative numbers, not positive numbers.
- * i = i - 65536;
- * }
- * // ------------- END KENV 1/4/05 MODIFICATIONS --------------
- *
- ************************** END DPS 3-July-2008 COMMENTS *******************************/
- // shift operands must be in range 0-31
+
+ /***************************************************************************
+ * MODIFICATION AND COMMENT, DPS 3-July-2008
+ *
+ * The modifications of January 2005 documented below are being rescinded.
+ * All hexadecimal immediate values are considered 32 bits in length and
+ * their classification as INTEGER_5, INTEGER_16, INTEGER_16U (new)
+ * or INTEGER_32 depends on their 32 bit value. So 0xFFFF will be
+ * equivalent to 0x0000FFFF instead of 0xFFFFFFFF. This change, along with
+ * the introduction of INTEGER_16U (adopted from Greg Gibeling of Berkeley),
+ * required extensive changes to instruction templates especially for
+ * pseudo-instructions.
+ *
+ * This modification also appears inbuildBasicStatementFromBasicInstruction()
+ * in mars.ProgramStatement.
+ *
+ * ///// Begin modification 1/4/05 KENV ///////////////////////////////////////////
+ * // We have decided to interpret non-signed (no + or -) 16-bit hexadecimal immediate
+ * // operands as signed values in the range -32768 to 32767. So 0xffff will represent
+ * // -1, not 65535 (bit 15 as sign bit), 0x8000 will represent -32768 not 32768.
+ * // NOTE: 32-bit hexadecimal immediate operands whose values fall into this range
+ * // will be likewise affected, but they are used only in pseudo-instructions. The
+ * // code in ExtendedInstruction.java to split this number into upper 16 bits for "lui"
+ * // and lower 16 bits for "ori" works with the original source code token, so it is
+ * // not affected by this tweak. 32-bit immediates in data segment directives
+ * // are also processed elsewhere so are not affected either.
+ * ////////////////////////////////////////////////////////////////////////////////
+ *
+ * if ( Binary.isHex(value) &&
+ * (i >= 32768) &&
+ * (i <= 65535) ) // Range 0x8000 ... 0xffff
+ * {
+ * // Subtract the 0xffff bias, because strings in the
+ * // range "0x8000" ... "0xffff" are used to represent
+ * // 16-bit negative numbers, not positive numbers.
+ * i = i - 65536;
+ * }
+ * // ------------- END KENV 1/4/05 MODIFICATIONS --------------
+ *
+ ************************** END DPS 3-July-2008 COMMENTS *******************************/
+ // shift operands must be in range 0-31
if (i>=0 && i<=31) {
- return TokenTypes.INTEGER_5;
+ return TokenTypes.INTEGER_5;
}
if (i>=DataTypes.MIN_UHALF_VALUE && i<=DataTypes.MAX_UHALF_VALUE) {
return TokenTypes.INTEGER_16U;
- }
+ }
if (i>=DataTypes.MIN_HALF_VALUE && i<=DataTypes.MAX_HALF_VALUE) {
- return TokenTypes.INTEGER_16;
+ return TokenTypes.INTEGER_16;
}
return TokenTypes.INTEGER_32; // default when no other type is applicable
- }
- catch(NumberFormatException e)
- {
- // NO ACTION -- exception suppressed
- }
-
- // See if it is a real (fixed or floating point) number. Note that parseDouble()
- // accepts integer values but if it were an integer literal we wouldn't get this far.
- try {
+ }
+ catch(NumberFormatException e)
+ {
+ // NO ACTION -- exception suppressed
+ }
+
+ // See if it is a real (fixed or floating point) number. Note that parseDouble()
+ // accepts integer values but if it were an integer literal we wouldn't get this far.
+ try {
Double.parseDouble(value);
return TokenTypes.REAL_NUMBER;
- }
- catch (NumberFormatException e)
- {
- // NO ACTION -- exception suppressed
- }
-
- // See if it is an instruction operator
- if (Globals.instructionSet.matchOperator(value) != null)
+ }
+ catch (NumberFormatException e)
+ {
+ // NO ACTION -- exception suppressed
+ }
+
+ // See if it is an instruction operator
+ if (Globals.instructionSet.matchOperator(value) != null)
return TokenTypes.OPERATOR;
-
- // See if it is a directive
- if (value.charAt(0) == '.' && Directives.matchDirective(value) != null) {
+
+ // See if it is a directive
+ if (value.charAt(0) == '.' && Directives.matchDirective(value) != null) {
return TokenTypes.DIRECTIVE;
- }
-
- // See if it is a quoted string
- if (value.charAt(0) == '"')
+ }
+
+ // See if it is a quoted string
+ if (value.charAt(0) == '"')
return TokenTypes.QUOTED_STRING;
-
- // Test for identifier goes last because I have defined tokens for various
- // MIPS constructs (such as operators and directives) that also could fit
- // the lexical specifications of an identifier, and those need to be
- // recognized first.
- if (isValidIdentifier(value))
+
+ // Test for identifier goes last because I have defined tokens for various
+ // MIPS constructs (such as operators and directives) that also could fit
+ // the lexical specifications of an identifier, and those need to be
+ // recognized first.
+ if (isValidIdentifier(value))
return TokenTypes.IDENTIFIER;
-
- // Matches no MIPS language token.
- return TokenTypes.ERROR;
- }
-
- /**
- *
- * Lets you know if given tokentype is for integers (INTGER_5, INTEGER_16, INTEGER_32).
- *
- * @param type the TokenType of interest
- * @return true if type is an integer type, false otherwise.
- **/
- public static boolean isIntegerTokenType(TokenTypes type) {
- return type == TokenTypes.INTEGER_5 || type == TokenTypes.INTEGER_16 ||
- type == TokenTypes.INTEGER_16U || type == TokenTypes.INTEGER_32;
- }
+
+ // Matches no MIPS language token.
+ return TokenTypes.ERROR;
+ }
+
+ /**
+ *
+ * Lets you know if given tokentype is for integers (INTGER_5, INTEGER_16, INTEGER_32).
+ *
+ * @param type the TokenType of interest
+ * @return true if type is an integer type, false otherwise.
+ **/
+ public static boolean isIntegerTokenType(TokenTypes type) {
+ return type == TokenTypes.INTEGER_5 || type == TokenTypes.INTEGER_16 ||
+ type == TokenTypes.INTEGER_16U || type == TokenTypes.INTEGER_32;
+ }
- /**
- *
- * Lets you know if given tokentype is for floating point numbers (REAL_NUMBER).
- *
- * @param type the TokenType of interest
- * @return true if type is an floating point type, false otherwise.
- **/
- public static boolean isFloatingTokenType(TokenTypes type) {
- return type == TokenTypes.REAL_NUMBER;
- }
-
-
- // COD2, A-51: "Identifiers are a sequence of alphanumeric characters,
- // underbars (_), and dots (.) that do not begin with a number."
- // Ideally this would be in a separate Identifier class but I did not see an immediate
- // need beyond this method (refactoring effort would probably identify other uses
- // related to symbol table).
- //
- // DPS 14-Jul-2008: added '$' as valid symbol. Permits labels to include $.
- // MIPS-target GCC will produce labels that start with $.
- public static boolean isValidIdentifier(String value) {
- boolean result =
- (Character.isLetter(value.charAt(0)) || value.charAt(0)=='_' || value.charAt(0)=='.' || value.charAt(0)=='$');
- int index = 1;
- while (result && index < value.length()) {
+ /**
+ *
+ * Lets you know if given tokentype is for floating point numbers (REAL_NUMBER).
+ *
+ * @param type the TokenType of interest
+ * @return true if type is an floating point type, false otherwise.
+ **/
+ public static boolean isFloatingTokenType(TokenTypes type) {
+ return type == TokenTypes.REAL_NUMBER;
+ }
+
+
+ // COD2, A-51: "Identifiers are a sequence of alphanumeric characters,
+ // underbars (_), and dots (.) that do not begin with a number."
+ // Ideally this would be in a separate Identifier class but I did not see an immediate
+ // need beyond this method (refactoring effort would probably identify other uses
+ // related to symbol table).
+ //
+ // DPS 14-Jul-2008: added '$' as valid symbol. Permits labels to include $.
+ // MIPS-target GCC will produce labels that start with $.
+ public static boolean isValidIdentifier(String value) {
+ boolean result =
+ (Character.isLetter(value.charAt(0)) || value.charAt(0)=='_' || value.charAt(0)=='.' || value.charAt(0)=='$');
+ int index = 1;
+ while (result && index < value.length()) {
if (!(Character.isLetterOrDigit(value.charAt(index)) || value.charAt(index)=='_' || value.charAt(index)=='.' || value.charAt(index)=='$'))
- result = false;
+ result = false;
index++;
- }
- return result;
- }
-
- }
+ }
+ return result;
+ }
+
+}