Implement syntax checking
MODIFY
src/asmhighlighter.cpp
src/asmhighlighter.cpp
#include "asmhighlighter.h"
+#include <QList>
#include <QRegularExpressionMatchIterator>
#include "defines.h"
+FieldType::FieldType(Type type, int lowerBound, int upperBound) {
+ m_type = type;
+ m_lowerBound = lowerBound;
+ m_upperBound = upperBound;
+}
+
+QString FieldType::validateField(const QString &field) const {
+ const static auto registerRegex =
+ QRegularExpression("\\b[(a|s|t|x)][0-9]{1,2}");
+
+ switch (m_type) {
+ case Type::Immediate: {
+ // Check that immediate can be converted
+ bool ok = false;
+ auto immediate = field.toInt(&ok, 10);
+ if (!ok) {
+ return QString("Invalid immediate field - got %1").arg(field);
+ }
+ // Check that immediate is within range
+ if (immediate >= m_lowerBound && immediate <= m_upperBound) {
+ return QString();
+ } else {
+ return QString(
+ "Immediate %1 out of valid range; must be within [%2 : %3]")
+ .arg(field)
+ .arg(m_lowerBound)
+ .arg(m_upperBound);
+ }
+ }
+ case Type::Register: {
+ if (!ABInames.contains(field) &&
+ !registerRegex.match(field, 0, QRegularExpression::NormalMatch)
+ .hasMatch()) {
+ return QString("Register %1 is unrecognized").arg(field);
+ } else {
+ return QString();
+ }
+ }
+ case Type::Offset: {
+ return QString();
+ }
+ }
+ return QString("Validation error");
+}
+
AsmHighlighter::AsmHighlighter(QTextDocument *parent)
: QSyntaxHighlighter(parent) {
+ createSyntaxRules();
+ errorFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline);
+ errorFormat.setUnderlineColor(Qt::red);
+
HighlightingRule rule;
// Create rules for name-specific registers
@@ -90,7 +140,10 @@ AsmHighlighter::AsmHighlighter(QTextDocument *parent)
<< "\\bbltu\\b"
<< "\\bbgeu\\b"
<< "\\bsrli\\b"
- << "\\bslli\\b";
+ << "\\bslli\\b"
+ << "\\bor\\b"
+ << "\\badd\\b"
+ << "\\becall\\b";
instrFormat.setForeground(QColor(Colors::BerkeleyBlue));
for (const auto &pattern : instructionPatterns) {
rule.pattern = QRegularExpression(pattern);
@@ -100,7 +153,7 @@ AsmHighlighter::AsmHighlighter(QTextDocument *parent)
// Create rules for registers that can easily be regex matched
// (saved, temporary and argument registers)
- rule.pattern = QRegularExpression("\\b[(a|s|t)][0-9]{1,2}");
+ rule.pattern = QRegularExpression("\\b[(a|s|t|x)][0-9]{1,2}");
rule.format = regFormat;
m_highlightingRules.append(rule);
@@ -118,6 +171,9 @@ AsmHighlighter::AsmHighlighter(QTextDocument *parent)
}
void AsmHighlighter::highlightBlock(const QString &text) {
+ if (checkSyntax(text) != QString()) {
+ setFormat(0, text.length(), errorFormat);
+ } else {
foreach (const HighlightingRule &rule, m_highlightingRules) {
QRegularExpressionMatchIterator matchIterator =
rule.pattern.globalMatch(text);
@@ -127,3 +183,203 @@ void AsmHighlighter::highlightBlock(const QString &text) {
}
}
}
+}
+
+void AsmHighlighter::createSyntaxRules() {
+ // Create syntax rules for all base- and pseudoinstructions
+ auto rule = SyntaxRule();
+ QList<FieldType> types = QList<FieldType>();
+ QStringList names;
+
+ // nop
+ rule.instr = "nop";
+ rule.fields = 1;
+ m_syntaxRules.insert(rule.instr, rule);
+
+ // ecall
+ rule.instr = "ecall";
+ rule.fields = 1;
+ m_syntaxRules.insert(rule.instr, rule);
+
+ // call
+ types.clear();
+ types << FieldType(Type::Offset);
+ rule.instr = "call";
+ rule.fields = 2;
+ m_syntaxRules.insert(rule.instr, rule);
+
+ // jr
+ types.clear();
+ types << FieldType(Type::Register);
+ rule.instr = "jr";
+ rule.fields = 2;
+ m_syntaxRules.insert(rule.instr, rule);
+
+ // j
+ types.clear();
+ types << FieldType(Type::Register);
+ rule.instr = "j";
+ rule.fields = 2;
+ m_syntaxRules.insert(rule.instr, rule);
+
+ // li
+ types.clear();
+ types << FieldType(Type::Register)
+ << FieldType(Type::Immediate, -2147483648, 2147483647);
+ rule.instr = "li";
+ rule.fields = 3;
+ rule.inputs = types;
+ m_syntaxRules.insert(rule.instr, rule);
+
+ // 2-register pseudoinstructions
+ types.clear();
+ names.clear();
+ types << FieldType(Type::Register) << FieldType(Type::Register);
+ names << "mv"
+ << "not"
+ << "neg"
+ << "negw"
+ << "sext"
+ << "seqz"
+ << "snez"
+ << "sltz"
+ << "sgtz";
+ for (const auto &name : names) {
+ rule.instr = name;
+ rule.fields = 3;
+ rule.inputs = types;
+ m_syntaxRules.insert(name, rule);
+ }
+
+ // Branch instructions
+ types.clear();
+ names.clear();
+ types << FieldType(Type::Register) << FieldType(Type::Register)
+ << FieldType(Type::Offset);
+ names << "beg"
+ << "bne"
+ << "blt"
+ << "bge"
+ << "bltu"
+ << "bgeu";
+ for (const auto &name : names) {
+ rule.instr = name;
+ rule.fields = 4;
+ rule.inputs = types;
+ m_syntaxRules.insert(name, rule);
+ }
+
+ // I type instructions
+ types.clear();
+ names.clear();
+ types << FieldType(Type::Register) << FieldType(Type::Register)
+ << FieldType(Type::Immediate, -2048, 2047);
+ names << "addi"
+ << "slti"
+ << "sltiu"
+ << "xori"
+ << "ori"
+ << "andi"
+ << "slli"
+ << "srli"
+ << "srai";
+ for (const auto &name : names) {
+ rule.instr = name;
+ rule.fields = 4;
+ rule.inputs = types;
+ m_syntaxRules.insert(name, rule);
+ }
+
+ // Load instructions
+ types.clear();
+ names.clear();
+ types << FieldType(Type::Register) << FieldType(Type::Immediate, -2048, 2047)
+ << FieldType(Type::Register);
+ names << "lb"
+ << "lh"
+ << "lw"
+ << "lbu"
+ << "lhu";
+
+ for (const auto &name : names) {
+ rule.instr = name;
+ rule.fields = 4;
+ rule.inputs = types;
+ m_syntaxRules.insert(name, rule);
+ }
+
+ // R type instructions
+ types.clear();
+ names.clear();
+ types << FieldType(Type::Register) << FieldType(Type::Register)
+ << FieldType(Type::Register);
+ names << "add"
+ << "sub"
+ << "sll"
+ << "slt"
+ << "sltu"
+ << "xor"
+ << "srl"
+ << "sra"
+ << "or"
+ << "and";
+ for (const auto &name : names) {
+ rule.instr = name;
+ rule.fields = 4;
+ rule.inputs = types;
+ m_syntaxRules.insert(name, rule);
+ }
+
+ // S type instructions
+ types.clear();
+ names.clear();
+ types << FieldType(Type::Register) << FieldType(Type::Immediate, -2048, 2047)
+ << FieldType(Type::Register);
+ names << "sb"
+ << "sh"
+ << "sw";
+ for (const auto &name : names) {
+ rule.instr = name;
+ rule.fields = 4;
+ rule.inputs = types;
+ m_syntaxRules.insert(name, rule);
+ }
+}
+
+QString AsmHighlighter::checkSyntax(const QString &input) {
+ const static auto splitter = QRegularExpression("(\\ |\\,|\\t|\\(|\\))");
+ auto fields = input.split(splitter);
+ fields.removeAll("");
+
+ // Check for labels
+ if (fields.size() > 0 && fields[0].at(fields[0].length() - 1) == ':') {
+ fields.removeFirst();
+ }
+
+ // Validate remaining fields
+ if (fields.size() > 0) {
+ auto rule = m_syntaxRules.find(fields[0]);
+ if (rule != m_syntaxRules.end()) {
+ // A rule for the instruction has been found
+ if (fields.size() == (*rule).fields) {
+ // fields size is correct, check each instruction
+ int index = 1;
+ for (const auto &input : (*rule).inputs) {
+ QString res = input.validateField(fields[index]);
+ if (res == QString()) {
+ // continue
+ index++;
+ } else {
+ return res;
+ }
+ }
+ } else {
+ // Invalid number of arguments
+ return QString("Invalid number of arguments");
+ }
+ } else {
+ return QString("Unknown instruction");
+ }
+ }
+ return QString();
+}

MODIFY
src/asmhighlighter.h
src/asmhighlighter.h
Matches instruction names directly, and register aliases/true name.
Matches immediate values by regex*/
+namespace {
+enum class Type { Immediate, Register, Offset };
+}
+
+class FieldType {
+ // Class for defining field-specific rules, such as immediate range checking,
+ // and whether a register is recognized
+public:
+ explicit FieldType(Type type, int lowerBound = 0, int upperBound = 0);
+ QString validateField(const QString &field) const;
+ Type m_type;
+ int m_lowerBound;
+ int m_upperBound;
+};
class AsmHighlighter : public QSyntaxHighlighter {
Q_OBJECT
@@ -18,6 +32,8 @@ public:
void highlightBlock(const QString &text);
+ QString checkSyntax(const QString &line);
+
signals:
private:
@@ -26,6 +42,17 @@ private:
QTextCharFormat format;
};
+ struct SyntaxRule {
+ QString instr;
+ int fields; // n instruction fields, including the instruction
+ QList<FieldType>
+ inputs; // list of each accepted input for the instruction, in order
+ };
+
+ void createSyntaxRules();
+
+ QMap<QString, SyntaxRule> m_syntaxRules;
+
QVector<HighlightingRule> m_highlightingRules;
// Format type for each matching case
@@ -33,6 +60,9 @@ private:
QTextCharFormat instrFormat;
QTextCharFormat immFormat;
QTextCharFormat commentFormat;
+ QTextCharFormat errorFormat;
+
+ QMap<int, QString> m_errors;
public slots:
};

MODIFY
src/cachesetupwidget.ui
src/cachesetupwidget.ui
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout_3">
+ <item row="6" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Blocks</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1">
+ <widget class="QComboBox" name="comboBox_2"/>
+ </item>
<item row="3" column="0">
<widget class="QLabel" name="label">
<property name="text">
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
- <string>Cache size</string>
+ <string>Cache size (data)</string>
</property>
</widget>
</item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_3">
+ <item row="4" column="1">
+ <widget class="QComboBox" name="setsize">
+ <item>
<property name="text">
- <string>Miss penalty (cycles)</string>
+ <string>1</string>
</property>
- </widget>
</item>
- <item row="4" column="1">
- <widget class="QComboBox" name="setsize"/>
+ <item>
+ <property name="text">
+ <string>2</string>
+ </property>
</item>
- <item row="4" column="0">
- <widget class="QLabel" name="label_4">
+ <item>
+ <property name="text">
+ <string>4</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>8</string>
+ </property>
+ </item>
+ <item>
<property name="text">
- <string>Set size</string>
+ <string>16</string>
</property>
+ </item>
</widget>
</item>
- <item row="5" column="0">
- <widget class="QLabel" name="label_5">
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
<property name="text">
- <string>Replacement strategy</string>
+ <string>Miss penalty (cycles)</string>
</property>
</widget>
</item>
</item>
</widget>
</item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Associativity</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Replacement strategy</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="1">
+ <widget class="QComboBox" name="comboBox_3"/>
+ </item>
+ <item row="7" column="0">
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>Words per block</string>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item>

MODIFY
src/defines.h
src/defines.h
@@ -63,6 +63,39 @@ enum instrState {
ERR_ECALL
};
+const static QStringList ABInames = QStringList() << "zero"
+ << "ra"
+ << "sp"
+ << "gp"
+ << "tp"
+ << "t0"
+ << "t1"
+ << "t2"
+ << "s0/fp"
+ << "s1"
+ << "a0"
+ << "a1"
+ << "a2"
+ << "a3"
+ << "a4"
+ << "a5"
+ << "a6"
+ << "a7"
+ << "s2"
+ << "s3"
+ << "s4"
+ << "s5"
+ << "s6"
+ << "s7"
+ << "s8"
+ << "s9"
+ << "s10"
+ << "s11"
+ << "t3"
+ << "t4"
+ << "t5"
+ << "t6";
+
const static std::map<int, QString> cacheSizes = {
{32, QString("32 Bytes")}, {64, QString("64 Bytes")},
{128, QString("128 Bytes")}, {256, {QString("256 Bytes")}},

MODIFY
src/memorytab.cpp
src/memorytab.cpp
@@ -44,39 +44,7 @@ void MemoryTab::saveAddress() {
}
void MemoryTab::initializeRegisterView() {
- // Initialize register ABInames
- QStringList ABInames = QStringList() << "zero"
- << "ra"
- << "sp"
- << "gp"
- << "tp"
- << "t0"
- << "t1"
- << "t2"
- << "s0/fp"
- << "s1"
- << "a0"
- << "a1"
- << "a2"
- << "a3"
- << "a4"
- << "a5"
- << "a6"
- << "a7"
- << "s2"
- << "s3"
- << "s4"
- << "s5"
- << "s6"
- << "s7"
- << "s8"
- << "s9"
- << "s10"
- << "s11"
- << "t3"
- << "t4"
- << "t5"
- << "t6";
+ // Initialize register descriptions
QStringList descriptions =
QStringList() << "Hard-Wired zero"
<< "Return Address \nSaver: Caller"

MODIFY
src/programfiletab.ui
src/programfiletab.ui
</layout>
</widget>
</item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Original code</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Translated code</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
<item>
<widget class="QStackedWidget" name="stackedWidget_2">
<property name="currentIndex">
<number>20</number>
</property>
</widget>
- <widget class="QPlainTextEdit" name="binaryedit">
+ <widget class="CodeEditor" name="binaryedit">
<property name="enabled">
<bool>true</bool>
</property>

Implement syntax checking