bool Compiler::compile(QStringList *msgs) { if(!precompile(msgs)) return false; QList<int> words; QList<LabelItem> labelQueue; int address = 0; auto packValue = [&](const int &value) { if(words.isEmpty()) return; words.last() += value; }; auto packOperand = [&](const int &operand) { if(words.isEmpty()) return; words.last() += operand * 10000; }; auto parseOperand = [&](QString operand, const int &n, const int &line) { operand.replace('\t', "").replace('\n', ""); bool isPointer = false; if((operand[0] == '[') && (operand[operand.length() - 1] == ']')) { isPointer = true; operand = operand.mid(1, operand.length() - 2); } bool isConst = false; if(!isPointer && operand.startsWith('$')) { isConst = true; operand = operand.mid(1); } bool isNumber = false; operand.toInt(&isNumber); if((operand[0] == '"') && (operand[operand.length() - 1] == '"')) { //string literal operand = operand.mid(1, operand.length() - 2); words.clear(); for(int i = 0; i < operand.length(); ++i) { char c = operand[i].toLatin1(); if(c == '\\') { switch(operand[i + 1].toLatin1()) { case 'n': c = 10; break; case 'r': c = 13; break; case 'a': c = 7; break; case '\\': c = 92; break; case '"': c = 34; break; case '0': c = 0; break; default: { if(msgs) *msgs << tr("%1:Unrecognised string escape \\%2").arg(line).arg(operand[i+1]); return false; } } ++i; } words << c; } } else if(isPointer && (operand.split('+').size() == 2)) { //register + offset const QString errorStr = tr("%1:Invalid offset pointer, must be one literal/label and one register"); const QStringList split = operand.replace(' ', "").split('+'); QString reg; QString offset; for(int i = 0; i < 2; ++i) { bool isOffset = false; int number = split[i].toInt(&isOffset); if(isOffset) { if(offset.isEmpty()) { offset = QString::number(number); } else { if(msgs) *msgs << errorStr.arg(line); return false; } packValue(number); } else if(registerList.contains(split[i].toUpper())) { if(reg.isEmpty()) { reg = split[i].toUpper(); } else { if(msgs) *msgs << errorStr.arg(line); return false; } } else if(offset.isEmpty() && labelPattern.match(split[i]).hasMatch()) { LabelItem label; label.name = split[i]; label.address = address; labelQueue << label; } else { if(msgs) *msgs << errorStr.arg(line); return false; } } if(reg == "AX") { packOperand(8); } else if(reg == "IP") { packOperand(9); } else if(reg == "SP") { packOperand(10); } else if(reg == "SB") { packOperand(11); } else if(reg == "DI") { packOperand(12); } } else if(isNumber) { const int value = operand.toInt(); const int intValue = VirtualMachine::memoryToInt(value); if((intValue < -999) || (intValue > 999)) { if(msgs) *msgs << tr("%1:Value out of range \"%2\"").arg(line).arg(value); return false; } if(n > 0) words << 0; if(isPointer) { packOperand(1); } else if(isConst) { packOperand(2); } else { packOperand(0); } packValue(value); } else { if(registerList.contains(operand.toUpper())) { if(operand.toUpper() == "AX") { packOperand(isPointer ? 8 : 3); } else if(operand.toUpper() == "IP") { packOperand(isPointer ? 9 : 4); } else if(operand.toUpper() == "SP") { packOperand(isPointer ? 10 : 5); } else if(operand.toUpper() == "SB") { packOperand(isPointer ? 11 : 6); } else if(operand.toUpper() == "DI") { packOperand(isPointer ? 12 : 7); } } else { if(isPointer) { packOperand(1); } else if(isConst) { packOperand(2); } else { packOperand(0); } if(labelPattern.match(operand).hasMatch()) { LabelItem label; label.name = operand; label.address = address; labelQueue << label; } else { if(msgs) *msgs << tr("%1:Illegal symbol in label \"%2\"").arg(line).arg(operand); return false; } } } return true; }; QHash<int, int> memory; for(int i = 0; i < m_instructions.size(); ++i) { const QString mnemonic = m_instructions[i].mnemonic.toUpper(); const QStringList operands = m_instructions[i].operands; if((mnemonic == ".CODE") || (mnemonic == ".DATA")) { if(operands.size()) { address = operands[0].toInt(); if((mnemonic == ".CODE") && (m_startCell == -1)) { m_startCell = address; } } } else { if(mnemonicMap.value(mnemonic).operands > operands.size()) { if(msgs) *msgs << tr("%1:Invalid operand count for \"%2\" (expecting %3)").arg(m_instructionMap[i]) .arg(mnemonic) .arg(mnemonicMap.value(mnemonic).operands); return false; } if(mnemonicMap.value(mnemonic.toUpper()).code > -1) { words = { mnemonicMap.value(mnemonic.toUpper()).code * 1000000 }; } else { words = { 0 }; } for(int j = 0; j < operands.size(); ++j) { if(!parseOperand(operands[j], j, m_instructionMap[i])) return false; } const int prevAddress = address; for(int j = 0; j < words.size(); ++j) memory.insert(address++, words[j]); for(int j = prevAddress; j <= address; ++j) { if(!m_addressMap.values().contains(i)) m_addressMap.insert(j, i); } } } for(int i = 0; i < labelQueue.size(); ++i) { if(!m_labelMap.contains(labelQueue[i].name)) { if(msgs) *msgs << tr("%1:Undefined label \"%2\"").arg(-1).arg(labelQueue[i].name); return false; } int value = address; const int key = m_addressMap.key(m_labelMap.value(labelQueue[i].name), -1); if(key > -1) value = key; memory[labelQueue[i].address] += value; } QHashIterator<int, int> it(memory); while(it.hasNext()) { it.next(); emit memoryChanged(it.key(), it.value()); } return true; }
int main(int argc, char** argv){ for(int i = 1; i < argc; i++){ precompile(argv[i]); } }