From 3164fe6201c7d3fbaec735b08cc0f13ee40e6295 Mon Sep 17 00:00:00 2001 From: Mark Long Date: Sat, 29 Oct 2016 16:10:54 -0500 Subject: [PATCH] Added syntax highlighting to Applesoft Viewer, reworked retokenizer --- README.md | 4 +- doc/AppleSAWS.notes.odt | Bin 13302 -> 13371 bytes src/applesoftfile/ApplesoftRetokenizer.cpp | 220 +++++++++++++----- src/applesoftfile/ApplesoftRetokenizer.h | 12 + src/applesoftfile/applesoftfile.cxx | 2 + src/applesoftfile/applesoftfile.h | 3 + src/applesoftfile/applesoftformatter.cxx | 245 ++++++++++++++++++++- src/applesoftfile/applesoftformatter.h | 4 +- src/applesoftfile/applesofttoken.cxx | 57 ++++- src/applesoftfile/applesofttoken.h | 52 +++-- src/ui/viewers/applesoftfileviewer.cxx | 46 +++- src/ui/viewers/applesoftfileviewer.h | 1 + 12 files changed, 548 insertions(+), 98 deletions(-) diff --git a/README.md b/README.md index 45ff1ba..0b85468 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This code is being developed using Qt5, with development work being done on Linu Among other things, the app includes: * Code that reads and parses DOS-format disk images at the disk-structure level. (It's just read-only for now, and ProDOS is on the horizon) -* An Applesoft parser/retokenizer/reformatter which can show code in its normal form or reindented on multiple lines, and can optionally show integers as hex values inline. The retokenizer creates new tokens for strings, variable names, numeric values, DATA payloads, REM remarks, and other things that are nice to have -- and sets the stage to create an analyzer for deeper processing of the code later on. +* An Applesoft parser/retokenizer/reformatter which can show code in its normal form or reindented on multiple lines with syntax highlighting, and can optionally show integers as hex values inline. The retokenizer creates new tokens for strings, variable names, numeric values, DATA payloads, REM remarks, and other things that are nice to have -- and sets the stage to create an analyzer for deeper processing of the code later on. * A binary file processor with a flow-tracing disassembler, which can show hex dumps and disassembly of code and data blocks (it also temporarily has some common labels for well-known addresses hard-coded into the display, though dynamic labeling of symbols is in the works.) It can also display the relocation table for type-R relocatable files. * A Text file viewer. * A graphics viewer which can show hires screen dumps as monochrome, with NTSC artifacts, or a hybrid mode where each pixel's natural color is shown in-place (with no white color blending.) @@ -20,7 +20,7 @@ Among other things, the app includes: There is also a Hex/Decimal converter utility and some in-app documentation for HRCG control character codes. Mainly stuff that I found useful at the time I was writing it. In the pipeline are some more useful features (as I get a chance): -* Syntax Highlighting +* Syntax Highlighting **(Currently in progress!)** * More low-level disk exploration tools (sector-level stuff, comparing DOS versions between disks, etc.) * More analysis of AppleSoft programs (Tracing flow control, find addresses of PEEKS, POKES, CALLS, USRs, and &'s) * Processing and analysis of Integer Basic files diff --git a/doc/AppleSAWS.notes.odt b/doc/AppleSAWS.notes.odt index 92b36fc8f3b4b1755f5be4ad1b7cc5d3f54318ac..f3e82e57c3148c37292aaee8c557f40a2e18d892 100644 GIT binary patch delta 9242 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 diff --git a/src/applesoftfile/ApplesoftRetokenizer.cpp b/src/applesoftfile/ApplesoftRetokenizer.cpp index 9599385..ce75e0b 100644 --- a/src/applesoftfile/ApplesoftRetokenizer.cpp +++ b/src/applesoftfile/ApplesoftRetokenizer.cpp @@ -6,17 +6,25 @@ ApplesoftRetokenizer::ApplesoftRetokenizer() { - + m_isParsed = false; } void ApplesoftRetokenizer::setData(QByteArray data) { m_data = data; m_data_end = data.length(); + m_isParsed = false; } void ApplesoftRetokenizer::parse(quint16 start_address) { + if (m_isParsed) + { + qWarning("File is already parsed. Not reparsing."); + return; + } + + //TODO: This could be changed to search for hidden space between applesoft lines int idx = 0; quint8 val = 0; m_retokenized_lines.clear(); @@ -46,11 +54,123 @@ void ApplesoftRetokenizer::parse(quint16 start_address) m_retokenized_lines.append(line); } - m_data_end = idx; + m_data_end = idx; if (idx < m_data.length()) { qDebug() << QString("%1 byte(s) unaccounted for.").arg(m_data.length() - idx); } + + retokenizeLinesForFormatting(); + + m_isParsed = true; +} + +void ApplesoftRetokenizer::retokenizeLinesForFormatting() +{ + QVector retLines; + + foreach(ApplesoftLine line, m_retokenized_lines) + { + int indentlevel = 1; + // quint16 linenum = line.linenum; + + bool firstToken = true; + ApplesoftToken previousToken; + QMutableVectorIterator tokenIt(line.tokens); + while (tokenIt.hasNext()) + { + ApplesoftToken token = tokenIt.next(); + bool isFlowTarget = false; + + QString tokenstr = token.getRawPrintableString(); + if (firstToken) + { + if (!tokenstr.startsWith(" ")) + { + ApplesoftToken tmptoken(ApplesoftToken::OptFmtLeadingSpaceTokenValue); + tokenIt.remove(); + tokenIt.insert(tmptoken); + tokenIt.insert(token); + } + firstToken = false; + } + + quint16 preTokenId = previousToken.getTokenId(); + if (preTokenId == ApplesoftToken::ASGoto || + preTokenId == ApplesoftToken::ASGosub || + preTokenId == ApplesoftToken::ASThen) + { + isFlowTarget = false; + if (preTokenId == ApplesoftToken::ASGoto || preTokenId == ApplesoftToken::ASGosub) + { + isFlowTarget = true; + } + else if (preTokenId == ApplesoftToken::ASThen + && token.getTokenId() == ApplesoftToken::IntegerTokenVal) + { + isFlowTarget = true; + } + if (isFlowTarget) + { + QPair pair; + pair.first = line.linenum; + pair.second = token.getWordValue(); + m_flowTargets.append(pair); + + ApplesoftToken tmptoken(ApplesoftToken::OptFmtFlagFlowTargetNextTokenValue); + tokenIt.remove(); + tokenIt.insert(tmptoken); + tokenIt.insert(token); + } + } + + if (token.getTokenId() == ApplesoftToken::ASReturn) + { + ApplesoftToken tmptoken(ApplesoftToken::OptFmtReturnLineBreakTokenValue); + tokenIt.insert(tmptoken); + } + + if (token.getTokenId() == ':') + { + ApplesoftToken tmptoken(ApplesoftToken::OptFmtIndentLineBreakTokenValue); + tokenIt.insert(tmptoken); + for (int ind = 0; ind < indentlevel; ind++) + { + ApplesoftToken tmptoken(ApplesoftToken::OptFmtIndentTabTokenValue); + tokenIt.insert(tmptoken); + } + if (!tokenIt.peekNext().getRawPrintableString().startsWith(" ")) + { + ApplesoftToken tmptoken(ApplesoftToken::OptFmtIndentSpaceTokenValue); + tokenIt.insert(tmptoken); + } + } + if (token.getTokenId() == ApplesoftToken::ASThen) + { + indentlevel++; + if (tokenIt.peekNext().getTokenId() != ApplesoftToken::IntegerTokenVal) + { + ApplesoftToken tmptoken(ApplesoftToken::OptFmtIndentLineBreakTokenValue); + tokenIt.insert(tmptoken); + for (int ind = 0; ind < indentlevel; ind++) + { + ApplesoftToken tmptoken(ApplesoftToken::OptFmtIndentTabTokenValue); + tokenIt.insert(tmptoken); + } + if (!tokenIt.peekNext().getRawPrintableString().startsWith(" ")) + { + ApplesoftToken tmptoken(ApplesoftToken::OptFmtIndentSpaceTokenValue); + tokenIt.insert(tmptoken); + } + } + } + + previousToken = token; + } + retLines.append(line); + } + + m_retokenized_lines = retLines; } void ApplesoftRetokenizer::retokenizeLine(ApplesoftLine &line) @@ -115,35 +235,35 @@ QVector ApplesoftRetokenizer::retokenizeStrings(QVector= 0x80) { replacements.append(token); - // continue; + // continue; } else - if (token.getWordValue() == '"') - { - if (!inString) + if (token.getWordValue() == '"') { - inString = true; - buffer.append(token.getWordValue()); - // continue; - } - else - { - buffer.append(token.getWordValue()); - ApplesoftToken strtoken(ApplesoftToken::StringTokenVal, buffer); - replacements.append(strtoken); - buffer.clear(); - inString = false; -// continue; - } - } else + if (!inString) + { + inString = true; + buffer.append(token.getWordValue()); + // continue; + } + else + { + buffer.append(token.getWordValue()); + ApplesoftToken strtoken(ApplesoftToken::StringTokenVal, buffer); + replacements.append(strtoken); + buffer.clear(); + inString = false; + // continue; + } + } else - if (inString) - { - buffer.append(token.getWordValue()); - // continue; - } else + if (inString) + { + buffer.append(token.getWordValue()); + // continue; + } else - replacements.append(token); + replacements.append(token); } return replacements; @@ -176,7 +296,7 @@ QVector ApplesoftRetokenizer::retokenizeDataStatements(QVector dataTokens; - dataTokens = processDataPayload(datatokenbuffer); + dataTokens = retokenizeDataPayload(datatokenbuffer); replacements.append(dataTokens); datatokenbuffer.clear(); inData = false; @@ -185,7 +305,7 @@ QVector ApplesoftRetokenizer::retokenizeDataStatements(QVector ApplesoftRetokenizer::processDataPayload(QVector& datatokens) +QVector ApplesoftRetokenizer::retokenizeDataPayload(QVector& datatokens) { QVector retval; @@ -249,13 +369,13 @@ QVector ApplesoftRetokenizer::retokenizeVariables(QVector matchstack; QRegularExpressionMatchIterator matches = varregexp.globalMatch(parsestring); - // qDebug() << parsestring; + // qDebug() << parsestring; while (matches.hasNext()) { QRegularExpressionMatch rematch = matches.next(); matchstack.push_front(rematch); -// qDebug() << "Capture " << " = " << rematch.capturedTexts() << "From: " << rematch.capturedStart() -// << "To: " << rematch.capturedEnd()-1 << "("< ApplesoftRetokenizer::retokenizeNumbers(QVector matchstack; QRegularExpressionMatchIterator matches = varregexp.globalMatch(parsestring); -// qDebug() << parsestring; + // qDebug() << parsestring; while (matches.hasNext()) { QRegularExpressionMatch rematch = matches.next(); matchstack.push_front(rematch); -// qDebug() << "Capture " << " = " << rematch.capturedTexts() << "From: " << rematch.capturedStart() -// << "To: " << rematch.capturedEnd()-1 << "("< ApplesoftRetokenizer::retokenizeNegativeNumbers(QVector< else if (token.getTokenId() == ApplesoftToken::IntVarTokenVal) lastWasInt = true; else if (token.getTokenId() == ApplesoftToken::FloatVarTokenVal) lastWasInt = true; else if (token.getTokenId() == ')') lastWasInt = true; -else - if (token.getTokenId() == ApplesoftToken::ASMINUS) - { - if (!lastWasInt && it.hasNext() && it.peekNext().getTokenId() == ApplesoftToken::IntegerTokenVal) + else + if (token.getTokenId() == ApplesoftToken::ASMINUS) { - it.remove(); - token = it.next(); - it.remove(); - int val = token.getUnsignedIntegerValue() * -1; - token.setValue(val); - it.insert(token); - lastWasInt = true; + if (!lastWasInt && it.hasNext() && it.peekNext().getTokenId() == ApplesoftToken::IntegerTokenVal) + { + it.remove(); + token = it.next(); + it.remove(); + int val = token.getUnsignedIntegerValue() * -1; + token.setValue(val); + it.insert(token); + lastWasInt = true; + } + else + { + lastWasInt = false; + } } else { lastWasInt = false; } - } - else - { - lastWasInt = false; - } } return tmptokens.toVector(); diff --git a/src/applesoftfile/ApplesoftRetokenizer.h b/src/applesoftfile/ApplesoftRetokenizer.h index d1d9913..cedc0b6 100644 --- a/src/applesoftfile/ApplesoftRetokenizer.h +++ b/src/applesoftfile/ApplesoftRetokenizer.h @@ -5,6 +5,8 @@ #include #include +#include +#include class ApplesoftRetokenizer { @@ -18,8 +20,12 @@ public: QVector getRetokenizedLines() { return m_retokenized_lines; } + QList > getFlowTargets() const { return m_flowTargets; } private: + void retokenizeLinesForFormatting(); + + void retokenizeLine(ApplesoftLine &line); QVector retokenizeRems(QVector &datatokens); QVector retokenizeStrings(QVector &datatokens); @@ -29,10 +35,16 @@ private: QVector retokenizeNumbers(QVector &datatokens); QVector retokenizeNegativeNumbers(QVector &datatokens); + QVector m_retokenized_lines; QByteArray m_data; quint16 m_data_end; + + bool m_isParsed; + + QList > m_flowTargets; + }; diff --git a/src/applesoftfile/applesoftfile.cxx b/src/applesoftfile/applesoftfile.cxx index 37f029b..53557b9 100644 --- a/src/applesoftfile/applesoftfile.cxx +++ b/src/applesoftfile/applesoftfile.cxx @@ -35,6 +35,8 @@ void ApplesoftFile::setData(QByteArray data) m_retokenizer->parse(); m_data_end = m_retokenizer->getEndOfDataOffset(); m_lines = m_retokenizer->getRetokenizedLines(); + + m_flowTargets = m_retokenizer->getFlowTargets(); } QByteArray ApplesoftFile::rawData() { diff --git a/src/applesoftfile/applesoftfile.h b/src/applesoftfile/applesoftfile.h index 7c5449f..d08fba3 100644 --- a/src/applesoftfile/applesoftfile.h +++ b/src/applesoftfile/applesoftfile.h @@ -33,6 +33,9 @@ private: quint16 m_length; ApplesoftRetokenizer *m_retokenizer; + + QList > m_flowTargets; + }; diff --git a/src/applesoftfile/applesoftformatter.cxx b/src/applesoftfile/applesoftformatter.cxx index 8ad69da..61fecab 100644 --- a/src/applesoftfile/applesoftformatter.cxx +++ b/src/applesoftfile/applesoftformatter.cxx @@ -9,7 +9,6 @@ ApplesoftFormatter::ApplesoftFormatter(QObject *parent) : QObject(parent) { m_file = Q_NULLPTR; - m_formattedDocument = QSharedPointer(new QTextDocument()); } void ApplesoftFormatter::setFile(ApplesoftFile *file) @@ -21,13 +20,11 @@ void ApplesoftFormatter::setFile(ApplesoftFile *file) void ApplesoftFormatter::formatText() { m_formattedText.clear(); - m_formattedDocument->clear(); if (!m_file) { return; } - QTextCursor cursor(m_formattedDocument.data()); QString formattedText; m_flowTargets.clear(); @@ -37,7 +34,6 @@ void ApplesoftFormatter::formatText() int indentlevel = 1; formattedText.append(linestring); - cursor.insertText(linestring, ApplesoftToken::defaultTextFormat()); QVectorIterator tokenIt(line.tokens); @@ -58,7 +54,6 @@ void ApplesoftFormatter::formatText() } firstToken = false; } - cursor.insertText(tokenstr, token.textFormat()); //TODO: Move this to the parser. @@ -69,12 +64,12 @@ void ApplesoftFormatter::formatText() { isFlowTarget = false; if (previousToken.getTokenId() == ApplesoftToken::ASGoto || - previousToken.getTokenId() == ApplesoftToken::ASGosub) + previousToken.getTokenId() == ApplesoftToken::ASGosub) { isFlowTarget = true; } else if (previousToken.getTokenId() == ApplesoftToken::ASThen && - token.getTokenId() == ApplesoftToken::IntegerTokenVal) + token.getTokenId() == ApplesoftToken::IntegerTokenVal) { isFlowTarget = true; } @@ -177,14 +172,244 @@ void ApplesoftFormatter::formatText() formattedText.append(tokenstr); previousToken = token; - } + } // While tokenIt.hasNext(); formattedText.append("\n"); if (m_format_options.testFlag(ReindentCode)) { - // retval.append("\n"); + // retval.append("\n"); } - } + } //foreach line m_formattedText = formattedText; } + + +void ApplesoftFormatter::newFormatText() +{ + m_formattedText.clear(); + + QString formattedText; + + foreach (ApplesoftLine line, m_file->getLines()) + { + QString linestring = QString("%1 ").arg(line.linenum,5,10,QChar(' ')); + formattedText.append(linestring); + + QVectorIteratortokenIt(line.tokens); + while (tokenIt.hasNext()) + { + ApplesoftToken token = tokenIt.next(); + bool isBranchTarget = false; + if (token.isOptFmtToken()) + { + switch (token.getTokenId()) + { + + case ApplesoftToken::OptFmtFlagFlowTargetNextTokenValue: + { + if (m_format_options.testFlag(ShowIntsAsHex)) + isBranchTarget = true; + break; + } + + case ApplesoftToken::OptFmtIndentLineBreakTokenValue: + { + if (m_format_options.testFlag(ReindentCode)) + formattedText.append("\n"); + break; + } + case ApplesoftToken::OptFmtIndentSpaceTokenValue: + { + if (m_format_options.testFlag(ReindentCode)) + formattedText.append(" "); + break; + } + case ApplesoftToken::OptFmtIndentTabTokenValue: + { + if (m_format_options.testFlag(ReindentCode)) + formattedText.append(" "); + break; + } + case ApplesoftToken::OptFmtLeadingSpaceTokenValue: + { + formattedText.append(" "); + break; + } + case ApplesoftToken::OptFmtReturnLineBreakTokenValue: + { + if (m_format_options.testFlag(BreakAfterReturn)) + formattedText.append("\n"); + break; + } + default: + { + break; + } + } + } // isOptFmt + else + { + QString tokenstr = token.getRawPrintableString(); + + if (token.getTokenId() == ApplesoftToken::IntegerTokenVal) + { + if (m_format_options.testFlag(ShowIntsAsHex) && !isBranchTarget) + { + quint32 ui32val = token.getUnsignedIntegerValue(); + qint32 i32val = token.getIntegerValue(); + if ((i32val < 128 && i32val >= -128) || ui32val < 256) + { + quint8 ui8 = ui32val; + tokenstr = HEXPREFIX+uint8ToHex(ui8); + } + else if ((i32val < 32768 && i32val >= -32768) || ui32val < 65536) + { + quint16 ui16 = ui32val; + tokenstr = HEXPREFIX+uint16ToHex(ui16); + } + else + { + tokenstr = HEXPREFIX+uint32ToHex(ui32val); + } + } // isShowIntsAsHex + } + + if (m_format_options.testFlag(ShowCtrlChars)) + { + tokenstr.replace(QChar(0x7f),QChar(0x2401)); + + for (int idx = 1; idx <= 0x1f; idx++) { + if (idx == '\n') continue; + tokenstr.replace(QChar(idx),QChar(idx+0x2400)); + // tokenstr.replace(QChar(idx), QString("<%1>").arg(uint8ToHex(idx))); + } + } // if ShowCtrlChars + + formattedText.append(tokenstr); + + } + + } // while tokenIt.hasNext() + + formattedText.append("\n"); + + } // foreach line + m_formattedText = formattedText; +} + +void ApplesoftFormatter::formatDocument(QTextDocument *doc) +{ + if (!doc) return; + + doc->clear(); + QTextCursor cursor(doc); + + foreach (ApplesoftLine line, m_file->getLines()) + { + QString linestring = QString("%1 ").arg(line.linenum,5,10,QChar(' ')); + cursor.insertText(linestring,ApplesoftToken::textFormat(ApplesoftToken::LineNumberTokenVal)); + + QVectorIteratortokenIt(line.tokens); + while (tokenIt.hasNext()) + { + ApplesoftToken token = tokenIt.next(); + bool isBranchTarget = false; + if (token.isOptFmtToken()) + { + switch (token.getTokenId()) + { + + case ApplesoftToken::OptFmtFlagFlowTargetNextTokenValue: + { + if (m_format_options.testFlag(ShowIntsAsHex)) + isBranchTarget = true; + break; + } + + case ApplesoftToken::OptFmtIndentLineBreakTokenValue: + { + if (m_format_options.testFlag(ReindentCode)) + cursor.insertBlock(); + break; + } + case ApplesoftToken::OptFmtIndentSpaceTokenValue: + { + if (m_format_options.testFlag(ReindentCode)) + cursor.insertText(" ",ApplesoftToken::defaultTextFormat()); + break; + } + case ApplesoftToken::OptFmtIndentTabTokenValue: + { + if (m_format_options.testFlag(ReindentCode)) + cursor.insertText(" ",ApplesoftToken::defaultTextFormat()); + break; + } + case ApplesoftToken::OptFmtLeadingSpaceTokenValue: + { + cursor.insertText(" ",ApplesoftToken::defaultTextFormat()); + break; + } + case ApplesoftToken::OptFmtReturnLineBreakTokenValue: + { + if (m_format_options.testFlag(BreakAfterReturn)) + cursor.insertBlock(); + break; + } + default: + { + break; + } + } + } // isOptFmt + else + { + QString tokenstr = token.getRawPrintableString(); + QTextCharFormat fmt = token.textFormat(); + + if (token.getTokenId() == ApplesoftToken::IntegerTokenVal) + { + if (m_format_options.testFlag(ShowIntsAsHex) && !isBranchTarget) + { + quint32 ui32val = token.getUnsignedIntegerValue(); + qint32 i32val = token.getIntegerValue(); + if ((i32val < 128 && i32val >= -128) || ui32val < 256) + { + quint8 ui8 = ui32val; + tokenstr = HEXPREFIX+uint8ToHex(ui8); + } + else if ((i32val < 32768 && i32val >= -32768) || ui32val < 65536) + { + quint16 ui16 = ui32val; + tokenstr = HEXPREFIX+uint16ToHex(ui16); + } + else + { + tokenstr = HEXPREFIX+uint32ToHex(ui32val); + } + } // isShowIntsAsHex + } + + if (m_format_options.testFlag(ShowCtrlChars)) + { + tokenstr.replace(QChar(0x7f),QChar(0x2401)); + + for (int idx = 1; idx <= 0x1f; idx++) { + if (idx == '\n') continue; + tokenstr.replace(QChar(idx),QChar(idx+0x2400)); + // tokenstr.replace(QChar(idx), QString("<%1>").arg(uint8ToHex(idx))); + } + } // if ShowCtrlChars + + //formattedText.append(tokenstr); + cursor.insertText(tokenstr,fmt); + + } + + } // while tokenIt.hasNext() + + //formattedText.append("\n"); + cursor.insertBlock(); + + } // foreach line +} diff --git a/src/applesoftfile/applesoftformatter.h b/src/applesoftfile/applesoftformatter.h index 580fc5f..6ca141a 100644 --- a/src/applesoftfile/applesoftformatter.h +++ b/src/applesoftfile/applesoftformatter.h @@ -35,11 +35,12 @@ public: FormatOptions flags() { return m_format_options; } void formatText(); - QSharedPointer getFormattedDocument() const { return m_formattedDocument; } QString getFormattedText() const { return m_formattedText; } QList > flowTargets() const { return m_flowTargets; } + void newFormatText(); + void formatDocument(QTextDocument *doc); signals: void newFile(ApplesoftFile *file); @@ -52,7 +53,6 @@ private: ApplesoftFile *m_file; QString m_formattedText; - QSharedPointer m_formattedDocument; }; diff --git a/src/applesoftfile/applesofttoken.cxx b/src/applesoftfile/applesofttoken.cxx index c1cfcbf..64c1b61 100644 --- a/src/applesoftfile/applesofttoken.cxx +++ b/src/applesoftfile/applesofttoken.cxx @@ -80,6 +80,9 @@ void ApplesoftToken::setTokenId(quint16 id) } else if (id == StringAryVarTokenVal) { m_token_type = STRING_ARY_VARIABLE_TOKEN; m_command_type = NONE; + } else if (id >= 0xe000 && id < 0xf000) { + m_token_type = OPTIONAL_FORMAT_TOKEN; + m_command_type = OPTIONAL_FORMAT; } } @@ -122,6 +125,8 @@ QString ApplesoftToken::getRawPrintableString() const return getStringValue(); } else if (m_token_id == StringAryVarTokenVal) { return getStringValue(); + } else if (m_token_id >= 0xe000 && m_token_id < 0xf000) { + return ""; } else { return "[temp undefined]"; } @@ -130,16 +135,55 @@ QString ApplesoftToken::getRawPrintableString() const QTextCharFormat ApplesoftToken::defaultTextFormat() { QTextCharFormat tf; // Default - tf.setFontFamily("Typewriter"); - tf.setFontPointSize(10); - tf.setForeground(Qt::red); +// tf.setFont(QFont("Courier")); +// tf.setFontPointSize(10); + tf.setForeground(Qt::black); return tf; } QTextCharFormat ApplesoftToken::textFormat(quint16 tokenType) { - makeTextCharFormats(); - return m_textcharformats[TCFDefault]; + QTextCharFormat tf = defaultTextFormat(); + + if (tokenType < 0x80) // Ascii + { + tf.setForeground(Qt::black); + } + else if (tokenType < 0x100) // Applesoft Tokens + { + tf.setForeground(Qt::black); + } + else if (tokenType == StringTokenVal) + { + tf.setForeground(Qt::blue); + tf.setFontWeight(QFont::Bold); + } + else if (tokenType == IntegerTokenVal || tokenType == FloatTokenVal) + { + tf.setForeground(Qt::darkGreen); + tf.setFontWeight(QFont::Bold); + } + else if (tokenType == StringVarTokenVal || + tokenType == StringAryVarTokenVal || + tokenType == IntVarTokenVal || + tokenType == IntAryVarTokenVal || + tokenType == FloatVarTokenVal || + tokenType == FloatAryVarTokenVal) + { + tf.setFontWeight(QFont::Bold); + tf.setForeground(Qt::darkMagenta); + } + else if (tokenType == RemStringTokenVal) + { + tf.setForeground(Qt::darkGray); + tf.setFontUnderline(true); + } + else if (tokenType == DataStringTokenVal) + { + tf.setForeground(Qt::darkRed); + } + + return tf; } @@ -159,9 +203,6 @@ void ApplesoftToken::makeTextCharFormats() // TCFRemString, // TCFUnknown - QTextCharFormat tf = defaultTextFormat(); - - m_textcharformats.insert(TCFDefault, tf); } diff --git a/src/applesoftfile/applesofttoken.h b/src/applesoftfile/applesofttoken.h index 9fef7f8..7201d15 100644 --- a/src/applesoftfile/applesofttoken.h +++ b/src/applesoftfile/applesofttoken.h @@ -6,6 +6,22 @@ #include #include +enum TextCharFormatType { + TCFDefault, + TCFCtrlChar, + TCFAscii, + TCFFunction, + TCFOperator, + TCFUnusedToken, + TCFNumber, + TCFString, + TCFVariable, + TCFDataString, + TCFRemString, + TCFUnknown +}; + + class ApplesoftToken { public: @@ -26,6 +42,15 @@ public: static const quint16 StringVarTokenVal = 0x109; static const quint16 StringAryVarTokenVal = 0x10A; + static const quint16 OptFmtLeadingSpaceTokenValue = 0xe000; + static const quint16 OptFmtIndentLineBreakTokenValue = 0xe001; + static const quint16 OptFmtIndentTabTokenValue = 0xe002; + static const quint16 OptFmtIndentSpaceTokenValue = 0xe003; + static const quint16 OptFmtFlagFlowTargetNextTokenValue = 0xe004; + static const quint16 OptFmtReturnLineBreakTokenValue = 0xe005; + + + static const quint16 LineNumberTokenVal = 0xfffe; static const quint16 DefaultTokenVal = 0xffff; @@ -117,7 +142,8 @@ public: FLOAT_VARIABLE_TOKEN = 0xB, FLOAT_ARY_VARIABLE_TOKEN = 0xC, STRING_VARIABLE_TOKEN = 0xD, - STRING_ARY_VARIABLE_TOKEN = 0xE + STRING_ARY_VARIABLE_TOKEN = 0xE, + OPTIONAL_FORMAT_TOKEN = 0xF } TokenType; typedef enum { @@ -125,7 +151,8 @@ public: COMMAND, OPERATOR, FUNCTION, - UNDEFINED_COMMAND + UNDEFINED_COMMAND, + OPTIONAL_FORMAT } CommandType; ApplesoftToken(); @@ -156,32 +183,20 @@ public: return textFormat(m_token_id); } - QTextCharFormat textFormat(quint16 tokentype) ; + static QTextCharFormat textFormat(quint16 tokentype) ; - static QString getStringForToken(quint8 token) { + QString getStringForToken(quint8 token) { if (m_tokens.size() == 0) { initializeTokenTable(); } return m_tokens[token]; } static QTextCharFormat defaultTextFormat(); + bool isOptFmtToken() const { return (m_token_id >= 0xe000 && m_token_id < 0xf000); } + private: void makeTextCharFormats(); - enum TextCharFormatType { - TCFDefault, - TCFCtrlChar, - TCFAscii, - TCFFunction, - TCFOperator, - TCFUnusedToken, - TCFNumber, - TCFString, - TCFVariable, - TCFDataString, - TCFRemString, - TCFUnknown - }; static QMap m_tokens; @@ -197,5 +212,4 @@ private: }; - #endif // APPLESOFTTOKEN_H diff --git a/src/ui/viewers/applesoftfileviewer.cxx b/src/ui/viewers/applesoftfileviewer.cxx index 40f5b77..a426d63 100644 --- a/src/ui/viewers/applesoftfileviewer.cxx +++ b/src/ui/viewers/applesoftfileviewer.cxx @@ -30,6 +30,7 @@ ApplesoftFileViewer::ApplesoftFileViewer(QWidget *parent) : setIndentCode(settings.value("ASViewer.indentCode",false).toBool(), NoReformat); setIntsAsHex(settings.value("ASViewer.intsAsHex",false).toBool(), NoReformat); + setBreakAfterReturn(settings.value("ASViewer.breakAfterReturn",false).toBool(), NoReformat); } ApplesoftFileViewer::~ApplesoftFileViewer() @@ -37,8 +38,6 @@ ApplesoftFileViewer::~ApplesoftFileViewer() delete ui; } - - bool ApplesoftFileViewer::makeMenuOptions(QMenu *menu) { QSettings settings; @@ -59,6 +58,14 @@ bool ApplesoftFileViewer::makeMenuOptions(QMenu *menu) connect(action, SIGNAL(toggled(bool)),SLOT(setIndentCode(bool))); menu->addAction(action); + action = new QAction("Blank &Line after RETURNs",menu); + action->setCheckable(true); + action->setChecked(settings.value("ASViewer.breakAfterReturn",false).toBool()); + setIndentCode(settings.value("ASViewer.breakAfterReturn",false).toBool(),NoReformat); + connect(action, SIGNAL(toggled(bool)), ui->findText,SLOT(clear())); + connect(action, SIGNAL(toggled(bool)),SLOT(setBreakAfterReturn(bool))); + menu->addAction(action); + menu->addSeparator(); action = new QAction("Show &Variable Explorer...",menu); @@ -113,6 +120,22 @@ void ApplesoftFileViewer::setIndentCode(bool enabled, ReformatRule reformat) reformatText(); } +void ApplesoftFileViewer::setBreakAfterReturn(bool enabled, ReformatRule reformat) +{ + if (enabled) + { + m_formatter->setFlags(m_formatter->flags() | ApplesoftFormatter::BreakAfterReturn); + } + else + { + m_formatter->setFlags(m_formatter->flags() & ~ApplesoftFormatter::BreakAfterReturn); + } + QSettings settings; + settings.setValue("ASViewer.breakAfterReturn",enabled); + if (reformat == ForceReformat) + reformatText(); +} + void ApplesoftFileViewer::setIntsAsHex(bool enabled, ReformatRule reformat) { if (enabled) @@ -131,9 +154,15 @@ void ApplesoftFileViewer::setIntsAsHex(bool enabled, ReformatRule reformat) void ApplesoftFileViewer::reformatText() { - m_formatter->formatText(); - ui->textArea->setText(m_formatter->getFormattedText()); - qDebug() << m_formatter->flowTargets(); + QTextDocument *doc = ui->textArea->document(); + + m_formatter->formatDocument(doc); + + QTextCursor cursor = ui->textArea->textCursor(); + cursor.movePosition(QTextCursor::Start,QTextCursor::MoveAnchor); + ui->textArea->setTextCursor(cursor); + + //qDebug() << m_formatter->flowTargets(); } void ApplesoftFileViewer::setFile(GenericFile *file) { @@ -151,8 +180,11 @@ void ApplesoftFileViewer::setFile(ApplesoftFile *file) { QString title = QString("AppleSoft Viewer: %1").arg(m_file->filename()); m_title = title; setWindowTitle(title); - m_formatter->formatText(); - ui->textArea->setText(m_formatter->getFormattedText()); + QTextDocument *doc = ui->textArea->document(); + m_formatter->formatDocument(doc); + QTextCursor cursor = ui->textArea->textCursor(); + cursor.movePosition(QTextCursor::Start,QTextCursor::MoveAnchor); + ui->textArea->setTextCursor(cursor); } void ApplesoftFileViewer::setData(QByteArray data) diff --git a/src/ui/viewers/applesoftfileviewer.h b/src/ui/viewers/applesoftfileviewer.h index 50e56c5..9b046a5 100644 --- a/src/ui/viewers/applesoftfileviewer.h +++ b/src/ui/viewers/applesoftfileviewer.h @@ -48,6 +48,7 @@ protected slots: void toggleWordWrap(bool enabled); void setIndentCode(bool enabled, ReformatRule reformat = ForceReformat); void setIntsAsHex(bool enabled, ReformatRule reformat = ForceReformat); + void setBreakAfterReturn(bool enabled, ReformatRule reformat = ForceReformat); void launchVarBrowser(); void reformatText();