From b2d8910f3f60b50bf3fc359dfa37a4da2414cd2f Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Wed, 3 Jul 2019 08:44:32 +0200 Subject: Allow spaces in middle of assembler arguments and report errors. Signed-off-by: Pavel Pisa --- qtmips_gui/mainwindow.cpp | 9 ++-- qtmips_gui/programdock.cpp | 7 +++ qtmips_gui/programdock.h | 1 + qtmips_gui/programmodel.cpp | 7 ++- qtmips_gui/programmodel.h | 2 + qtmips_machine/instruction.cpp | 102 +++++++++++++++++++---------------------- qtmips_machine/instruction.h | 4 +- 7 files changed, 70 insertions(+), 62 deletions(-) diff --git a/qtmips_gui/mainwindow.cpp b/qtmips_gui/mainwindow.cpp index e3ad8dd..766a28c 100644 --- a/qtmips_gui/mainwindow.cpp +++ b/qtmips_gui/mainwindow.cpp @@ -620,6 +620,7 @@ void MainWindow::compile_source() { int ln = 1; for ( QTextBlock block = doc->begin(); block.isValid(); block = block.next(), ln++) { + QString error; int pos; QString label = ""; QString line = block.text(); @@ -641,7 +642,6 @@ void MainWindow::compile_source() { QString op = line.split(" ").at(0).toUpper(); if (op == ".ORG") { bool ok; - QString error; fixmatheval::FmeExpression expression; fixmatheval::FmeValue value; ok = expression.parse(line.mid(op.size()), error); @@ -659,7 +659,6 @@ void MainWindow::compile_source() { continue; } if (op == ".WORD") { - QString error; foreach (QString s, line.mid(op.size()).split(",")) { s = s.simplified(); std::uint32_t val = 0; @@ -677,14 +676,14 @@ void MainWindow::compile_source() { } std::uint32_t inst[2] = {0, 0}; - ssize_t size = machine::Instruction::code_from_string(inst, 8, line, + ssize_t size = machine::Instruction::code_from_string(inst, 8, line, error, address, &reloc, ln, true); if (size < 0) { error_line = ln; editor->setCursorToLine(error_line); QMessageBox::critical(this, "QtMips Error", - tr("line %1 instruction %2 parse error.") - .arg(QString::number(ln), line)); + tr("line %1 instruction %2 parse error - %3.") + .arg(QString::number(ln), line, error)); break; } std::uint32_t *p = inst; diff --git a/qtmips_gui/programdock.cpp b/qtmips_gui/programdock.cpp index c5f40d8..bcdbd23 100644 --- a/qtmips_gui/programdock.cpp +++ b/qtmips_gui/programdock.cpp @@ -39,6 +39,8 @@ #include #include #include +#include + #include "programdock.h" #include "programmodel.h" #include "programtableview.h" @@ -103,6 +105,7 @@ ProgramDock::ProgramDock(QWidget *parent, QSettings *settings) : Super(parent) { program_model, SLOT(toggle_hw_break(QModelIndex))); connect(this, SIGNAL(stage_addr_changed(uint,std::uint32_t)), program_model, SLOT(update_stage_addr(uint,std::uint32_t))); + connect(program_model, SIGNAL(report_error(QString)), this, SLOT(report_error(QString))); } void ProgramDock::setup(machine::QtMipsMachine *machine) { @@ -166,3 +169,7 @@ void ProgramDock::update_follow_position() { if (follow_source != FOLLOWSRC_NONE) emit focus_addr(follow_addr[follow_source]); } + +void ProgramDock::report_error(QString error) { + QMessageBox::critical(this, "QtMips Error", error); +} diff --git a/qtmips_gui/programdock.h b/qtmips_gui/programdock.h index 0dec65d..50baa50 100644 --- a/qtmips_gui/programdock.h +++ b/qtmips_gui/programdock.h @@ -65,6 +65,7 @@ public slots: void execute_inst_addr(std::uint32_t addr); void memory_inst_addr(std::uint32_t addr); void writeback_inst_addr(std::uint32_t addr); + void report_error(QString error); private: enum FollowSource { FOLLOWSRC_NONE, diff --git a/qtmips_gui/programmodel.cpp b/qtmips_gui/programmodel.cpp index 0f3341f..b70ed34 100644 --- a/qtmips_gui/programmodel.cpp +++ b/qtmips_gui/programmodel.cpp @@ -256,6 +256,7 @@ bool ProgramModel::setData(const QModelIndex & index, const QVariant & value, in if (role == Qt::EditRole) { bool ok; + QString error; std::uint32_t address; std::uint32_t data; machine::MemoryAccess *mem; @@ -274,8 +275,12 @@ bool ProgramModel::setData(const QModelIndex & index, const QVariant & value, in mem->write_word(address, data); break; case 3: - if (machine::Instruction::code_from_string(&data, 4, value.toString(), address) < 0) + if (machine::Instruction::code_from_string(&data, 4, value.toString(), + error, address) < 0) { + emit report_error(tr("instruction 1 parse error - %2.").arg(error)); + return false; + } mem->write_word(address, data); break; default: diff --git a/qtmips_gui/programmodel.h b/qtmips_gui/programmodel.h index a2eff4b..95d0e3f 100644 --- a/qtmips_gui/programmodel.h +++ b/qtmips_gui/programmodel.h @@ -93,6 +93,8 @@ public: STAGEADDR_COUNT, }; +signals: + void report_error(QString error); public slots: void setup(machine::QtMipsMachine *machine); void check_for_updates(); diff --git a/qtmips_machine/instruction.cpp b/qtmips_machine/instruction.cpp index b851461..49604ca 100644 --- a/qtmips_machine/instruction.cpp +++ b/qtmips_machine/instruction.cpp @@ -1071,10 +1071,11 @@ static void reloc_append(RelocExpressionList *reloc, QString fl, uint32_t inst_a #define CFS_OPTION_SILENT_MASK 0x100 ssize_t Instruction::code_from_string(std::uint32_t *code, size_t buffsize, - QString inst_base, QVector &inst_fields, + QString inst_base, QStringList &inst_fields, QString &error, std::uint32_t inst_addr, RelocExpressionList *reloc, int line, bool pseudo_opt, int options) { + const char *err = "unknown instruction"; if (str_to_instruction_code_map.isEmpty()) instruction_from_string_build_base(); @@ -1092,6 +1093,7 @@ ssize_t Instruction::code_from_string(std::uint32_t *code, size_t buffsize, field = 0; foreach (const QString &arg, im.args) { if (field >= inst_fields.count()) { + err = "number of arguments does not match"; field = -1; break; } @@ -1107,10 +1109,12 @@ ssize_t Instruction::code_from_string(std::uint32_t *code, size_t buffsize, const ArgumentDesc *adesc = argdesbycode[a]; if (adesc == nullptr) { if (!fl.count()) { + err = "empty argument encountered"; field = -1; break; } if (fl.at(0) != ao) { + err = "argument does not match instruction template"; field = -1; break; } @@ -1197,11 +1201,13 @@ ssize_t Instruction::code_from_string(std::uint32_t *code, size_t buffsize, break; } if (chars_taken <= 0) { + err = "argument parse error"; field = -1; break; } if ((val & ((1 << adesc->shift) - 1)) && !(options & CFS_OPTION_SILENT_MASK)) { + err = "low bits of argument has to be zero"; field = -1; break; } @@ -1213,12 +1219,14 @@ ssize_t Instruction::code_from_string(std::uint32_t *code, size_t buffsize, if (adesc->min < 0) { if (((std::int64_t)val < adesc->min) || ((std::int64_t)val > adesc->max)) { + err = "argument range exceed"; field = -1; break; } } else { if ((val < (std::uint64_t)adesc->min) || (val > (std::uint64_t)adesc->max)) { + err = "argument range exceed"; field = -1; break; } @@ -1230,6 +1238,11 @@ ssize_t Instruction::code_from_string(std::uint32_t *code, size_t buffsize, } if (field == -1) break; + if (fl.trimmed() != "") { + err = "excessive characters in argument"; + field = -1; + break; + } } if (field != inst_fields.count()) continue; @@ -1246,77 +1259,58 @@ ssize_t Instruction::code_from_string(std::uint32_t *code, size_t buffsize, ret = 4; } else if (pseudo_opt) { if (((inst_base == "LA") || (inst_base == "LI")) && (inst_fields.size() == 2)) { - if(code_from_string(code, buffsize, "LUI", inst_fields, + if(code_from_string(code, buffsize, "LUI", inst_fields, error, inst_addr, reloc, line, false, - CFS_OPTION_SILENT_MASK + 16) < 0) + CFS_OPTION_SILENT_MASK + 16) < 0) { + error = QString("error in LUI element of " + inst_base); return -1; + } inst_fields.insert(1, "$0"); - if (code_from_string(code + 1, buffsize - 4, "ORI", inst_fields, + if (code_from_string(code + 1, buffsize - 4, "ORI", inst_fields, error, inst_addr + 4, reloc, line, false, - CFS_OPTION_SILENT_MASK + 0) < 0) + CFS_OPTION_SILENT_MASK + 0) < 0) { + error = QString("error in ORI element of " + inst_base); return -1; + } return 8; } } if (buffsize >= 4) *code = inst_code; + if (ret < 0) { + error = err; + } return ret; } ssize_t Instruction::code_from_string(std::uint32_t *code, size_t buffsize, - QString str, std::uint32_t inst_addr, + QString str, QString &error, std::uint32_t inst_addr, RelocExpressionList *reloc, int line, bool pseudo_opt, int options) { - if (str_to_instruction_code_map.isEmpty()) - instruction_from_string_build_base(); - - QString inst_base = ""; - QVector inst_fields(0); - bool prev_white = true; - bool act_white; - bool comma = false; - bool next_comma = false; - int field = 0; - bool error = false; - - for (int k = 0, l = 0; k < str.count() + 1; k++, prev_white = act_white) { - if (next_comma) - comma = true; - next_comma = false; - if (k >= str.count()) { - act_white = true; - } else { - act_white = str.at(k).isSpace(); - if (str.at(k) == ',') - next_comma = act_white = true; - } - - if (prev_white and !act_white) - l = k; - if (!prev_white and act_white) { - if (inst_base.count() == 0) { - if (comma) { - error = true; - break; - } - inst_base = str.mid(l, k - l).toUpper(); - } else { - if ((field && !comma) || (!field && comma)) { - error = true; - break; - } - inst_fields.append(str.mid(l, k - l)); - comma = false; - field++; - } - l = k; - } + int k = 0, l; + while (k < str.count()) { + if (!str.at(k).isSpace()) + break; + k++; + } + l = k; + while (l < str.count()) { + if (!str.at(l).isLetterOrNumber()) + break; + l++; + } + QString inst_base = str.mid(k, l - k).toUpper(); + str = str.mid(l + 1).trimmed(); + QStringList inst_fields; + if (str.count()) + inst_fields = str.split(","); + + if (!inst_base.count()) { + error = "empty instruction field"; + return -1; } - if (error) - return -1; - - return code_from_string(code, buffsize, inst_base, inst_fields, inst_addr, + return code_from_string(code, buffsize, inst_base, inst_fields, error, inst_addr, reloc, line, pseudo_opt, options); } diff --git a/qtmips_machine/instruction.h b/qtmips_machine/instruction.h index 101d82f..03b8f65 100644 --- a/qtmips_machine/instruction.h +++ b/qtmips_machine/instruction.h @@ -149,13 +149,13 @@ public: QString to_str(std::int32_t inst_addr = 0) const; static ssize_t code_from_string(std::uint32_t *code, size_t buffsize, - QString inst_base, QVector &inst_fields, + QString inst_base, QStringList &inst_fields, QString &error, std::uint32_t inst_addr = 0, RelocExpressionList *reloc = nullptr, int line = 0, bool pseudo_opt = false, int options = 0); static ssize_t code_from_string(std::uint32_t *code, size_t buffsize, - QString str, std::uint32_t inst_addr = 0, + QString str, QString &error, std::uint32_t inst_addr = 0, RelocExpressionList *reloc = nullptr, int line = 0, bool pseudo_opt = false, int options = 0); -- cgit v1.2.3