diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 01:49:02 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 01:49:02 +0000 |
commit | 5de3dd4762ca33a0f92e79ffa4fe2ff67069d531 (patch) | |
tree | bad482b7afa4cdf47422d60a5dd2c61c7e333b09 /src/languages | |
download | ktechlab-5de3dd4762ca33a0f92e79ffa4fe2ff67069d531.tar.gz ktechlab-5de3dd4762ca33a0f92e79ffa4fe2ff67069d531.zip |
Added KDE3 version of ktechlab
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/ktechlab@1095338 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/languages')
29 files changed, 4452 insertions, 0 deletions
diff --git a/src/languages/Makefile.am b/src/languages/Makefile.am new file mode 100644 index 0000000..fef84e7 --- /dev/null +++ b/src/languages/Makefile.am @@ -0,0 +1,14 @@ +INCLUDES = -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/electronics -I$(top_srcdir)/src/electronics/components \ + -I$(top_srcdir)/src/electronics/simulation -I$(top_srcdir)/src/flowparts -I$(top_srcdir)/src/gui \ + -I$(top_srcdir)/src/languages -I$(top_srcdir)/src/mechanics -I$(top_srcdir)/src/micro -Igui \ + $(all_includes) +METASOURCES = AUTO +noinst_LTLIBRARIES = liblanguages.la +liblanguages_la_SOURCES = language.cpp languagemanager.cpp microbe.cpp \ + externallanguage.cpp gpasm.cpp gpdasm.cpp processchain.cpp flowcode.cpp asmparser.cpp \ + sdcc.cpp gplink.cpp gplib.cpp sourceline.cpp picprogrammer.cpp +noinst_HEADERS = externallanguage.h gpasm.h gpdasm.h language.h \ + languagemanager.h microbe.h processchain.h flowcode.h asmparser.h sdcc.h gplink.h gplib.h \ + sourceline.h picprogrammer.h +liblanguages_la_LIBADD = $(top_builddir)/src/gui/libgui.la diff --git a/src/languages/asmparser.cpp b/src/languages/asmparser.cpp new file mode 100644 index 0000000..eb4b7cd --- /dev/null +++ b/src/languages/asmparser.cpp @@ -0,0 +1,150 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "asmparser.h" +#include "config.h" +#include "gpsimprocessor.h" + +#include <kdebug.h> +#include <qfile.h> +#include <qregexp.h> + +AsmParser::AsmParser( const QString &url ) + : m_url(url) +{ + m_bContainsRadix = false; + m_type = Absolute; +} + + +AsmParser::~AsmParser() +{ +} + + +bool AsmParser::parse( GpsimDebugger * debugger ) +{ + QFile file(m_url); + if ( !file.open(IO_ReadOnly) ) + return false; + + QTextStream stream( &file ); + + m_type = Absolute; + m_bContainsRadix = false; + m_picID = QString::null; + + QStringList nonAbsoluteOps = QStringList::split( ",", + "code,.def,.dim,.direct,endw,extern,.file,global,idata,.ident,.line,.type,udata,udata_acs,udata_ovr,udata_shr" ); + + unsigned inputAtLine = 0; + while ( !stream.atEnd() ) + { + const QString line = stream.readLine().stripWhiteSpace(); + if ( m_type != Relocatable ) + { + QString col0 = line.section( QRegExp("[; ]"), 0, 0 ); + col0 = col0.stripWhiteSpace(); + if ( nonAbsoluteOps.contains(col0) ) + m_type = Relocatable; + } + if ( !m_bContainsRadix ) + { + if ( line.contains( QRegExp("^RADIX[\\s]*") ) || line.contains( QRegExp("^radix[\\s]*") ) ) + m_bContainsRadix = true; + } + if ( m_picID.isEmpty() ) + { + // We look for "list p = ", and "list p = picid ", and subtract the positions / lengths away from each other to get the picid text position + QRegExp fullRegExp("[lL][iI][sS][tT][\\s]+[pP][\\s]*=[\\s]*[\\d\\w]+"); + QRegExp halfRegExp("[lL][iI][sS][tT][\\s]+[pP][\\s]*=[\\s]*"); + + int startPos = fullRegExp.search(line); + if ( (startPos != -1) && (startPos == halfRegExp.search(line)) ) + { + m_picID = line.mid( startPos + halfRegExp.matchedLength(), fullRegExp.matchedLength() - halfRegExp.matchedLength() ); + m_picID = m_picID.upper(); + if ( !m_picID.startsWith("P") ) + m_picID.prepend("P"); + } + } +#ifndef NO_GPSIM + if ( debugger && line.startsWith(";#CSRC\t") ) + { + // Assembly file produced (by sdcc) from C, line is in format: + // ;#CSRC\t[file-name] [file-line] + // The filename can contain spaces. + int fileLineAt = line.findRev(" "); + + if ( fileLineAt == -1 ) + kdWarning() << k_funcinfo << "Syntax error in line \"" << line << "\" while looking for file-line" << endl; + else + { + // 7 = length_of(";#CSRC\t") + QString fileName = line.mid( 7, fileLineAt-7 ); + QString fileLineString = line.mid( fileLineAt+1, line.length() - fileLineAt - 1 ); + + if ( fileName.startsWith("\"") ) + { + // Newer versions of SDCC insert " around the filename + fileName.remove( 0, 1 ); // First " + fileName.remove( fileName.length()-1, 1 ); // Last " + } + + bool ok; + int fileLine = fileLineString.toInt(&ok) - 1; + if ( ok && fileLine >= 0 ) + debugger->associateLine( fileName, fileLine, m_url, inputAtLine ); + else + kdDebug() << k_funcinfo << "Not a valid line number: \"" << fileLineString << "\"" << endl; + } + } + if ( debugger && (line.startsWith(".line\t") || line.startsWith(";#MSRC") ) ) + { + // Assembly file produced by either sdcc or microbe, line is in format: + // \t[".line"/"#MSRC"]\t[file-line]; [file-name]\t[c/microbe source code for that line] + // We're screwed if the file name contains tabs, but hopefully not many do... + QStringList lineParts = QStringList::split( '\t', line ); + if ( lineParts.size() < 2 ) + kdWarning() << k_funcinfo << "Line is in wrong format for extracing source line and file: \""<<line<<"\""<<endl; + else + { + const QString lineAndFile = lineParts[1]; + int lineFileSplit = lineAndFile.find("; "); + if ( lineFileSplit == -1 ) + kdDebug() << k_funcinfo << "Could not find file / line split in \""<<lineAndFile<<"\""<<endl; + else + { + QString fileName = lineAndFile.mid( lineFileSplit + 2 ); + QString fileLineString = lineAndFile.left( lineFileSplit ); + + if ( fileName.startsWith("\"") ) + { + // Newer versions of SDCC insert " around the filename + fileName.remove( 0, 1 ); // First " + fileName.remove( fileName.length()-1, 1 ); // Last " + } + + bool ok; + int fileLine = fileLineString.toInt(&ok) - 1; + if ( ok && fileLine >= 0 ) + debugger->associateLine( fileName, fileLine, m_url, inputAtLine ); + else + kdDebug() << k_funcinfo << "Not a valid line number: \"" << fileLineString << "\"" << endl; + } + } + } +#endif // !NO_GPSIM + inputAtLine++; + } + + return true; +} + diff --git a/src/languages/asmparser.h b/src/languages/asmparser.h new file mode 100644 index 0000000..ab21837 --- /dev/null +++ b/src/languages/asmparser.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ASMPARSER_H +#define ASMPARSER_H + +#include <qstring.h> + +class GpsimDebugger; + +/** +Reads in an assembly file, and extracts useful information from it, such as the +PIC ID + +@author David Saxton +*/ +class AsmParser +{ + public: + AsmParser( const QString &url ); + ~AsmParser(); + + enum Type { Relocatable, Absolute }; + + /** + * Read in data from file, return success status. + * @param debugger if this is non-null, then source-line markers read + * from the assembly file (such as those beginning with ";#CSRC" will be + * passed to hllDebugger). + */ + bool parse( GpsimDebugger * debugger = 0l ); + /** + * Returns the PIC ID + */ + QString picID() const { return m_picID; } + /** + * Returns whether or not the assembly file contained the "set radix" + * directive + */ + bool containsRadix() const { return m_bContainsRadix; } + /** + * If the assembly file contains any of several key words that identify + * it as a relocatable object, then this will return Relocatable. + */ + Type type() const { return m_type; } + + protected: + const QString m_url; + QString m_picID; + bool m_bContainsRadix; + Type m_type; +}; + +#endif diff --git a/src/languages/externallanguage.cpp b/src/languages/externallanguage.cpp new file mode 100644 index 0000000..7297e63 --- /dev/null +++ b/src/languages/externallanguage.cpp @@ -0,0 +1,167 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "externallanguage.h" +#include "languagemanager.h" +#include "logview.h" + +#include <kdebug.h> +#include <kprocess.h> +#include <qregexp.h> +#include <qtimer.h> + +ExternalLanguage::ExternalLanguage( ProcessChain *processChain, KTechlab *parent, const QString &name ) + : Language( processChain, parent, name ) +{ + m_languageProcess = 0l; +} + + +ExternalLanguage::~ExternalLanguage() +{ + deleteLanguageProcess(); +} + + +void ExternalLanguage::deleteLanguageProcess() +{ + if (!m_languageProcess) + return; + + // I'm not too sure if this combination of killing the process is the best way.... +// m_languageProcess->tryTerminate(); +// QTimer::singleShot( 5000, m_languageProcess, SLOT( kill() ) ); +// delete m_languageProcess; + m_languageProcess->kill(); + m_languageProcess->deleteLater(); + + m_languageProcess = 0L; +} + + +void ExternalLanguage::receivedStdout( KProcess *, char * buffer, int buflen ) +{ + QStringList lines = QStringList::split( '\n', QString::fromLocal8Bit( buffer, buflen ), false ); + QStringList::iterator end = lines.end(); + + for ( QStringList::iterator it = lines.begin(); it != end; ++it ) + { + if ( isError( *it ) ) + { + outputError( *it ); + outputtedError( *it ); + } + else if ( isWarning( *it ) ) + { + outputWarning( *it ); + outputtedWarning( *it ); + } + else + { + outputMessage( *it ); + outputtedMessage( *it ); + } + } +} + + +void ExternalLanguage::receivedStderr( KProcess *, char * buffer, int buflen ) +{ + QStringList lines = QStringList::split( '\n', QString::fromLocal8Bit( buffer, buflen ), false ); + QStringList::iterator end = lines.end(); + + for ( QStringList::iterator it = lines.begin(); it != end; ++it ) + { + if ( isStderrOutputFatal( *it ) ) + { + outputError( *it ); + outputtedError( *it ); + } + else + { + outputWarning( *it ); + outputtedWarning( *it ); + } + } +} + + +void ExternalLanguage::processExited( KProcess * ) +{ + if ( !m_languageProcess ) + return; + bool allOk = processExited( m_languageProcess->normalExit() && m_errorCount == 0 ); + finish(allOk); + deleteLanguageProcess(); +} + + +void ExternalLanguage::processInitFailed() +{ + finish(false); + deleteLanguageProcess(); +} + + +bool ExternalLanguage::start() +{ + displayProcessCommand(); + + return m_languageProcess->start( KProcess::NotifyOnExit, KProcess::All ); +} + + +void ExternalLanguage::resetLanguageProcess() +{ + reset(); + deleteLanguageProcess(); + m_errorCount = 0; + + m_languageProcess = new KProcess(this); + + connect( m_languageProcess, SIGNAL(receivedStdout( KProcess*, char*, int )), + this, SLOT(receivedStdout( KProcess*, char*, int )) ); + + connect( m_languageProcess, SIGNAL(receivedStderr( KProcess*, char*, int )), + this, SLOT(receivedStderr( KProcess*, char*, int )) ); + + connect( m_languageProcess, SIGNAL(processExited( KProcess* )), + this, SLOT(processExited( KProcess* )) ); +} + + +void ExternalLanguage::displayProcessCommand() +{ + QStringList quotedArguments; + QValueList<QCString> arguments = m_languageProcess->args(); + + if ( arguments.size() == 1 ) + quotedArguments << arguments[0]; + + else + { + QValueList<QCString>::const_iterator end = arguments.end(); + + for ( QValueList<QCString>::const_iterator it = arguments.begin(); it != end; ++it ) + { + if ( (*it).isEmpty() || (*it).contains( QRegExp("[\\s]") ) ) + quotedArguments << KProcess::quote( *it ); + else + quotedArguments << *it; + } + } + +// outputMessage( "<i>" + quotedArguments.join(" ") + "</i>" ); + outputMessage( quotedArguments.join(" ") ); +// LanguageManager::self()->logView()->addOutput( quotedArguments.join(" "), LogView::ot_info ); +} + + +#include "externallanguage.moc" diff --git a/src/languages/externallanguage.h b/src/languages/externallanguage.h new file mode 100644 index 0000000..401c2b8 --- /dev/null +++ b/src/languages/externallanguage.h @@ -0,0 +1,97 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef EXTERNALLANGUAGE_H +#define EXTERNALLANGUAGE_H + +#include "language.h" + +class KProcess; + +/** +Base class for Language support that relies on an external program; so this +class provides functionality for dealing with external processes. + +@author Daniel Clarke +@author David Saxton +*/ +class ExternalLanguage : public Language +{ +Q_OBJECT +public: + ExternalLanguage( ProcessChain *processChain, KTechlab *parent, const QString &name ); + ~ExternalLanguage(); + +protected slots: + void receivedStdout( KProcess *, char * buffer, int buflen ); + void receivedStderr( KProcess *, char * buffer, int buflen ); + void processExited( KProcess * ); + +protected: + /** + * Call this to start the language process. ExternalLanguage will ensure + * that communication et all is properly set up. + * @return true on success, false on error + */ + bool start(); + /** + * @returns whether the string outputted to stdout is an error or not + */ + virtual bool isError( const QString &message ) const = 0; + /** + * @returns whether the string outputted to stderr is fatal (stopped compilation) + */ + virtual bool isStderrOutputFatal( const QString & message ) const { Q_UNUSED(message); return true; } + /** + * @returns whether the string outputted to stdout is a warning or not + */ + virtual bool isWarning( const QString &message ) const = 0; + /** + * Called when the process outputs a (non warning/error) message + */ + virtual void outputtedMessage( const QString &/*message*/ ) {}; + /** + * Called when the process outputs a warning + */ + virtual void outputtedWarning( const QString &/*message*/ ) {}; + /** + * Called when the process outputs an error + */ + virtual void outputtedError( const QString &/*message*/ ) {}; + /** + * Called when the process exits (called before any signals are emitted, + * etc). If you reinherit this function, you should return whether + * everything is OK. + */ + virtual bool processExited( bool successfully ) { return successfully; } + /** + * Call this function if your process could not be started - the process + * will be deleted, and a failure signal emitted. + */ + void processInitFailed(); + /** + * Disconnects and deletes the language's process. + */ + void deleteLanguageProcess(); + /** + * Creates process and makes connections, ready for the derived class to + * add arguments and start the process. + */ + void resetLanguageProcess(); + /** + * Prints out the command used for running the process, with any arguments + * that contain spaces put into quotation marks. + */ + void displayProcessCommand(); + + KProcess * m_languageProcess; +}; + +#endif diff --git a/src/languages/flowcode.cpp b/src/languages/flowcode.cpp new file mode 100644 index 0000000..d19d17e --- /dev/null +++ b/src/languages/flowcode.cpp @@ -0,0 +1,496 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "flowcodedocument.h" +#include "flowcode.h" +#include "flowcontainer.h" +#include "flowpart.h" +#include "microsettings.h" +#include "microinfo.h" +#include "micropackage.h" +#include "node.h" +#include "pinmapping.h" + +#include <klocale.h> +// #include <kmessagebox.h> +#include <qfile.h> + +FlowCode::FlowCode( ProcessChain *processChain, KTechlab *parent ) + : Language( processChain, parent, i18n("FlowCode") ) +{ + m_successfulMessage = i18n("*** Microbe generation successful ***"); + m_failedMessage = i18n("*** Microbe generation failed ***"); + p_startPart = 0l; +} + +FlowCode::~FlowCode() +{ +} + + +void FlowCode::processInput( ProcessOptions options ) +{ + m_processOptions = options; + + if ( !options.p_flowCodeDocument ) + { + options.p_flowCodeDocument = new FlowCodeDocument( QString::null, 0l ); + options.p_flowCodeDocument->openURL( options.inputFiles().first() ); + + connect( this, SIGNAL(processSucceeded( Language *)), options.p_flowCodeDocument, SLOT(deleteLater()) ); + connect( this, SIGNAL(processFailed( Language *)), options.p_flowCodeDocument, SLOT(deleteLater()) ); + } + + if ( !options.p_flowCodeDocument->microSettings() ) + { + finish(false); + return; + } + + QFile file(options.intermediaryOutput()); + if ( file.open(IO_WriteOnly | IO_ReadOnly) == false ) + { + finish(false); + return; + } + file.close(); + + if ( file.open(IO_WriteOnly) == false ) + { + finish(false); + return; + } + + const QString code = generateMicrobe( options.p_flowCodeDocument->itemList(), options.p_flowCodeDocument->microSettings() ); + if (code.isEmpty()) + { + finish(false); + return; + } + + QTextStream stream(&file); + stream << code; + file.close(); + finish(true); +} + + +void FlowCode::setStartPart( FlowPart *startPart ) +{ + p_startPart = startPart; +} + + +void FlowCode::addCode( const QString& code ) +{ + m_code += code; + if ( !m_code.endsWith("\n") ) m_code += '\n'; +} + +bool FlowCode::isValidBranch( FlowPart *flowPart ) +{ + return flowPart && (flowPart->level() >= m_curLevel) && !m_stopParts.contains(flowPart); +} + +void FlowCode::addCodeBranch( FlowPart * flowPart ) +{ + if (!flowPart) + return; + + if ( !isValidBranch(flowPart) ) + return; + + if ( m_addedParts.contains(flowPart) ) + { + const QString labelName = genLabel(flowPart->id()); + addCode( "goto "+labelName ); + m_gotos.append(labelName); + return; + } + else + { + m_addedParts.append(flowPart); + int prevLevel = m_curLevel; + m_curLevel = flowPart->level(); + + const QString labelName = genLabel(flowPart->id()); + addCode(labelName+':'); + m_labels.append(labelName); + + flowPart->generateMicrobe(this); + m_curLevel = prevLevel; + } +} + +QString FlowCode::genLabel( const QString &id ) +{ + return "__label_"+id; +} + +void FlowCode::addStopPart( FlowPart *part ) +{ + if (part) m_stopParts.append(part); +} + +void FlowCode::removeStopPart( FlowPart *part ) +{ + if (!part) return; + + // We only want to remove one instance of the FlowPart, in case it has been + // used as a StopPart for more than one FlowPart + FlowPartList::iterator it = m_stopParts.find(part); + if ( it != m_stopParts.end() ) m_stopParts.remove(it); +} + +QString FlowCode::generateMicrobe( const ItemList &itemList, MicroSettings *settings ) +{ + bool foundStart = false; + const ItemList::const_iterator end = itemList.end(); + for ( ItemList::const_iterator it = itemList.begin(); it != end; ++it ) + { + if (!*it) + continue; + + FlowPart * startPart = dynamic_cast<FlowPart*>((Item*)*it); + + if (!startPart) + continue; + + // Check to see if we have any floating connections + const NodeMap nodeMap = startPart->nodeMap(); + NodeMap::const_iterator nodeMapEnd = nodeMap.end(); + for ( NodeMap::const_iterator nodeMapIt = nodeMap.begin(); nodeMapIt != nodeMapEnd; ++nodeMapIt ) + { + Node * node = nodeMapIt.data().node; + if ( !node || (node->type() != Node::fp_out) ) + continue; + + if ( !startPart->outputPart( nodeMapIt.key() ) ) + outputWarning( i18n("Warning: Floating connection for %1").arg( startPart->id() ) ); + } + + FlowContainer * fc = dynamic_cast<FlowContainer*>((Item*)*it); + + if ( (*it)->id().startsWith("START") && startPart ) + { + foundStart = true; + setStartPart(startPart); + } + else if ( ((*it)->id().startsWith("interrupt") || (*it)->id().startsWith("sub")) && fc ) + { + addSubroutine(fc); + } + } + + if (!foundStart) + { + outputError( i18n("KTechlab was unable to find the \"Start\" part.\nThis must be included as the starting point for your program.") ); + return 0; + } + + m_addedParts.clear(); + m_stopParts.clear(); + m_gotos.clear(); + m_labels.clear(); + m_code = QString::null; + + // PIC type + { + const QString codeString = settings->microInfo()->id() + "\n"; + addCode(codeString); + } + + // Initial variables + { + QStringList vars = settings->variableNames(); + + // If "inited" is true at the end, we comment at the insertion point + bool inited = false; + const QString codeString = "// Initial variable values:\n"; + addCode(codeString); + + const QStringList::iterator end = vars.end(); + for ( QStringList::iterator it = vars.begin(); it != end; ++it ) + { + VariableInfo *info = settings->variableInfo(*it); + if ( info /*&& info->initAtStart*/ ) + { + inited = true; + addCode(*it+" = "+info->valueAsString()); + } + } + if (!inited) { + m_code.remove(codeString); + } else { + addCode("\n"); + } + } + + // Initial pin maps + { + const PinMappingMap pinMappings = settings->pinMappings(); + PinMappingMap::const_iterator end = pinMappings.end(); + for ( PinMappingMap::const_iterator it = pinMappings.begin(); it != end; ++it ) + { + QString type; + + switch ( it.data().type() ) + { + case PinMapping::Keypad_4x3: + case PinMapping::Keypad_4x4: + type = "keypad"; + break; + + case PinMapping::SevenSegment: + type = "sevenseg"; + break; + + case PinMapping::Invalid: + break; + } + + if ( type.isEmpty() ) + continue; + + addCode( QString("%1 %2 %3").arg( type ).arg( it.key() ).arg( it.data().pins().join(" ") ) ); + } + } + + // Initial port settings + { + QStringList portNames = settings->microInfo()->package()->portNames(); + const QStringList::iterator end = portNames.end(); + + // TRIS registers (remember that this is set to ..11111 on all resets) + for ( QStringList::iterator it = portNames.begin(); it != end; ++it ) + { + const int portType = settings->portType(*it); + const int pinCount = settings->microInfo()->package()->pinCount( 0, *it ); + + // We don't need to reset it if portType == 2^(pinCount-1) + if ( portType != (1<<pinCount)-1 ) + { + QString name = *it; + name.replace("PORT","TRIS"); + addCode( name+" = "+QString::number(portType) ); + } + } + + // PORT registers + for ( QStringList::iterator it = portNames.begin(); it != end; ++it ) + { + const int portState = settings->portState(*it); + addCode( (*it)+" = "+QString::number(portState) ); + } + } + + + m_curLevel = p_startPart->level(); + addCodeBranch(p_startPart); + addCode("end"); + + { + const FlowPartList::iterator end = m_subroutines.end(); + for ( FlowPartList::iterator it = m_subroutines.begin(); it != end; ++it ) + { + m_curLevel = 0; + if (*it) + { + addCode("\n"); + addCodeBranch(*it); + } + } + } + + tidyCode(); + return m_code; +} + +void FlowCode::tidyCode() +{ + // First, get rid of the unused labels + const QStringList::iterator end = m_labels.end(); + for ( QStringList::iterator it = m_labels.begin(); it != end; ++it ) + { + if ( !m_gotos.contains(*it) ) m_code.remove(*it+':'); + } + + + // And now on to handling indentation :-) + + if ( !m_code.endsWith("\n") ) m_code.append("\n"); + QString newCode; + bool multiLineComment = false; // For "/*"..."*/" + bool comment = false; // For "//" + bool asmEmbed = false; + bool asmEmbedAllowed = true; + bool asmKeyword = false; + int asmEmbedLevel = -1; + int level = 0; + + int pos=-1; + const int length = m_code.length(); + while ( ++pos<length ) + { + switch ( m_code[pos].latin1() ) + { + case '\n': + { + if (comment && !multiLineComment) comment = false; + newCode += '\n'; + if ( !comment && !asmEmbed ) + { + while ( pos+1<length && m_code[pos+1].isSpace() ) pos++; + bool closeBrace = false; + if ( pos+1<length && m_code[pos+1] == '}' ) + { + level--; + pos++; + closeBrace = true; + } + for ( int i=0; i<level; i++ ) newCode += '\t'; + if (closeBrace) newCode += '}'; + asmEmbedAllowed = true; + } + break; + } + case '/': + { + newCode += '/'; + if ( pos+1<length ) + { + if ( m_code[pos+1] == '/' ) comment = true; + else if ( m_code[pos+1] == '*' ) multiLineComment = comment = true; + newCode += m_code[++pos]; + } + asmEmbedAllowed = false; + asmKeyword = false; + break; + } + case '*': + { + newCode += '*'; + if ( pos+1<length ) + { + if ( m_code[pos++] == '/' && multiLineComment ) comment = multiLineComment = false; + newCode += m_code[pos]; + } + asmEmbedAllowed = false; + asmKeyword = false; + break; + } + case '{': + { + if (asmKeyword) { + asmEmbed = true; + asmEmbedLevel = level; + } + + if ( !comment ) level++; + newCode += '{'; + + asmEmbedAllowed = false; + asmKeyword = false; + break; + } + case '}': + { + if ( !comment ) level--; + + if (asmEmbed && asmEmbedLevel == level) + { + asmEmbed = false; + newCode += "\n"; + for ( int i=0; i<level; i++ ) newCode += '\t'; + } + newCode += '}'; + + asmEmbedAllowed = true; + asmKeyword = false; + break; + } + case 'a': + { + newCode += m_code[pos]; + if ( asmEmbedAllowed && !comment && pos+2<length ) + { + if ( m_code[pos+1] == 's' && m_code[pos+2] == 'm' ) + { + asmKeyword = true; + newCode += "sm"; + pos += 2; + } + } + break; + } + default: + { + asmEmbedAllowed = false; + asmKeyword = false; + newCode += m_code[pos]; + break; + } + } + } + m_code = newCode; +} + +void FlowCode::addSubroutine( FlowPart *part ) +{ + if ( !part || m_subroutines.contains(part) || part->parentItem() || !dynamic_cast<FlowContainer*>(part) ) return; + m_subroutines.append(part); +} + + +ProcessOptions::ProcessPath::Path FlowCode::outputPath( ProcessOptions::ProcessPath::Path inputPath ) const +{ + switch (inputPath) + { + case ProcessOptions::ProcessPath::FlowCode_AssemblyAbsolute: + return ProcessOptions::ProcessPath::Microbe_AssemblyAbsolute; + + case ProcessOptions::ProcessPath::FlowCode_Microbe: + return ProcessOptions::ProcessPath::None; + + case ProcessOptions::ProcessPath::FlowCode_PIC: + return ProcessOptions::ProcessPath::Microbe_PIC; + + case ProcessOptions::ProcessPath::FlowCode_Program: + return ProcessOptions::ProcessPath::Microbe_Program; + + case ProcessOptions::ProcessPath::AssemblyAbsolute_PIC: + case ProcessOptions::ProcessPath::AssemblyAbsolute_Program: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Library: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Object: + case ProcessOptions::ProcessPath::AssemblyRelocatable_PIC: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Program: + case ProcessOptions::ProcessPath::C_AssemblyRelocatable: + case ProcessOptions::ProcessPath::C_Library: + case ProcessOptions::ProcessPath::C_Object: + case ProcessOptions::ProcessPath::C_PIC: + case ProcessOptions::ProcessPath::C_Program: + case ProcessOptions::ProcessPath::Microbe_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Microbe_PIC: + case ProcessOptions::ProcessPath::Microbe_Program: + case ProcessOptions::ProcessPath::Object_Disassembly: + case ProcessOptions::ProcessPath::Object_Library: + case ProcessOptions::ProcessPath::Object_PIC: + case ProcessOptions::ProcessPath::Object_Program: + case ProcessOptions::ProcessPath::PIC_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Program_Disassembly: + case ProcessOptions::ProcessPath::Program_PIC: + case ProcessOptions::ProcessPath::Invalid: + case ProcessOptions::ProcessPath::None: + return ProcessOptions::ProcessPath::Invalid; + } + + return ProcessOptions::ProcessPath::Invalid; +} + diff --git a/src/languages/flowcode.h b/src/languages/flowcode.h new file mode 100644 index 0000000..afa17db --- /dev/null +++ b/src/languages/flowcode.h @@ -0,0 +1,107 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef FLOWCODE_H +#define FLOWCODE_H + +#include "language.h" + +#include <qguardedptr.h> +#include <qobject.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qvaluelist.h> + +class CNItem; +class FlowPart; +class Item; +class MicroSettings; + +typedef QValueList<FlowPart*> FlowPartList; +typedef QValueList<QGuardedPtr<Item> > ItemList; + +/** +"FlowCode" can possibly be considered a misnomer, as the output is actually Microbe. +However, the function of this class is to take a set of FlowParts, and generate the +basic from the code that they create. The 3 simple steps for usage of this function: +(1) Create an instance of this class, giving the Start point and setings +(2) Add all the subroutines present using addSubroutine() +(3) Call generateMicrobe() to get the Microbe code. +@author David Saxton +*/ +class FlowCode : public Language +{ +public: + FlowCode( ProcessChain *processChain, KTechlab *parent ); + + virtual void processInput( ProcessOptions options ); + virtual ProcessOptions::ProcessPath::Path outputPath( ProcessOptions::ProcessPath::Path inputPath ) const; + + /** + * You must set the start part + */ + void setStartPart( FlowPart *startPart ); + ~FlowCode(); + /** + * You must add all top level subroutines using this function + */ + void addSubroutine( FlowPart *part ); + /** + * Adds code at the current insertion point + */ + void addCode( const QString& code ); + /** + * Adds a code branch to the current insertion point. This will stop when the level gets + * below the original starting level (so for insertion of the contents of a for loop, + * insertion will stop at the end of that for loop). + * @param flowPart The next FlowPart to get code from + */ + void addCodeBranch( FlowPart *flowPart ); + /** + * Designates a FlowPart as a stopping part (i.e. will refuse requests to addCodeBranch + * for that FlowPart until removeStopPart is called + */ + void addStopPart( FlowPart *part ); + /** + * Undesignates a FlowPart as a stopping part + */ + void removeStopPart( FlowPart *part ); + /** + * Generates and returns the microbe code + * @param nonVerbal if true then will not inform the user when something goes wrong + */ + QString generateMicrobe( const ItemList &itemList, MicroSettings *settings ); + /** + * Returns true if the FlowPart is a valid one for adding a branch + */ + bool isValidBranch( FlowPart *flowPart ); + /** + * Generates a nice label name from the string, e.g. genLabel("callsub") + * returns "__label_callsub". + */ + static QString genLabel( const QString &id ); + +protected: + /** + * Performs indenting, removal of unnecessary labels, etc. + */ + void tidyCode(); + + QStringList m_gotos; // Gotos used + QStringList m_labels; // Labels used + FlowPartList m_subroutines; + FlowPartList m_addedParts; + FlowPartList m_stopParts; + FlowPart *p_startPart; + QString m_code; + int m_curLevel; +}; + +#endif diff --git a/src/languages/gpasm.cpp b/src/languages/gpasm.cpp new file mode 100644 index 0000000..447354e --- /dev/null +++ b/src/languages/gpasm.cpp @@ -0,0 +1,187 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "asmparser.h" +#include "docmanager.h" +#include "gpasm.h" +#include "logview.h" +#include "languagemanager.h" +#include "src/core/ktlconfig.h" + +#include <klocale.h> +#include <kmessagebox.h> +#include <kprocess.h> +#include <qregexp.h> + +Gpasm::Gpasm( ProcessChain *processChain, KTechlab * parent ) + : ExternalLanguage( processChain, parent, "Gpasm" ) +{ + m_successfulMessage = i18n("*** Assembly successful ***"); + m_failedMessage = i18n("*** Assembly failed ***"); +} + + +Gpasm::~Gpasm() +{ +} + + +void Gpasm::processInput( ProcessOptions options ) +{ + resetLanguageProcess(); + m_processOptions = options; + + AsmParser p( options.inputFiles().first() ); + p.parse(); + + *m_languageProcess << ("gpasm"); + + if ( ProcessOptions::ProcessPath::from( options.processPath() ) == ProcessOptions::ProcessPath::AssemblyRelocatable ) + *m_languageProcess << ("--object"); + +// *m_languageProcess << ("--debug-info"); // Debug info + + // Output filename + *m_languageProcess << ("--output"); + *m_languageProcess << ( options.intermediaryOutput() ); + + if ( !options.m_hexFormat.isEmpty() ) + { + *m_languageProcess << ("--hex-format"); + *m_languageProcess << (options.m_hexFormat); + } + + // Radix + if ( !p.containsRadix() ) + { + *m_languageProcess << ("--radix"); + switch( KTLConfig::radix() ) + { + case KTLConfig::EnumRadix::Binary: + *m_languageProcess << ("BIN"); + break; + case KTLConfig::EnumRadix::Octal: + *m_languageProcess << ("OCT"); + break; + case KTLConfig::EnumRadix::Hexadecimal: + *m_languageProcess << ("HEX"); + break; + case KTLConfig::EnumRadix::Decimal: + default: + *m_languageProcess << ("DEC"); + break; + } + } + + // Warning Level + *m_languageProcess << ("--warning"); + switch( KTLConfig::gpasmWarningLevel() ) + { + case KTLConfig::EnumGpasmWarningLevel::Warnings: + *m_languageProcess << ("1"); + break; + case KTLConfig::EnumGpasmWarningLevel::Errors: + *m_languageProcess << ("2"); + break; + default: + case KTLConfig::EnumGpasmWarningLevel::All: + *m_languageProcess << ("0"); + break; + } + + // Ignore case + if ( KTLConfig::ignoreCase() ) + *m_languageProcess << ("--ignore-case"); + + // Dos formatting + if ( KTLConfig::dosFormat() ) + *m_languageProcess << ("--dos"); + + // Force list + if ( options.b_forceList ) + *m_languageProcess << ("--force-list"); + + // Other options + if ( !KTLConfig::miscGpasmOptions().isEmpty() ) + *m_languageProcess << ( KTLConfig::miscGpasmOptions() ); + + // Input Asm file + *m_languageProcess << ( options.inputFiles().first() ); + + if ( !start() ) + { + KMessageBox::sorry( LanguageManager::self()->logView(), i18n("Assembly failed. Please check you have gputils installed.") ); + processInitFailed(); + return; + } +} + + +bool Gpasm::isError( const QString &message ) const +{ + return message.contains( "Error", false ); +} + + +bool Gpasm::isWarning( const QString &message ) const +{ + return message.contains( "Warning", false ); +} + + +ProcessOptions::ProcessPath::Path Gpasm::outputPath( ProcessOptions::ProcessPath::Path inputPath ) const +{ + switch (inputPath) + { + case ProcessOptions::ProcessPath::AssemblyAbsolute_PIC: + return ProcessOptions::ProcessPath::Program_PIC; + + case ProcessOptions::ProcessPath::AssemblyAbsolute_Program: + return ProcessOptions::ProcessPath::None; + + case ProcessOptions::ProcessPath::AssemblyRelocatable_Library: + return ProcessOptions::ProcessPath::Object_Library; + + case ProcessOptions::ProcessPath::AssemblyRelocatable_Object: + return ProcessOptions::ProcessPath::None; + + case ProcessOptions::ProcessPath::AssemblyRelocatable_PIC: + return ProcessOptions::ProcessPath::Object_PIC; + + case ProcessOptions::ProcessPath::AssemblyRelocatable_Program: + return ProcessOptions::ProcessPath::Object_Program; + + case ProcessOptions::ProcessPath::C_AssemblyRelocatable: + case ProcessOptions::ProcessPath::C_Library: + case ProcessOptions::ProcessPath::C_Object: + case ProcessOptions::ProcessPath::C_PIC: + case ProcessOptions::ProcessPath::C_Program: + case ProcessOptions::ProcessPath::FlowCode_AssemblyAbsolute: + case ProcessOptions::ProcessPath::FlowCode_Microbe: + case ProcessOptions::ProcessPath::FlowCode_PIC: + case ProcessOptions::ProcessPath::FlowCode_Program: + case ProcessOptions::ProcessPath::Microbe_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Microbe_PIC: + case ProcessOptions::ProcessPath::Microbe_Program: + case ProcessOptions::ProcessPath::Object_Disassembly: + case ProcessOptions::ProcessPath::Object_Library: + case ProcessOptions::ProcessPath::Object_PIC: + case ProcessOptions::ProcessPath::Object_Program: + case ProcessOptions::ProcessPath::PIC_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Program_Disassembly: + case ProcessOptions::ProcessPath::Program_PIC: + case ProcessOptions::ProcessPath::Invalid: + case ProcessOptions::ProcessPath::None: + return ProcessOptions::ProcessPath::Invalid; + } + + return ProcessOptions::ProcessPath::Invalid; +} + diff --git a/src/languages/gpasm.h b/src/languages/gpasm.h new file mode 100644 index 0000000..c92a969 --- /dev/null +++ b/src/languages/gpasm.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef GPASM_H +#define GPASM_H + +#include "externallanguage.h" + +/** +@short Interface to the GNU PIC assembler +@author David Saxton +*/ +class Gpasm : public ExternalLanguage +{ + public: + Gpasm( ProcessChain *processChain, KTechlab *parent ); + ~Gpasm(); + + virtual void processInput( ProcessOptions options ); + virtual ProcessOptions::ProcessPath::Path outputPath( ProcessOptions::ProcessPath::Path inputPath ) const; + + protected: + virtual bool isError( const QString &message ) const; + virtual bool isWarning( const QString &message ) const; +}; + +#endif diff --git a/src/languages/gpdasm.cpp b/src/languages/gpdasm.cpp new file mode 100644 index 0000000..8c255d3 --- /dev/null +++ b/src/languages/gpdasm.cpp @@ -0,0 +1,158 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "docmanager.h" +#include "gpdasm.h" +#include "logview.h" +#include "languagemanager.h" + +#include <klocale.h> +#include <kmessagebox.h> +#include <kprocess.h> +#include <qfile.h> +#include <qregexp.h> + +Gpdasm::Gpdasm( ProcessChain *processChain, KTechlab *parent ) + : ExternalLanguage( processChain, parent, "Gpdasm" ) +{ + m_successfulMessage = i18n("*** Disassembly successful ***"); + m_failedMessage = i18n("*** Disassembly failed ***"); +} + + +Gpdasm::~Gpdasm() +{ +} + + +void Gpdasm::processInput( ProcessOptions options ) +{ + resetLanguageProcess(); + m_asmOutput = ""; + m_processOptions = options;; + + *m_languageProcess << ("gpdasm"); + + *m_languageProcess << ("--processor"); + *m_languageProcess << ( options.m_picID ); + *m_languageProcess << ( options.inputFiles().first() ); + + if ( !start() ) + { + KMessageBox::sorry( LanguageManager::self()->logView(), i18n("Disassembly failed. Please check you have gputils installed.") ); + processInitFailed(); + return; + } +} + + +void Gpdasm::outputtedMessage( const QString &message ) +{ + m_asmOutput += message + "\n"; +} + + +bool Gpdasm::processExited( bool successfully ) +{ + if (!successfully) + return false; + + QFile file(m_processOptions.intermediaryOutput()); + if ( file.open(IO_WriteOnly) == false ) + return false; + + QTextStream stream(&file); + stream << m_asmOutput; + file.close(); + return true; +} + + +bool Gpdasm::isError( const QString &message ) const +{ + return (message.find( "error", -1, false ) != -1); +} + + +bool Gpdasm::isWarning( const QString &message ) const +{ + return (message.find( "warning", -1, false ) != -1); +} + + +MessageInfo Gpdasm::extractMessageInfo( const QString &text ) +{ + if ( text.length()<5 || !text.startsWith("/") ) + return MessageInfo(); + + const int index = text.find( ".asm", 0, false )+4; + if ( index == -1+4 ) + return MessageInfo(); + const QString fileName = text.left(index); + + // Extra line number + const QString message = text.right(text.length()-index); + const int linePos = message.find( QRegExp(":[\\d]+") ); + int line = -1; + if ( linePos != -1 ) + { + const int linePosEnd = message.find( ':', linePos+1 ); + if ( linePosEnd != -1 ) + { + const QString number = message.mid( linePos+1, linePosEnd-linePos-1 ).stripWhiteSpace(); + bool ok; + line = number.toInt(&ok)-1; + if (!ok) line = -1; + } + } + + return MessageInfo( fileName, line ); +} + + + +ProcessOptions::ProcessPath::Path Gpdasm::outputPath( ProcessOptions::ProcessPath::Path inputPath ) const +{ + switch (inputPath) + { + case ProcessOptions::ProcessPath::Object_Disassembly: + case ProcessOptions::ProcessPath::Program_Disassembly: + return ProcessOptions::ProcessPath::None; + + case ProcessOptions::ProcessPath::AssemblyAbsolute_PIC: + case ProcessOptions::ProcessPath::AssemblyAbsolute_Program: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Library: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Object: + case ProcessOptions::ProcessPath::AssemblyRelocatable_PIC: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Program: + case ProcessOptions::ProcessPath::C_AssemblyRelocatable: + case ProcessOptions::ProcessPath::C_Library: + case ProcessOptions::ProcessPath::C_Object: + case ProcessOptions::ProcessPath::C_PIC: + case ProcessOptions::ProcessPath::C_Program: + case ProcessOptions::ProcessPath::FlowCode_AssemblyAbsolute: + case ProcessOptions::ProcessPath::FlowCode_Microbe: + case ProcessOptions::ProcessPath::FlowCode_PIC: + case ProcessOptions::ProcessPath::FlowCode_Program: + case ProcessOptions::ProcessPath::Microbe_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Microbe_PIC: + case ProcessOptions::ProcessPath::Microbe_Program: + case ProcessOptions::ProcessPath::Object_Library: + case ProcessOptions::ProcessPath::Object_PIC: + case ProcessOptions::ProcessPath::Object_Program: + case ProcessOptions::ProcessPath::PIC_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Program_PIC: + case ProcessOptions::ProcessPath::Invalid: + case ProcessOptions::ProcessPath::None: + return ProcessOptions::ProcessPath::Invalid; + } + + return ProcessOptions::ProcessPath::Invalid; +} diff --git a/src/languages/gpdasm.h b/src/languages/gpdasm.h new file mode 100644 index 0000000..149ed26 --- /dev/null +++ b/src/languages/gpdasm.h @@ -0,0 +1,39 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef GPDASM_H +#define GPDASM_H + +#include <externallanguage.h> + +/** +Interface to the GNU Pic Disassembler +@author David Saxton +*/ +class Gpdasm : public ExternalLanguage +{ +public: + Gpdasm( ProcessChain *processChain, KTechlab *parent ); + ~Gpdasm(); + + virtual void processInput( ProcessOptions options ); + virtual MessageInfo extractMessageInfo( const QString &text ); + virtual ProcessOptions::ProcessPath::Path outputPath( ProcessOptions::ProcessPath::Path inputPath ) const; + +protected: + virtual void outputtedMessage( const QString &message ); + virtual bool isError( const QString &message ) const; + virtual bool isWarning( const QString &message ) const; + virtual bool processExited( bool successfully ); + + QString m_asmOutput; // Outputed by gpdasm +}; + +#endif diff --git a/src/languages/gplib.cpp b/src/languages/gplib.cpp new file mode 100644 index 0000000..db4a32b --- /dev/null +++ b/src/languages/gplib.cpp @@ -0,0 +1,139 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "gplib.h" +#include "languagemanager.h" +#include "logview.h" + +#include <klocale.h> +#include <kmessagebox.h> +#include <kprocess.h> + +Gplib::Gplib( ProcessChain *processChain, KTechlab * parent ) + : ExternalLanguage( processChain, parent, "Gpasm" ) +{ + m_successfulMessage = i18n("*** Archiving successful ***"); + m_failedMessage = i18n("*** Archiving failed ***"); +} + + +Gplib::~Gplib() +{ +} + + +void Gplib::processInput( ProcessOptions options ) +{ + resetLanguageProcess(); + m_processOptions = options; + + *m_languageProcess << ("gplib"); + *m_languageProcess << ("--create"); + + *m_languageProcess << ( options.intermediaryOutput() ); + + const QStringList inputFiles = options.inputFiles(); + QStringList::const_iterator end = inputFiles.end(); + for ( QStringList::const_iterator it = inputFiles.begin(); it != end; ++it ) + *m_languageProcess << ( *it ); + + if ( !start() ) + { + KMessageBox::sorry( LanguageManager::self()->logView(), i18n("Linking failed. Please check you have gputils installed.") ); + processInitFailed(); + return; + } +} + + +bool Gplib::isError( const QString &message ) const +{ + return message.contains( "Error", false ); +} + + +bool Gplib::isWarning( const QString &message ) const +{ + return message.contains( "Warning", false ); +} + + +MessageInfo Gplib::extractMessageInfo( const QString &text ) +{ +#if 0 + if ( text.length()<5 || !text.startsWith("/") ) + return MessageInfo(); + + const int index = text.find( ".asm", 0, false )+4; + if ( index == -1+4 ) + return MessageInfo(); + const QString fileName = text.left(index); + + // Extra line number + const QString message = text.right(text.length()-index); + const int linePos = message.find( QRegExp(":[\\d]+") ); + int line = -1; + if ( linePos != -1 ) +{ + const int linePosEnd = message.find( ':', linePos+1 ); + if ( linePosEnd != -1 ) +{ + const QString number = message.mid( linePos+1, linePosEnd-linePos-1 ).stripWhiteSpace(); + bool ok; + line = number.toInt(&ok)-1; + if (!ok) line = -1; +} +} + return MessageInfo( fileName, line ); +#endif + return MessageInfo(); +} + + + + +ProcessOptions::ProcessPath::Path Gplib::outputPath( ProcessOptions::ProcessPath::Path inputPath ) const +{ + switch (inputPath) + { + case ProcessOptions::ProcessPath::Object_Library: + return ProcessOptions::ProcessPath::None; + + case ProcessOptions::ProcessPath::AssemblyAbsolute_PIC: + case ProcessOptions::ProcessPath::AssemblyAbsolute_Program: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Library: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Object: + case ProcessOptions::ProcessPath::AssemblyRelocatable_PIC: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Program: + case ProcessOptions::ProcessPath::C_AssemblyRelocatable: + case ProcessOptions::ProcessPath::C_Library: + case ProcessOptions::ProcessPath::C_Object: + case ProcessOptions::ProcessPath::C_PIC: + case ProcessOptions::ProcessPath::C_Program: + case ProcessOptions::ProcessPath::FlowCode_AssemblyAbsolute: + case ProcessOptions::ProcessPath::FlowCode_Microbe: + case ProcessOptions::ProcessPath::FlowCode_PIC: + case ProcessOptions::ProcessPath::FlowCode_Program: + case ProcessOptions::ProcessPath::Microbe_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Microbe_PIC: + case ProcessOptions::ProcessPath::Microbe_Program: + case ProcessOptions::ProcessPath::Object_Disassembly: + case ProcessOptions::ProcessPath::Object_PIC: + case ProcessOptions::ProcessPath::Object_Program: + case ProcessOptions::ProcessPath::PIC_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Program_Disassembly: + case ProcessOptions::ProcessPath::Program_PIC: + case ProcessOptions::ProcessPath::Invalid: + case ProcessOptions::ProcessPath::None: + return ProcessOptions::ProcessPath::Invalid; + } + + return ProcessOptions::ProcessPath::Invalid; +} diff --git a/src/languages/gplib.h b/src/languages/gplib.h new file mode 100644 index 0000000..35cb1da --- /dev/null +++ b/src/languages/gplib.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef GPLIB_H +#define GPLIB_H + +#include <externallanguage.h> + +/** +@author David Saxton +*/ +class Gplib : public ExternalLanguage +{ + public: + Gplib( ProcessChain *processChain, KTechlab *parent ); + ~Gplib(); + + virtual void processInput( ProcessOptions options ); + virtual MessageInfo extractMessageInfo( const QString &text ); + virtual ProcessOptions::ProcessPath::Path outputPath( ProcessOptions::ProcessPath::Path inputPath ) const; + + protected: + virtual bool isError( const QString &message ) const; + virtual bool isWarning( const QString &message ) const; +}; + +#endif diff --git a/src/languages/gplink.cpp b/src/languages/gplink.cpp new file mode 100644 index 0000000..548449a --- /dev/null +++ b/src/languages/gplink.cpp @@ -0,0 +1,174 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "gplink.h" +#include "languagemanager.h" +#include "logview.h" + +#include <klocale.h> +#include <kmessagebox.h> +#include <kprocess.h> + +Gplink::Gplink( ProcessChain *processChain, KTechlab * parent ) + : ExternalLanguage( processChain, parent, "Gpasm" ) +{ + m_successfulMessage = i18n("*** Linking successful ***"); + m_failedMessage = i18n("*** Linking failed ***"); +} + + +Gplink::~Gplink() +{ +} + + +void Gplink::processInput( ProcessOptions options ) +{ + resetLanguageProcess(); + m_processOptions = options; + + *m_languageProcess << ("gplink"); + + if ( !options.m_hexFormat.isEmpty() ) + { + *m_languageProcess << ("--hex-format"); + *m_languageProcess << (options.m_hexFormat); + } + + if ( options.m_bOutputMapFile ) + *m_languageProcess << ("--map"); + + if ( !options.m_libraryDir.isEmpty() ) + { + *m_languageProcess << ("--include"); + *m_languageProcess << ( options.m_libraryDir ); + } + + if ( !options.m_linkerScript.isEmpty() ) + { + *m_languageProcess << ("--script"); + *m_languageProcess << ( options.m_linkerScript ); + } + + if ( !options.m_linkOther.isEmpty() ) + *m_languageProcess << (options.m_linkOther); + + // Output hex file + *m_languageProcess << ("--output"); + *m_languageProcess << ( options.intermediaryOutput() ); + + // Input object file + const QStringList inputFiles = options.inputFiles(); + QStringList::const_iterator end = inputFiles.end(); + for ( QStringList::const_iterator it = inputFiles.begin(); it != end; ++it ) + *m_languageProcess << ( *it ); + + // Other libraries + end = options.m_linkLibraries.end(); + for ( QStringList::const_iterator it = options.m_linkLibraries.begin(); it != end; ++it ) + *m_languageProcess << ( *it ); + + if ( !start() ) + { + KMessageBox::sorry( LanguageManager::self()->logView(), i18n("Linking failed. Please check you have gputils installed.") ); + processInitFailed(); + return; + } +} + + +bool Gplink::isError( const QString &message ) const +{ + return message.contains( "Error", false ); +} + + +bool Gplink::isWarning( const QString &message ) const +{ + return message.contains( "Warning", false ); +} + + +MessageInfo Gplink::extractMessageInfo( const QString &text ) +{ +#if 0 + if ( text.length()<5 || !text.startsWith("/") ) + return MessageInfo(); + + const int index = text.find( ".asm", 0, false )+4; + if ( index == -1+4 ) + return MessageInfo(); + const QString fileName = text.left(index); + + // Extra line number + const QString message = text.right(text.length()-index); + const int linePos = message.find( QRegExp(":[\\d]+") ); + int line = -1; + if ( linePos != -1 ) + { + const int linePosEnd = message.find( ':', linePos+1 ); + if ( linePosEnd != -1 ) + { + const QString number = message.mid( linePos+1, linePosEnd-linePos-1 ).stripWhiteSpace(); + bool ok; + line = number.toInt(&ok)-1; + if (!ok) line = -1; + } + } + return MessageInfo( fileName, line ); +#endif + return MessageInfo(); +} + + + +ProcessOptions::ProcessPath::Path Gplink::outputPath( ProcessOptions::ProcessPath::Path inputPath ) const +{ + switch (inputPath) + { + case ProcessOptions::ProcessPath::Object_PIC: + return ProcessOptions::ProcessPath::Program_PIC; + + case ProcessOptions::ProcessPath::Object_Program: + return ProcessOptions::ProcessPath::None; + + case ProcessOptions::ProcessPath::AssemblyAbsolute_PIC: + case ProcessOptions::ProcessPath::AssemblyAbsolute_Program: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Library: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Object: + case ProcessOptions::ProcessPath::AssemblyRelocatable_PIC: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Program: + case ProcessOptions::ProcessPath::C_AssemblyRelocatable: + case ProcessOptions::ProcessPath::C_Library: + case ProcessOptions::ProcessPath::C_Object: + case ProcessOptions::ProcessPath::C_PIC: + case ProcessOptions::ProcessPath::C_Program: + case ProcessOptions::ProcessPath::FlowCode_AssemblyAbsolute: + case ProcessOptions::ProcessPath::FlowCode_Microbe: + case ProcessOptions::ProcessPath::FlowCode_PIC: + case ProcessOptions::ProcessPath::FlowCode_Program: + case ProcessOptions::ProcessPath::Microbe_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Microbe_PIC: + case ProcessOptions::ProcessPath::Microbe_Program: + case ProcessOptions::ProcessPath::Object_Disassembly: + case ProcessOptions::ProcessPath::Object_Library: + case ProcessOptions::ProcessPath::PIC_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Program_Disassembly: + case ProcessOptions::ProcessPath::Program_PIC: + case ProcessOptions::ProcessPath::Invalid: + case ProcessOptions::ProcessPath::None: + return ProcessOptions::ProcessPath::Invalid; + } + + return ProcessOptions::ProcessPath::Invalid; +} + + + diff --git a/src/languages/gplink.h b/src/languages/gplink.h new file mode 100644 index 0000000..c60f9f9 --- /dev/null +++ b/src/languages/gplink.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef GPLINK_H +#define GPLINK_H + +#include <externallanguage.h> + +/** +@short Interface to the GNU PIC linker +@author David Saxton +*/ +class Gplink : public ExternalLanguage +{ + public: + Gplink( ProcessChain *processChain, KTechlab *parent ); + ~Gplink(); + + virtual void processInput( ProcessOptions options ); + virtual MessageInfo extractMessageInfo( const QString &text ); + virtual ProcessOptions::ProcessPath::Path outputPath( ProcessOptions::ProcessPath::Path inputPath ) const; + + protected: + virtual bool isError( const QString &message ) const; + virtual bool isWarning( const QString &message ) const; +}; + +#endif diff --git a/src/languages/language.cpp b/src/languages/language.cpp new file mode 100644 index 0000000..e7ce759 --- /dev/null +++ b/src/languages/language.cpp @@ -0,0 +1,558 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "asmparser.h" +#include "ktechlab.h" +#include "language.h" +#include "logview.h" +#include "outputmethoddlg.h" +#include "processchain.h" +#include "projectmanager.h" +#include "languagemanager.h" +#include "src/core/ktlconfig.h" + +#include <kdebug.h> +#include <kio/netaccess.h> +#include <kmessagebox.h> +#include <kprocess.h> +#include <qregexp.h> +#include <qtimer.h> + +//BEGIN class Language +Language::Language( ProcessChain *processChain, KTechlab *parent, const QString &name ) + : QObject(parent,name) +{ + p_ktechlab = parent; + p_processChain = processChain; +} + + +Language::~Language() +{ +} + + +void Language::outputMessage( const QString &message ) +{ + LanguageManager::self()->slotMessage( message, extractMessageInfo(message) ); +} + + +void Language::outputWarning( const QString &message ) +{ + LanguageManager::self()->slotWarning( message, extractMessageInfo(message) ); +} + + +void Language::outputError( const QString &message ) +{ + LanguageManager::self()->slotError( message, extractMessageInfo(message) ); + m_errorCount++; +} + + +void Language::finish( bool successful ) +{ + if (successful) + { + outputMessage(m_successfulMessage + "\n"); + p_ktechlab->slotChangeStatusbar(m_successfulMessage); + + ProcessOptions::ProcessPath::Path newPath = outputPath( m_processOptions.processPath() ); + + if ( newPath == ProcessOptions::ProcessPath::None ) + emit processSucceeded(this); + + else if (p_processChain) + { + m_processOptions.setInputFiles( m_processOptions.intermediaryOutput() ); + m_processOptions.setIntermediaryOutput( m_processOptions.targetFile() ); + m_processOptions.setProcessPath(newPath); +// p_processChain->compile(m_processOptions); + p_processChain->setProcessOptions(m_processOptions); + p_processChain->compile(); + } + } + else + { + outputError(m_failedMessage + "\n"); + p_ktechlab->slotChangeStatusbar(m_failedMessage); + emit processFailed(this); + return; + } +} + + +void Language::reset() +{ + m_errorCount = 0; +} + + +MessageInfo Language::extractMessageInfo( const QString &text ) +{ + if ( !text.startsWith("/") ) + return MessageInfo(); + + const int index = text.find( ":", 0, false ); + if ( index == -1 ) + return MessageInfo(); + const QString fileName = text.left(index); + + // Extra line number + const QString message = text.right(text.length()-index); + const int linePos = message.find( QRegExp(":[\\d]+") ); + int line = -1; + if ( linePos != -1 ) + { + const int linePosEnd = message.find( ':', linePos+1 ); + if ( linePosEnd != -1 ) + { + const QString number = message.mid( linePos+1, linePosEnd-linePos-1 ).stripWhiteSpace(); + bool ok; + line = number.toInt(&ok)-1; + if (!ok) line = -1; + } + } + return MessageInfo( fileName, line ); +} +//END class Language + + + +//BEGIN class ProcessOptionsSpecial +ProcessOptionsSpecial::ProcessOptionsSpecial() +{ + m_bOutputMapFile = true; + b_forceList = true; + b_addToProject = ProjectManager::self()->currentProject(); + + p_flowCodeDocument = 0l; + + switch ( KTLConfig::hexFormat() ) + { + case KTLConfig::EnumHexFormat::inhx8m: + m_hexFormat = "inhx8m"; + break; + + case KTLConfig::EnumHexFormat::inhx8s: + m_hexFormat = "inhx8s"; + break; + + case KTLConfig::EnumHexFormat::inhx16: + m_hexFormat = "inhx16"; + break; + + case KTLConfig::EnumHexFormat::inhx32: + default: + m_hexFormat = "inhx32"; + break; + } +} +//END class ProcessOptionsSpecial + + +//BEGIN class ProcessOptions +ProcessOptions::ProcessOptions() +{ + m_pHelper = new ProcessOptionsHelper; + + b_targetFileSet = false; + m_pTextOutputTarget = 0l; +} + + +ProcessOptions::ProcessOptions( OutputMethodInfo info ) +{ + m_pHelper = new ProcessOptionsHelper; + + b_addToProject = info.addToProject(); + m_picID = info.picID(); + b_targetFileSet = false; + + QString target; + if ( !KIO::NetAccess::download( info.outputFile(), target, 0l ) ) + { + // If the file could not be downloaded, for example does not + // exist on disk, NetAccess will tell us what error to use + KMessageBox::error( 0l, KIO::NetAccess::lastErrorString() ); + + return; + } + setTargetFile(target); + + switch ( info.method() ) + { + case OutputMethodInfo::Method::Direct: + m_method = Method::LoadAsNew; + break; + + case OutputMethodInfo::Method::SaveAndForget: + m_method = Method::Forget; + break; + + case OutputMethodInfo::Method::SaveAndLoad: + m_method = Method::Load; + break; + } +} + + +void ProcessOptions::setTextOutputTarget( TextDocument * target, QObject * receiver, const char * slot ) +{ + m_pTextOutputTarget = target; + QObject::connect( m_pHelper, SIGNAL(textOutputtedTo( TextDocument* )), receiver, slot ); +} + + +void ProcessOptions::setTextOutputtedTo( TextDocument * outputtedTo ) +{ + m_pTextOutputTarget = outputtedTo; + emit m_pHelper->textOutputtedTo( m_pTextOutputTarget ); +} + + +void ProcessOptions::setTargetFile( const QString &file ) +{ + if (b_targetFileSet) + { + kdWarning() << "Trying to reset target file!"<<endl; + return; + } + m_targetFile = file; + m_intermediaryFile = file; + b_targetFileSet = true; +} + + +ProcessOptions::ProcessPath::MediaType ProcessOptions::guessMediaType( const QString & url ) +{ + QString extension = url.right( url.length() - url.findRev('.') - 1 ); + extension = extension.lower(); + + if ( extension == "asm" ) + { + // We'll have to look at the file contents to determine its type... + AsmParser p( url ); + p.parse(); + switch ( p.type() ) + { + case AsmParser::Relocatable: + return ProcessPath::AssemblyRelocatable; + + case AsmParser::Absolute: + return ProcessPath::AssemblyAbsolute; + } + } + + if ( extension == "c" ) + return ProcessPath::C; + + if ( extension == "flowcode" ) + return ProcessPath::FlowCode; + + if ( extension == "a" || extension == "lib" ) + return ProcessPath::Library; + + if ( extension == "microbe" || extension == "basic" ) + return ProcessPath::Microbe; + + if ( extension == "o" ) + return ProcessPath::Object; + + if ( extension == "hex" ) + return ProcessPath::Program; + + return ProcessPath::Unknown; +} + + +ProcessOptions::ProcessPath::Path ProcessOptions::ProcessPath::path( MediaType from, MediaType to ) +{ + switch (from) + { + case AssemblyAbsolute: + switch (to) + { + case AssemblyAbsolute: + return None; + case Pic: + return AssemblyAbsolute_PIC; + case Program: + return AssemblyAbsolute_Program; + + case AssemblyRelocatable: + case C: + case Disassembly: + case FlowCode: + case Library: + case Microbe: + case Object: + case Unknown: + return Invalid; + } + + case AssemblyRelocatable: + switch (to) + { + case Library: + return AssemblyRelocatable_Library; + case Object: + return AssemblyRelocatable_Object; + case Pic: + return AssemblyRelocatable_PIC; + case Program: + return AssemblyRelocatable_Program; + + case AssemblyAbsolute: + case AssemblyRelocatable: + case C: + case Disassembly: + case FlowCode: + case Microbe: + case Unknown: + return Invalid; + } + + case C: + switch (to) + { + case AssemblyRelocatable: + return C_AssemblyRelocatable; + case Library: + return C_Library; + case Object: + return C_Object; + case Pic: + return C_PIC; + case Program: + return C_Program; + + case AssemblyAbsolute: + case C: + case Disassembly: + case FlowCode: + case Microbe: + case Unknown: + return Invalid; + } + + case Disassembly: + return Invalid; + + case FlowCode: + switch (to) + { + case AssemblyAbsolute: + return FlowCode_AssemblyAbsolute; + case Microbe: + return FlowCode_Microbe; + case Pic: + return FlowCode_PIC; + case Program: + return FlowCode_Program; + + case AssemblyRelocatable: + case C: + case Disassembly: + case FlowCode: + case Library: + case Object: + case Unknown: + return Invalid; + } + + case Library: + return Invalid; + + case Microbe: + switch (to) + { + case AssemblyAbsolute: + return Microbe_AssemblyAbsolute; + case Pic: + return Microbe_PIC; + case Program: + return Microbe_Program; + + case AssemblyRelocatable: + case C: + case Disassembly: + case FlowCode: + case Library: + case Microbe: + case Object: + case Unknown: + return Invalid; + } + + case Object: + switch (to) + { + case Disassembly: + return Object_Disassembly; + case Library: + return Object_Library; + case Pic: + return Object_PIC; + case Program: + return Object_Program; + + case AssemblyAbsolute: + case AssemblyRelocatable: + case C: + case FlowCode: + case Microbe: + case Object: + case Unknown: + return Invalid; + } + + case Pic: + return Invalid; + + case Program: + switch (to) + { + case Disassembly: + return Program_Disassembly; + case Pic: + return Program_PIC; + + case AssemblyAbsolute: + case AssemblyRelocatable: + case C: + case FlowCode: + case Library: + case Microbe: + case Object: + case Program: + case Unknown: + return Invalid; + } + + case Unknown: + return Invalid; + } + + return Invalid; +} + + +ProcessOptions::ProcessPath::MediaType ProcessOptions::ProcessPath::from( Path path ) +{ + switch (path) + { + case ProcessPath::AssemblyAbsolute_PIC: + case ProcessPath::AssemblyAbsolute_Program: + return AssemblyAbsolute; + + case ProcessPath::AssemblyRelocatable_Library: + case ProcessPath::AssemblyRelocatable_Object: + case ProcessPath::AssemblyRelocatable_PIC: + case ProcessPath::AssemblyRelocatable_Program: + return AssemblyRelocatable; + + case ProcessPath::C_AssemblyRelocatable: + case ProcessPath::C_Library: + case ProcessPath::C_Object: + case ProcessPath::C_PIC: + case ProcessPath::C_Program: + return C; + + case ProcessPath::FlowCode_AssemblyAbsolute: + case ProcessPath::FlowCode_Microbe: + case ProcessPath::FlowCode_PIC: + case ProcessPath::FlowCode_Program: + return FlowCode; + + case ProcessPath::Microbe_AssemblyAbsolute: + case ProcessPath::Microbe_PIC: + case ProcessPath::Microbe_Program: + return Microbe; + + case ProcessPath::Object_Disassembly: + case ProcessPath::Object_Library: + case ProcessPath::Object_PIC: + case ProcessPath::Object_Program: + return Object; + + case ProcessPath::PIC_AssemblyAbsolute: + return Pic; + + case ProcessPath::Program_Disassembly: + case ProcessPath::Program_PIC: + return Program; + + case ProcessPath::Invalid: + case ProcessPath::None: + return Unknown; + } + + return Unknown; +} + + +ProcessOptions::ProcessPath::MediaType ProcessOptions::ProcessPath::to( Path path ) +{ + switch (path) + { + case ProcessPath::FlowCode_AssemblyAbsolute: + case ProcessPath::Microbe_AssemblyAbsolute: + case ProcessPath::PIC_AssemblyAbsolute: + return AssemblyAbsolute; + + case ProcessPath::C_AssemblyRelocatable: + return AssemblyRelocatable; + + case ProcessPath::Object_Disassembly: + case ProcessPath::Program_Disassembly: + return Disassembly; + + case ProcessPath::AssemblyRelocatable_Library: + case ProcessPath::C_Library: + case ProcessPath::Object_Library: + return Library; + + case ProcessPath::FlowCode_Microbe: + return Microbe; + + case ProcessPath::AssemblyRelocatable_Object: + case ProcessPath::C_Object: + return Object; + + case ProcessPath::AssemblyAbsolute_PIC: + case ProcessPath::AssemblyRelocatable_PIC: + case ProcessPath::C_PIC: + case ProcessPath::FlowCode_PIC: + case ProcessPath::Microbe_PIC: + case ProcessPath::Object_PIC: + case ProcessPath::Program_PIC: + return Pic; + + case ProcessPath::AssemblyAbsolute_Program: + case ProcessPath::AssemblyRelocatable_Program: + case ProcessPath::C_Program: + case ProcessPath::FlowCode_Program: + case ProcessPath::Microbe_Program: + case ProcessPath::Object_Program: + return Program; + + case ProcessPath::Invalid: + case ProcessPath::None: + return Unknown; + } + + return Unknown; +} +//END class ProcessOptions + + +#include "language.moc" diff --git a/src/languages/language.h b/src/languages/language.h new file mode 100644 index 0000000..68ef187 --- /dev/null +++ b/src/languages/language.h @@ -0,0 +1,268 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef LANGUAGE_H +#define LANGUAGE_H + +#include <qobject.h> +#include <qstringlist.h> + +class FlowCodeDocument; +class KTechlab; +class LogView; +class MessageInfo; +class MicroSettings; +class OutputMethodInfo; +class ProcessChain; +class ProcessOptions; +class TextDocument; +class QProcess; + +typedef QValueList<ProcessOptions> ProcessOptionsList; + +class ProcessOptionsSpecial +{ + public: + ProcessOptionsSpecial(); + + bool b_addToProject; + bool b_forceList; + QString m_picID; + FlowCodeDocument * p_flowCodeDocument; + + // Linking + QString m_hexFormat; + bool m_bOutputMapFile; + QString m_libraryDir; + QString m_linkerScript; + QStringList m_linkLibraries; + QString m_linkOther; + + // Programming + QString m_port; + QString m_program; +}; + + +class ProcessOptionsHelper : public QObject +{ + Q_OBJECT +#define protected public + signals: +#undef protected + void textOutputtedTo( TextDocument * outputtedTo ); +}; + + +class ProcessOptions : public ProcessOptionsSpecial +{ + public: + ProcessOptions(); + ProcessOptions( OutputMethodInfo info ); + + class ProcessPath { public: + enum MediaType + { + AssemblyAbsolute, + AssemblyRelocatable, + C, + Disassembly, + FlowCode, + Library, + Microbe, + Object, + Pic, + Program, + + Unknown // Used for guessing the media type + }; + + enum Path // From_To // processor that will be invoked first + { + AssemblyAbsolute_PIC, // gpasm (indirect) + AssemblyAbsolute_Program, // gpasm (direct) + + AssemblyRelocatable_Library, // gpasm (indirect) + AssemblyRelocatable_Object, // gpasm (direct) + AssemblyRelocatable_PIC, // gpasm (indirect) + AssemblyRelocatable_Program, // gpasm (indirect) + + C_AssemblyRelocatable, // sdcc (direct) + C_Library, // sdcc (indirect) + C_Object, // sdcc (indirect) + C_PIC, // sdcc (indirect) + C_Program, // sdcc (indirect) + + FlowCode_AssemblyAbsolute, // flowcode (indirect) + FlowCode_Microbe, // flowcode (direct) + FlowCode_PIC, // flowcode (indirect) + FlowCode_Program, // flowcode (indirect) + + Microbe_AssemblyAbsolute, // microbe (direct) + Microbe_PIC, // microbe (indirect) + Microbe_Program, // microbe (indirect) + + Object_Disassembly, // gpdasm (direct) + Object_Library, // gplib (direct) + Object_PIC, // gplink (indirect) + Object_Program, // gplink (direct) + + PIC_AssemblyAbsolute, // download from pic (direct) + + Program_Disassembly, // gpdasm (direct) + Program_PIC, // upload to pic (direct) + + Invalid, // From and to types are incompatible + None // From and to types are the same + }; + + static Path path( MediaType from, MediaType to ); + static MediaType from( Path path ); + static MediaType to( Path path ); + }; + + class Method + { + public: enum type + { + Forget, // Don't do anything after processing successfully + LoadAsNew, // Load the output as a new file + Load // Load the output file + }; + }; + + /** + * Tries to guess the media type from the url (and possible the contents + * of the file as well). + */ + static ProcessPath::MediaType guessMediaType( const QString & url ); + /** + * The *final* target file (not any intermediatary ones) + */ + QString targetFile() const { return m_targetFile; } + /** + * This sets the final target file, as well as the initial intermediatary one + */ + void setTargetFile( const QString &file ); + + void setIntermediaryOutput( const QString &file ) { m_intermediaryFile = file; } + QString intermediaryOutput() const { return m_intermediaryFile; } + + void setInputFiles( const QStringList & files ) { m_inputFiles = files; } + QStringList inputFiles() const { return m_inputFiles; } + + void setMethod( Method::type method ) { m_method = method; } + Method::type method() const { return m_method; } + + void setProcessPath( ProcessPath::Path path ) { m_processPath = path; } + ProcessPath::Path processPath() const { return m_processPath; } + + /** + * If the output is text; If the user has selected (in config options) + * ReuseSameViewForOutput, then the given TextDocument will have its + * text set to the output if the TextDocument is not modified and has + * an empty url. Otherwise a new TextDocument will be created. Either + * way, once the the processing has finished, a signal will be emitted + * to the given receiver passing a TextDocument * as an argument. This + * is not to be confused with setTextOutputtedTo, which is called once + * the processing has finished, and will call-back to the slot given. + */ + void setTextOutputTarget( TextDocument * target, QObject * receiver, const char * slot ); + /** + * @see setTextOutputTarget + */ + TextDocument * textOutputTarget() const { return m_pTextOutputTarget; } + /** + * @see setTextOuputTarget + */ + void setTextOutputtedTo( TextDocument * outputtedTo ); + + protected: + TextDocument * m_pTextOutputTarget; + ProcessOptionsHelper * m_pHelper; + bool b_targetFileSet; + QStringList m_inputFiles; + QString m_targetFile; + QString m_intermediaryFile; + Method::type m_method; + ProcessPath::Path m_processPath; +}; + + +/** +@author Daniel Clarke +@author David Saxton +*/ +class Language : public QObject +{ + Q_OBJECT + public: + Language( ProcessChain *processChain, KTechlab *parent, const QString &name ); + ~Language(); + + /** + * Compile / assemble / dissassembly / whatever the given input. + * @returns true if processing was started succesfully (this is different to finishing successfuly). + */ + virtual void processInput( ProcessOptions options ) = 0; + /** + * Return the ProcessOptions object current state + */ + ProcessOptions processOptions() const { return m_processOptions; } + /** + * Return the output path from the given input path. Will return None + * if we've done processing. + */ + virtual ProcessOptions::ProcessPath::Path outputPath( ProcessOptions::ProcessPath::Path inputPath ) const = 0; + + signals: + /** + * Emitted when the processing was successful. + * @param language Pointer to this class + */ + void processSucceeded( Language *language ); + /** + * Emitted when the processing failed. + * @param language Pointer to this class + */ + void processFailed( Language *language ); + + protected: + /** + * Examines the string for the line number if applicable, and creates a new + * MessageInfo for it. + */ + virtual MessageInfo extractMessageInfo( const QString &text ); + + /** + * Reset the error count + */ + void reset(); + void outputMessage( const QString &message ); + void outputWarning( const QString &message ); + void outputError( const QString &error ); + void finish( bool successful ); + + int m_errorCount; + KTechlab *p_ktechlab; + ProcessOptions m_processOptions; + ProcessChain *p_processChain; + + /** + * A message appropriate to the language's success after compilation or similar. + */ + QString m_successfulMessage; + /** + * A message appropriate to the language's failure after compilation or similar. + */ + QString m_failedMessage; +}; + +#endif diff --git a/src/languages/languagemanager.cpp b/src/languages/languagemanager.cpp new file mode 100644 index 0000000..a6dddd8 --- /dev/null +++ b/src/languages/languagemanager.cpp @@ -0,0 +1,108 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "docmanager.h" +#include "languagemanager.h" +#include "logview.h" +#include "ktechlab.h" +#include "ktempfile.h" +#include "src/core/ktlconfig.h" +#include "outputmethoddlg.h" +#include "processchain.h" +#include "projectmanager.h" + +#include "microbe.h" +#include "gpasm.h" +#include "gpdasm.h" + +#include <kdockwidget.h> +#include <kiconloader.h> +#include <klocale.h> +#include <qwhatsthis.h> + +#include <assert.h> + + +LanguageManager * LanguageManager::m_pSelf = 0l; + + +LanguageManager * LanguageManager::self( KateMDI::ToolView * parent, KTechlab * ktl ) +{ + if (!m_pSelf) + { + assert(parent); + assert(ktl); + m_pSelf = new LanguageManager( parent, ktl ); + } + return m_pSelf; +} + + +LanguageManager::LanguageManager( KateMDI::ToolView * parent, KTechlab * ktl ) + : QObject((QObject*)ktl) +{ + p_ktechlab = ktl; + m_logView = new LogView( parent, "LanguageManager LogView"); + + QWhatsThis::add( m_logView, i18n("These messages show the output of language-related functionality such as compiling and assembling.<br><br>For error messages, clicking on the line will automatically open up the file at the position of the error.") ); + connect( m_logView, SIGNAL(paraClicked(const QString&, MessageInfo )), this, SLOT(slotParaClicked(const QString&, MessageInfo )) ); + reset(); +} + + +LanguageManager::~LanguageManager() +{ +} + + +void LanguageManager::reset() +{ + m_logView->clear(); +} + + +ProcessChain * LanguageManager::compile( ProcessOptions options ) +{ + if ( KTLConfig::raiseMessagesLog() ) + p_ktechlab->showToolView( p_ktechlab->toolView( toolViewIdentifier() ) ); + + return new ProcessChain( options, p_ktechlab ); +} + + +ProcessListChain * LanguageManager::compile( ProcessOptionsList pol ) +{ + if ( KTLConfig::raiseMessagesLog() ) + p_ktechlab->showToolView( p_ktechlab->toolView( toolViewIdentifier() ) ); + + return new ProcessListChain( pol, p_ktechlab ); +} + + +void LanguageManager::slotError( const QString &error, MessageInfo messageInfo ) +{ + m_logView->addOutput( error, LogView::ot_error, messageInfo ); +} +void LanguageManager::slotWarning( const QString &error, MessageInfo messageInfo ) +{ + m_logView->addOutput( error, LogView::ot_warning, messageInfo ); +} +void LanguageManager::slotMessage( const QString &error, MessageInfo messageInfo ) +{ + m_logView->addOutput( error, LogView::ot_message, messageInfo ); +} + +void LanguageManager::slotParaClicked( const QString& message, MessageInfo messageInfo ) +{ + Q_UNUSED(message); + DocManager::self()->gotoTextLine( messageInfo.fileURL(), messageInfo.fileLine() ); +} + +#include "languagemanager.moc" diff --git a/src/languages/languagemanager.h b/src/languages/languagemanager.h new file mode 100644 index 0000000..c5bda98 --- /dev/null +++ b/src/languages/languagemanager.h @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef LANGUAGEMANAGER_H +#define LANGUAGEMANAGER_H + +#include <qobject.h> +#include <qvaluelist.h> + +#include "language.h" + +class FlowCode; +class Gpasm; +class Gpdasm; +class KTechlab; +class Language; +class LanguageManager; +class LogView; +class MessageInfo; +class Microbe; +class ProcessChain; +class ProcessListChain; +class ProcessOptions; +namespace KateMDI { class ToolView; } + +/** +@author David Saxton +*/ +class LanguageManager : public QObject +{ + Q_OBJECT + public: + static LanguageManager * self( KateMDI::ToolView * parent = 0l, KTechlab * ktl = 0l ); + static QString toolViewIdentifier() { return "LanguageManager"; } + ~LanguageManager(); + + /** + * Call to compile a file of one type all the way to another type, this can + * also be used in reverse to disassemble code. Connect to the returned + * ProcessChain for notification of compile success / failure + * @return Pointer to the ProcessChain used to compile + */ + ProcessChain * compile( ProcessOptions options ); + ProcessListChain * compile( ProcessOptionsList pol ); + /** + * @return Pointer to the LogView that displays the output messages + */ + LogView * logView() const { return m_logView; } + /** + * Clear any errors and clear the log view + */ + void reset(); + + public slots: + /** + * Called when the user clicks on any text in the LogView + */ + void slotParaClicked( const QString& message, MessageInfo messageInfo ); + /** + * Called by languages to report an error message + * @param error Error message to report + */ + void slotError( const QString &error, MessageInfo messageInfo ); + /** + * Called by languages to report a warning message + * @param warning Warning message to report + */ + void slotWarning( const QString &warning, MessageInfo messageInfo ); + /** + * Called by languages to report a general message + * @param message General message to report + */ + void slotMessage( const QString &message, MessageInfo messageInfo ); + + protected: + LanguageManager( KateMDI::ToolView * parent, KTechlab * ktl ); + + private: + LogView * m_logView; + static LanguageManager * m_pSelf; + KTechlab * p_ktechlab; +}; + +#endif diff --git a/src/languages/microbe.cpp b/src/languages/microbe.cpp new file mode 100644 index 0000000..628b3c1 --- /dev/null +++ b/src/languages/microbe.cpp @@ -0,0 +1,136 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "contexthelp.h" +#include "docmanager.h" +#include "logview.h" +#include "microbe.h" +#include "languagemanager.h" + +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> + +#include <qfile.h> +#include <kprocess.h> + +Microbe::Microbe( ProcessChain *processChain, KTechlab *parent ) + : ExternalLanguage( processChain, parent, "Microbe" ) +{ + m_failedMessage = i18n("*** Compilation failed ***"); + m_successfulMessage = i18n("*** Compilation successful ***"); + + // Setup error messages list + QFile file( locate("appdata",i18n("error_messages_en_gb")) ); + if ( file.open( IO_ReadOnly ) ) + { + QTextStream stream( &file ); + QString line; + while ( !stream.atEnd() ) + { + line = stream.readLine(); // line of text excluding '\n' + if ( !line.isEmpty() ) + { + bool ok; + const int pos = line.left( line.find("#") ).toInt(&ok); + if (ok) { + m_errorMessages[pos] = line.right(line.length()-line.find("#")); + } else { + kdError() << k_funcinfo << "Error parsing Microbe error-message file"<<endl; + } + } + } + file.close(); + } +} + +Microbe::~Microbe() +{ +} + + +void Microbe::processInput( ProcessOptions options ) +{ + resetLanguageProcess(); + m_processOptions = options; + + *m_languageProcess << ("microbe"); + + // Input Asm file + *m_languageProcess << ( options.inputFiles().first() ); + + // Output filename + *m_languageProcess << ( options.intermediaryOutput() ); + + *m_languageProcess << ("--show-source"); + + if ( !start() ) + { + KMessageBox::sorry( LanguageManager::self()->logView(), i18n("Assembly failed. Please check you have KTechlab installed properly (\"microbe\" could not be started).") ); + processInitFailed(); + return; + } +} + + +bool Microbe::isError( const QString &message ) const +{ + return message.contains( "Error", false ); +} + +bool Microbe::isWarning( const QString &message ) const +{ + return message.contains( "Warning", false ); +} + + +ProcessOptions::ProcessPath::Path Microbe::outputPath( ProcessOptions::ProcessPath::Path inputPath ) const +{ + switch (inputPath) + { + case ProcessOptions::ProcessPath::Microbe_AssemblyAbsolute: + return ProcessOptions::ProcessPath::None; + + case ProcessOptions::ProcessPath::Microbe_PIC: + return ProcessOptions::ProcessPath::AssemblyAbsolute_PIC; + + case ProcessOptions::ProcessPath::Microbe_Program: + return ProcessOptions::ProcessPath::AssemblyAbsolute_Program; + + case ProcessOptions::ProcessPath::AssemblyAbsolute_PIC: + case ProcessOptions::ProcessPath::AssemblyAbsolute_Program: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Library: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Object: + case ProcessOptions::ProcessPath::AssemblyRelocatable_PIC: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Program: + case ProcessOptions::ProcessPath::C_AssemblyRelocatable: + case ProcessOptions::ProcessPath::C_Library: + case ProcessOptions::ProcessPath::C_Object: + case ProcessOptions::ProcessPath::C_PIC: + case ProcessOptions::ProcessPath::C_Program: + case ProcessOptions::ProcessPath::FlowCode_AssemblyAbsolute: + case ProcessOptions::ProcessPath::FlowCode_Microbe: + case ProcessOptions::ProcessPath::FlowCode_PIC: + case ProcessOptions::ProcessPath::FlowCode_Program: + case ProcessOptions::ProcessPath::Object_Disassembly: + case ProcessOptions::ProcessPath::Object_Library: + case ProcessOptions::ProcessPath::Object_PIC: + case ProcessOptions::ProcessPath::Object_Program: + case ProcessOptions::ProcessPath::PIC_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Program_Disassembly: + case ProcessOptions::ProcessPath::Program_PIC: + case ProcessOptions::ProcessPath::Invalid: + case ProcessOptions::ProcessPath::None: + return ProcessOptions::ProcessPath::Invalid; + } + + return ProcessOptions::ProcessPath::Invalid; +} diff --git a/src/languages/microbe.h b/src/languages/microbe.h new file mode 100644 index 0000000..568db4b --- /dev/null +++ b/src/languages/microbe.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef MICROBE_H +#define MICROBE_H + +#include "externallanguage.h" + +#include <qmap.h> + +typedef QMap< int, QString > ErrorMap; + +/** +@author Daniel Clarke +@author David Saxton +*/ +class Microbe : public ExternalLanguage +{ +public: + Microbe( ProcessChain *processChain, KTechlab *parent ); + ~Microbe(); + + virtual void processInput( ProcessOptions options ); + virtual ProcessOptions::ProcessPath::Path outputPath( ProcessOptions::ProcessPath::Path inputPath ) const; + +protected: + virtual bool isError( const QString &message ) const; + virtual bool isWarning( const QString &message ) const; + + ErrorMap m_errorMessages; +}; + +#endif diff --git a/src/languages/picprogrammer.cpp b/src/languages/picprogrammer.cpp new file mode 100644 index 0000000..6f5e76f --- /dev/null +++ b/src/languages/picprogrammer.cpp @@ -0,0 +1,456 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "languagemanager.h" +#include "picprogrammer.h" +#include "src/core/ktlconfig.h" + +#include <kapplication.h> +#include <kconfig.h> +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> + +#include <qapplication.h> +#include <qfile.h> +#include <kprocess.h> +#include <qregexp.h> +#include <qtextstream.h> +#include <qdatetime.h> + +#include <stdio.h> + +//BEGIN class ProgrammerConfig +ProgrammerConfig::ProgrammerConfig() +{ +} + + +void ProgrammerConfig::reset() +{ + initCommand = QString::null; + readCommand = QString::null; + writeCommand = QString::null; + verifyCommand = QString::null; + blankCheckCommand = QString::null; + eraseCommand = QString::null; +} +//END class ProgrammerConfig + + + +//BEGIN class PicProgrammerSettings +bool PicProgrammerSettings::m_bDoneStaticConfigsInit = false; +ProgrammerConfigMap PicProgrammerSettings::m_staticConfigs = ProgrammerConfigMap(); + + +PicProgrammerSettings::PicProgrammerSettings() +{ + if ( !m_bDoneStaticConfigsInit ) + initStaticConfigs(); +} + + +void PicProgrammerSettings::initStaticConfigs() +{ + m_bDoneStaticConfigsInit = true; + ProgrammerConfig config; + + config.description = i18n("Supported programmers: %1").arg("JuPic, PICStart Plus, Warp-13"); + config.description += i18n("<br>Interface: Serial Port"); + config.initCommand = ""; + config.readCommand = "picp %port %device -rp %file"; + config.writeCommand = "picp %port %device -wp %file"; + config.verifyCommand = ""; + config.blankCheckCommand = "picp %port %device -b"; + config.eraseCommand = "picp %port %device -e"; +// config.executable = "picp"; + m_staticConfigs[ "PICP" ] = config; + + + config.description = i18n("Supported programmers: %1").arg("Epic Plus"); + config.description += i18n("<br>Interface: Parallel Port"); + config.initCommand = "odyssey init"; + config.readCommand = "odyssey %device read %file"; + config.writeCommand = "odyssey %device write %file"; + config.verifyCommand = "odyssey %device verify %file"; + config.blankCheckCommand = "odyssey %device blankcheck"; + config.eraseCommand = "odyssey %device erase"; +// config.executable = "odyssey"; + m_staticConfigs[ "Odyssey" ] = config; + + + config.description = i18n("Supported programmers: %1").arg("JDM PIC-Programmer 2, PIC-PG2C"); + config.description += i18n("<br>Interface: Serial Port"); + config.initCommand = ""; + config.readCommand = "picprog --output %file --pic %port"; + config.writeCommand = "picprog --burn --input %file --pic %port --device %device"; + config.verifyCommand = ""; + config.blankCheckCommand = ""; + config.eraseCommand = "picprog --erase --pic %device"; + m_staticConfigs[ "PICProg" ] = config; + + + config.description = i18n("Supported programmers: %1").arg("Epic Plus"); + config.description += i18n("<br>Interface: Parallel Port"); + config.initCommand = ""; + config.readCommand = "dump84 --dump-all --output=%file"; + config.writeCommand = "prog84 --intel16=%file"; + config.verifyCommand = ""; + config.blankCheckCommand = ""; + config.eraseCommand = "prog84 --clear"; + m_staticConfigs[ "prog84" ] = config; + + + config.description = i18n("Supported programmers: %1").arg("Kit 149, Kit 150"); + config.description += i18n("<br>Interface: USB Port"); + config.initCommand = ""; + config.readCommand = "pp -d %device -r %file"; + config.writeCommand = "pp -d %device -w %file"; + config.verifyCommand = "pp -d %device -v %file"; + config.blankCheckCommand = ""; + config.eraseCommand = "pp -d %device -e"; + m_staticConfigs[ "PP" ] = config; + + + config.description = i18n("Supported programmers: %1").arg("Wisp628"); + config.description += i18n("<br>Interface: Serial Port"); + config.initCommand = ""; + config.readCommand = "xwisp ID %device PORT %device DUMP"; + config.writeCommand = "xwisp ID %device PORT %device WRITE %file"; + config.verifyCommand = ""; + config.blankCheckCommand = ""; + config.eraseCommand = "xwisp ID %device PORT %device ERASE"; + m_staticConfigs[ "XWisp" ] = config; + + +#if 0 + config.description = i18n("Supported programmers: %1").arg("Epic Plus, JDM PIC-Programmer 2, PICCOLO, PICCOLO Grande, Trivial HVP Programmer"); + config.description += i18n("<br>Interface: Serial Port and Parallel Port"); + config.initCommand = ""; + config.readCommand = ""; + config.writeCommand = ""; + config.verifyCommand = ""; + config.blankCheckCommand = ""; + config.eraseCommand = ""; + config.executable = "pkp"; + m_staticConfigs[ "PiKdev" ] = config; + config.executable = ""; + + + config.description = i18n("Supported programmers: %1").arg("Trivial LVP programmer, Trivial HVP Programmer"); + config.description += i18n("<br>Interface: Parallel Port"); + config.initCommand = ""; + config.readCommand = ""; + config.writeCommand = ""; + config.verifyCommand = ""; + config.blankCheckCommand = ""; + config.eraseCommand = ""; + m_staticConfigs[ "PicPrg2" ] = config; + + + config.description = i18n("Supported programmers: %1").arg("El Cheapo"); + config.description += i18n("<br>Interface: Parallel Port"); + config.initCommand = ""; + config.readCommand = ""; + config.writeCommand = ""; + config.verifyCommand = ""; + config.blankCheckCommand = ""; + config.eraseCommand = ""; + m_staticConfigs[ "PP06" ] = config; + + + config.description = i18n("Supported programmers: %1").arg("NOPPP"); + config.description += i18n("<br>Interface: Parallel Port"); + config.initCommand = ""; + config.readCommand = ""; + config.writeCommand = ""; + config.verifyCommand = ""; + config.blankCheckCommand = ""; + config.eraseCommand = ""; + m_staticConfigs[ "NOPPP" ] = config; + + + config.description = i18n("Supported programmers: %1").arg("SNOPPP"); + config.description += i18n("<br>Interface: Parallel Port"); + config.initCommand = ""; + config.readCommand = ""; + config.writeCommand = ""; + config.verifyCommand = ""; + config.blankCheckCommand = ""; + config.eraseCommand = ""; + m_staticConfigs[ "SNOPPP" ] = config; +#endif +} + + +void PicProgrammerSettings::load( KConfig * config ) +{ + QStringList oldCustomProgrammers = config->groupList().grep("CustomProgrammer_"); + QStringList::iterator ocpEnd = oldCustomProgrammers.end(); + for ( QStringList::iterator it = oldCustomProgrammers.begin(); it != ocpEnd; ++it ) + { + // The CustomProgrammer_ string we searched for might appear half way through... (don't want) + if ( (*it).startsWith("CustomProgrammer_") ) + { + config->setGroup(*it); + + ProgrammerConfig pc; + pc.initCommand = config->readEntry( "InitCommand" ); + pc.readCommand = config->readEntry( "ReadCommand" ); + pc.writeCommand = config->readEntry( "WriteCommand" ); + pc.verifyCommand = config->readEntry( "VerifyCommand" ); + pc.blankCheckCommand = config->readEntry( "BlankCheckCommand" ); + pc.eraseCommand = config->readEntry( "EraseCommand" ); + + QString name = config->readEntry( "Name" ); + m_customConfigs[name] = pc; + } + } +} + + +void PicProgrammerSettings::save( KConfig * config ) +{ + QStringList oldCustomProgrammers = config->groupList().grep("CustomProgrammer_"); + QStringList::iterator ocpEnd = oldCustomProgrammers.end(); + for ( QStringList::iterator it = oldCustomProgrammers.begin(); it != ocpEnd; ++it ) + { + // The CustomProgrammer_ string we searched for might appear half way through... (don't want) + if ( (*it).startsWith("CustomProgrammer_") ) + config->deleteGroup(*it); + } + + int at = 0; + ProgrammerConfigMap::iterator end = m_customConfigs.end(); + for ( ProgrammerConfigMap::iterator it = m_customConfigs.begin(); it != end; ++it ) + { + config->setGroup( QString("CustomProgrammer_%1").arg(at++) ); + + config->writeEntry( "Name", it.key() ); + config->writeEntry( "InitCommand", it.data().initCommand ); + config->writeEntry( "ReadCommand", it.data().readCommand ); + config->writeEntry( "WriteCommand", it.data().writeCommand ); + config->writeEntry( "VerifyCommand", it.data().verifyCommand ); + config->writeEntry( "BlankCheckCommand", it.data().blankCheckCommand ); + config->writeEntry( "EraseCommand", it.data().eraseCommand ); + } +} + + +ProgrammerConfig PicProgrammerSettings::config( const QString & name ) +{ + if ( name.isEmpty() ) + return ProgrammerConfig(); + + QString l = name.lower(); + + ProgrammerConfigMap::const_iterator end = m_customConfigs.end(); + for ( ProgrammerConfigMap::const_iterator it = m_customConfigs.begin(); it != end; ++it ) + { + if ( it.key().lower() == l ) + return *it; + } + + end = m_staticConfigs.end(); + for ( ProgrammerConfigMap::const_iterator it = m_staticConfigs.begin(); it != end; ++it ) + { + if ( it.key().lower() == l ) + return *it; + } + + return m_customConfigs[ name ]; +} + + +void PicProgrammerSettings::removeConfig( const QString & name ) +{ + if ( isPredefined( name ) ) + { + kdWarning() << k_funcinfo << "Cannot remove a predefined PIC programmer configuration." << endl; + return; + } + + QString l = name.lower(); + + ProgrammerConfigMap::iterator end = m_customConfigs.end(); + for ( ProgrammerConfigMap::iterator it = m_customConfigs.begin(); it != end; ++it ) + { + if ( it.key().lower() == l ) + { + m_customConfigs.remove( it ); + return; + } + } +} + + +void PicProgrammerSettings::saveConfig( const QString & name, const ProgrammerConfig & config ) +{ + if ( isPredefined( name ) ) + { + kdWarning() << k_funcinfo << "Cannot save to a predefined PIC programmer configuration." << endl; + return; + } + + QString l = name.lower(); + + ProgrammerConfigMap::iterator end = m_customConfigs.end(); + for ( ProgrammerConfigMap::iterator it = m_customConfigs.begin(); it != end; ++it ) + { + if ( it.key().lower() == l ) + { + *it = config; + return; + } + } + + m_customConfigs[ name ] = config; +} + + +QStringList PicProgrammerSettings::configNames( bool makeLowercase ) const +{ + if ( !makeLowercase ) + return m_customConfigs.keys() + m_staticConfigs.keys(); + + QStringList names; + + ProgrammerConfigMap::const_iterator end = m_customConfigs.end(); + for ( ProgrammerConfigMap::const_iterator it = m_customConfigs.begin(); it != end; ++it ) + names << it.key().lower(); + + end = m_staticConfigs.end(); + for ( ProgrammerConfigMap::const_iterator it = m_staticConfigs.begin(); it != end; ++it ) + names << it.key().lower(); + + return names; +} + + +bool PicProgrammerSettings::isPredefined( const QString & name ) const +{ + QString l = name.lower(); + + ProgrammerConfigMap::const_iterator end = m_staticConfigs.end(); + for ( ProgrammerConfigMap::const_iterator it = m_staticConfigs.begin(); it != end; ++it ) + { + if ( it.key().lower() == l ) + return true; + } + + return false; +} +//END class PicProgrammerSettings + + + +//BEGIN class PicProgrammer +PicProgrammer::PicProgrammer( ProcessChain *processChain, KTechlab * parent ) + : ExternalLanguage( processChain, parent, "PicProgrammer" ) +{ + m_successfulMessage = i18n("*** Programming successful ***"); + m_failedMessage = i18n("*** Programming failed ***"); +} + + +PicProgrammer::~PicProgrammer() +{ +} + + +void PicProgrammer::processInput( ProcessOptions options ) +{ + resetLanguageProcess(); + m_processOptions = options; + + PicProgrammerSettings settings; + settings.load( kapp->config() ); + + QString program = options.m_program; + if ( !settings.configNames( true ).contains( program.lower() ) ) + { + kdError() << k_funcinfo << "Invalid program" << endl; + finish( false ); + return; + } + + ProgrammerConfig config = settings.config( program ); + + QString command = config.writeCommand; + command.replace( "%port", options.m_port ); + command.replace( "%device", QString( options.m_picID ).remove("P") ); + command.replace( "%file", KProcess::quote( options.inputFiles().first() ) ); + + m_languageProcess->setUseShell( true ); + *m_languageProcess << command; + + if ( !start() ) + { +// KMessageBox::sorry( LanguageManager::self()->logView(), i18n("Could not program PIC.") ); + processInitFailed(); + return; + } +} + + +bool PicProgrammer::isError( const QString &message ) const +{ + return message.contains( "Error", false ); +} + + +bool PicProgrammer::isWarning( const QString &message ) const +{ + return message.contains( "Warning", false ); +} + + +ProcessOptions::ProcessPath::Path PicProgrammer::outputPath( ProcessOptions::ProcessPath::Path inputPath ) const +{ + switch (inputPath) + { + case ProcessOptions::ProcessPath::PIC_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Program_PIC: + return ProcessOptions::ProcessPath::None; + + case ProcessOptions::ProcessPath::AssemblyAbsolute_PIC: + case ProcessOptions::ProcessPath::AssemblyAbsolute_Program: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Library: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Object: + case ProcessOptions::ProcessPath::AssemblyRelocatable_PIC: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Program: + case ProcessOptions::ProcessPath::C_AssemblyRelocatable: + case ProcessOptions::ProcessPath::C_Library: + case ProcessOptions::ProcessPath::C_Object: + case ProcessOptions::ProcessPath::C_PIC: + case ProcessOptions::ProcessPath::C_Program: + case ProcessOptions::ProcessPath::FlowCode_AssemblyAbsolute: + case ProcessOptions::ProcessPath::FlowCode_Microbe: + case ProcessOptions::ProcessPath::FlowCode_PIC: + case ProcessOptions::ProcessPath::FlowCode_Program: + case ProcessOptions::ProcessPath::Microbe_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Microbe_PIC: + case ProcessOptions::ProcessPath::Microbe_Program: + case ProcessOptions::ProcessPath::Object_Disassembly: + case ProcessOptions::ProcessPath::Object_Library: + case ProcessOptions::ProcessPath::Object_PIC: + case ProcessOptions::ProcessPath::Object_Program: + case ProcessOptions::ProcessPath::Program_Disassembly: + case ProcessOptions::ProcessPath::Invalid: + case ProcessOptions::ProcessPath::None: + return ProcessOptions::ProcessPath::Invalid; + } + + return ProcessOptions::ProcessPath::Invalid; +} +//END class PicProgrammer + + diff --git a/src/languages/picprogrammer.h b/src/languages/picprogrammer.h new file mode 100644 index 0000000..580cf6b --- /dev/null +++ b/src/languages/picprogrammer.h @@ -0,0 +1,127 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PICPROGRAMMER_H +#define PICPROGRAMMER_H + +#include "externallanguage.h" + + +class KConfig; +class KProcess; + + +class ProgrammerConfig +{ + public: + ProgrammerConfig(); + + /** + * Clears the type and all commands. + */ + void reset(); + + QString initCommand; + QString readCommand; + QString writeCommand; + QString verifyCommand; + QString blankCheckCommand; + QString eraseCommand; + + QString description; + QString executable; // The name of the program executable +}; + +typedef QMap< QString, ProgrammerConfig > ProgrammerConfigMap; + + + +/** +This class provides access to the PIC Programmer configurations. Several are +predefinied; the rest can be read from and written to, and removed. Names are +case insensitive. + +Each programmer configuration is in the form of the ProgrammerConfig struct. + +@author David Saxton +*/ +class PicProgrammerSettings +{ + public: + PicProgrammerSettings(); + + /** + * Reads in custom ProgrammerConfigs from config. Any previously loaded + * configurations stored in this class will removed first. + */ + void load( KConfig * config ); + /** + * Saves the custom ProgrammConfigs to config. + */ + void save( KConfig * config ); + /** + * @return the ProgrammConfig for the programmer with the given name. If + * no such ProgrammerConfigs with the given name exist, then one will be + * created. The name is case insensitive (although the full case of the + * name will be stored if a new ProgrammerConfig is created). + */ + ProgrammerConfig config( const QString & name ); + /** + * Removes the config (if it is custom) with the give name. + */ + void removeConfig( const QString & name ); + /** + * Sets the ProgrammerConfig with the given name (or creates one if no + * such config exists). The name is case insensitive. + */ + void saveConfig( const QString & name, const ProgrammerConfig & config ); + /** + * @param makeLowercase whether the names should be converted to + * lowercase before returning. + * @return a list of names of the custom and predefined configs. + */ + QStringList configNames( bool makeLowercase ) const; + /** + * @return whether the given config is predefined. + */ + bool isPredefined( const QString & name ) const; + + protected: + /** + * Called when a PicProgrammerSettings object is first created. Does + * initialization of the predefined configs. + */ + void initStaticConfigs(); + + ProgrammerConfigMap m_customConfigs; + + static bool m_bDoneStaticConfigsInit; + static ProgrammerConfigMap m_staticConfigs; +}; + + +/** +@author David Saxton +*/ +class PicProgrammer : public ExternalLanguage +{ + public: + PicProgrammer( ProcessChain *processChain, KTechlab *parent ); + ~PicProgrammer(); + + virtual void processInput( ProcessOptions options ); + virtual ProcessOptions::ProcessPath::Path outputPath( ProcessOptions::ProcessPath::Path inputPath ) const; + + protected: + virtual bool isError( const QString &message ) const; + virtual bool isWarning( const QString &message ) const; +}; + +#endif diff --git a/src/languages/processchain.cpp b/src/languages/processchain.cpp new file mode 100644 index 0000000..e17c6ae --- /dev/null +++ b/src/languages/processchain.cpp @@ -0,0 +1,326 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "asmparser.h" +#include "docmanager.h" +#include "gplib.h" +#include "src/core/ktlconfig.h" +#include "language.h" +#include "languagemanager.h" +#include "logview.h" +#include "outputmethoddlg.h" +#include "processchain.h" +#include "projectmanager.h" +#include "textdocument.h" + +#include "flowcode.h" +#include "gpasm.h" +#include "gpdasm.h" +#include "gplink.h" +#include "microbe.h" +#include "picprogrammer.h" +#include "sdcc.h" + +#include <kdebug.h> +#include <klocale.h> +#include <ktempfile.h> +#include <qfile.h> +#include <qtimer.h> + + +//BEGIN class ProcessChain +ProcessChain::ProcessChain( ProcessOptions options, KTechlab * ktechlab, const char *name ) + : QObject( (QObject*)ktechlab, name) +{ + m_pKTechlab = ktechlab; + m_pFlowCode = 0l; + m_pGpasm = 0l; + m_pGpdasm = 0l; + m_pGplib = 0l; + m_pGplink = 0l; + m_pMicrobe = 0l; + m_pPicProgrammer = 0l; + m_pSDCC = 0l; + m_processOptions = options; + + QString target; + if ( ProcessOptions::ProcessPath::to( options.processPath() ) == ProcessOptions::ProcessPath::Pic ) + target = options.m_picID; + else + target = options.targetFile(); + + LanguageManager::self()->logView()->addOutput( i18n("Building: %1").arg( target ), LogView::ot_important ); + QTimer::singleShot( 0, this, SLOT(compile()) ); +} + + +ProcessChain::~ProcessChain() +{ + delete m_pFlowCode; + m_pFlowCode = 0l; + delete m_pGpasm; + m_pGpasm = 0l; + delete m_pGpdasm; + m_pGpdasm = 0l; + delete m_pGplib; + m_pGplib = 0l; + delete m_pGplink; + m_pGplink = 0l; + delete m_pMicrobe; + m_pMicrobe = 0l; + delete m_pPicProgrammer; + m_pPicProgrammer = 0l; + delete m_pSDCC; + m_pSDCC = 0l; +} + + +// void ProcessChain::compile( ProcessOptions * options ) +void ProcessChain::compile() +{ + // If the micro id in the options is empty, then attempt to get it from any + // open project (it might not be necessarily...but won't hurt if it isn't). + if ( m_processOptions.m_picID.isEmpty() ) + { + if ( ProjectInfo * projectInfo = ProjectManager::self()->currentProject() ) + { + ProjectItem * projectItem = projectInfo->findItem( m_processOptions.inputFiles().first() ); + if (projectItem) + m_processOptions.m_picID = projectItem->microID(); + } + } + + switch ( m_processOptions.processPath() ) + { +#define DIRECT_PROCESS( path, processor ) case ProcessOptions::ProcessPath::path: { processor()->processInput(m_processOptions); break; } +#define INDIRECT_PROCESS( path, processor, extension ) case ProcessOptions::ProcessPath::path: { KTempFile f( QString::null, extension ); f.close(); m_processOptions.setIntermediaryOutput( f.name() ); processor()->processInput(m_processOptions); break; } + + INDIRECT_PROCESS( AssemblyAbsolute_PIC, gpasm, ".hex" ) + DIRECT_PROCESS( AssemblyAbsolute_Program, gpasm ) + INDIRECT_PROCESS( AssemblyRelocatable_Library, gpasm, ".o" ) + DIRECT_PROCESS( AssemblyRelocatable_Object, gpasm ) + INDIRECT_PROCESS( AssemblyRelocatable_PIC, gpasm, ".o" ) + INDIRECT_PROCESS( AssemblyRelocatable_Program, gpasm, ".o" ) + DIRECT_PROCESS( C_AssemblyRelocatable, sdcc ) + INDIRECT_PROCESS( C_Library, sdcc, ".asm" ) + INDIRECT_PROCESS( C_Object, sdcc, ".asm" ) + INDIRECT_PROCESS( C_PIC, sdcc, ".asm" ) + INDIRECT_PROCESS( C_Program, sdcc, ".asm" ) + INDIRECT_PROCESS( FlowCode_AssemblyAbsolute, flowCode, ".microbe" ) + DIRECT_PROCESS( FlowCode_Microbe, flowCode ) + INDIRECT_PROCESS( FlowCode_PIC, flowCode, ".microbe" ) + INDIRECT_PROCESS( FlowCode_Program, flowCode, ".microbe" ) + DIRECT_PROCESS( Microbe_AssemblyAbsolute, microbe ) + INDIRECT_PROCESS( Microbe_PIC, microbe, ".asm" ) + INDIRECT_PROCESS( Microbe_Program, microbe, ".asm" ) + DIRECT_PROCESS( Object_Disassembly, gpdasm ) + DIRECT_PROCESS( Object_Library, gplib ) + INDIRECT_PROCESS( Object_PIC, gplink, ".lib" ) + DIRECT_PROCESS( Object_Program, gplink ) + DIRECT_PROCESS( PIC_AssemblyAbsolute, picProgrammer ) + DIRECT_PROCESS( Program_Disassembly, gpdasm ) + DIRECT_PROCESS( Program_PIC, picProgrammer ) +#undef DIRECT_PROCESS +#undef INDIRECT_PROCESS + + case ProcessOptions::ProcessPath::Invalid: + kdWarning() << k_funcinfo << "Process path is invalid" << endl; + + case ProcessOptions::ProcessPath::None: + kdWarning() << k_funcinfo << "Nothing to do" << endl; + break; + } +} + + +void ProcessChain::slotFinishedCompile(Language *language) +{ + ProcessOptions options = language->processOptions(); + + if ( options.b_addToProject && ProjectManager::self()->currentProject() ) + ProjectManager::self()->currentProject()->addFile( KURL(options.targetFile()) ); + + ProcessOptions::ProcessPath::MediaType typeTo = ProcessOptions::ProcessPath::to( m_processOptions.processPath() ); + + TextDocument * editor = 0l; + if ( KTLConfig::reuseSameViewForOutput() ) + { + editor = options.textOutputTarget(); + if ( editor && (!editor->url().isEmpty() || editor->isModified()) ) + editor = 0l; + } + + switch (typeTo) + { + case ProcessOptions::ProcessPath::AssemblyAbsolute: + case ProcessOptions::ProcessPath::AssemblyRelocatable: + case ProcessOptions::ProcessPath::C: + case ProcessOptions::ProcessPath::Disassembly: + case ProcessOptions::ProcessPath::Library: + case ProcessOptions::ProcessPath::Microbe: + case ProcessOptions::ProcessPath::Object: + case ProcessOptions::ProcessPath::Program: + { + switch ( options.method() ) + { + case ProcessOptions::Method::LoadAsNew: + { + if ( !editor ) + editor = DocManager::self()->createTextDocument(); + + if ( !editor ) + break; + + QString text; + QFile f( options.targetFile() ); + if ( !f.open( IO_ReadOnly ) ) + { + editor->deleteLater(); + editor = 0l; + break; + } + + QTextStream stream(&f); + + while ( !stream.atEnd() ) + text += stream.readLine()+'\n'; + + f.close(); + + editor->setText( text, true ); + break; + } + + case ProcessOptions::Method::Load: + { + editor = dynamic_cast<TextDocument*>( DocManager::self()->openURL(options.targetFile()) ); + break; + } + + case ProcessOptions::Method::Forget: + break; + } + } + + case ProcessOptions::ProcessPath::FlowCode: + case ProcessOptions::ProcessPath::Pic: + case ProcessOptions::ProcessPath::Unknown: + break; + } + + + if (editor) + { + switch (typeTo) + { + case ProcessOptions::ProcessPath::AssemblyAbsolute: + case ProcessOptions::ProcessPath::AssemblyRelocatable: + { + if ( KTLConfig::autoFormatMBOutput() ) + editor->formatAssembly(); + editor->slotInitLanguage( TextDocument::ct_asm ); + break; + } + + case ProcessOptions::ProcessPath::C: + editor->slotInitLanguage( TextDocument::ct_c ); + break; + + case ProcessOptions::ProcessPath::Disassembly: + break; + + case ProcessOptions::ProcessPath::Library: + case ProcessOptions::ProcessPath::Object: + case ProcessOptions::ProcessPath::Program: + editor->slotInitLanguage( TextDocument::ct_hex ); + break; + + case ProcessOptions::ProcessPath::Microbe: + editor->slotInitLanguage( TextDocument::ct_microbe ); + break; + + case ProcessOptions::ProcessPath::FlowCode: + case ProcessOptions::ProcessPath::Pic: + case ProcessOptions::ProcessPath::Unknown: + break; + } + + DocManager::self()->giveDocumentFocus( editor ); + } + + options.setTextOutputtedTo( editor ); + + emit successful(options); + emit successful(); +} + +#define LanguageFunction(a,b,c) \ +a * ProcessChain::b( ) \ +{ \ + if ( !c ) \ + { \ + c = new a( this, m_pKTechlab ); \ + connect( c, SIGNAL(processSucceeded(Language* )), this, SLOT(slotFinishedCompile(Language* )) ); \ + connect( c, SIGNAL(processFailed(Language* )), this, SIGNAL(failed()) ); \ + } \ + return c; \ +} + +LanguageFunction( FlowCode, flowCode, m_pFlowCode ) +LanguageFunction( Gpasm, gpasm, m_pGpasm ) +LanguageFunction( Gpdasm, gpdasm, m_pGpdasm ) +LanguageFunction( Gplib, gplib, m_pGplib ) +LanguageFunction( Gplink, gplink, m_pGplink ) +LanguageFunction( Microbe, microbe, m_pMicrobe ) +LanguageFunction( PicProgrammer, picProgrammer, m_pPicProgrammer ) +LanguageFunction( SDCC, sdcc, m_pSDCC ) +//END class ProcessChain + + + +//BEGIN class ProcessListChain +ProcessListChain::ProcessListChain( ProcessOptionsList pol, KTechlab * parent, const char * name ) + : QObject( (QObject*)parent, name ) +{ + m_processOptionsList = pol; + m_pKTechlab = parent; + + // Start us off... + slotProcessChainSuccessful(); +} + + +void ProcessListChain::slotProcessChainSuccessful() +{ + if ( m_processOptionsList.isEmpty() ) + { + emit successful(); + return; + } + + ProcessOptionsList::iterator it = m_processOptionsList.begin(); + ProcessOptions po = *it; + m_processOptionsList.remove(it); + + ProcessChain * pc = LanguageManager::self()->compile(po); + + connect( pc, SIGNAL(successful()), this, SLOT(slotProcessChainSuccessful()) ); + connect( pc, SIGNAL(failed()), this, SLOT(slotProcessChainFailed()) ); +} + + +void ProcessListChain::slotProcessChainFailed() +{ + emit failed(); +} +//END class ProcessListChain + + +#include "processchain.moc" diff --git a/src/languages/processchain.h b/src/languages/processchain.h new file mode 100644 index 0000000..90b871e --- /dev/null +++ b/src/languages/processchain.h @@ -0,0 +1,127 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PROCESSCHAIN_H +#define PROCESSCHAIN_H + +#include "language.h" +#include <qobject.h> +#include <qvaluelist.h> + +class FlowCode; +class Gpasm; +class Gpdasm; +class Gplib; +class Gplink; +class KTechlab; +class Microbe; +class PicProgrammer; +class ProcesOptions; +class SDCC; + +typedef QValueList<ProcessOptions> ProcessOptionsList; + +/** +@author Daniel Clarke +@author David Saxton +*/ +class ProcessChain : public QObject +{ + Q_OBJECT + public: + ProcessChain( ProcessOptions options, KTechlab *parent, const char *name = 0l ); + ~ProcessChain(); + + void setProcessOptions( ProcessOptions options ) { m_processOptions = options; } + + public slots: + /** + * Adds the output file to project if requested in the options, and opens + * the file in a code editor. Called to signal that a language in the last + * step of a compile has finished its compiling successfully. + */ + void slotFinishedCompile( Language * language ); + /** + * Call to compile a file of one type all the way to another type. This + * uses the ProcessOptions given in the constructor of this function, or + * later in setProcessOptions. + */ + void compile(); + + signals: + /** + * Emitted when compiling has successfully gone all the way through to the + * specified 'typeTo' + * @param options The ProcessOptions holding the output filename + * @see compile + */ + void successful(ProcessOptions options); + /** + * Convenience signal + */ + void successful(); + /** + * Emitted if not successful + */ + void failed(); + + protected: + FlowCode * flowCode(); + Gpasm * gpasm(); + Gpdasm * gpdasm(); + Gplib * gplib(); + Gplink * gplink(); + Microbe * microbe(); + PicProgrammer * picProgrammer(); + SDCC * sdcc(); + + int m_errorCount; + ProcessOptions m_processOptions; + KTechlab * m_pKTechlab; + + private: + FlowCode * m_pFlowCode; + Microbe * m_pMicrobe; + Gpasm * m_pGpasm; + Gpdasm * m_pGpdasm; + Gplib * m_pGplib; + Gplink * m_pGplink; + PicProgrammer * m_pPicProgrammer; + SDCC * m_pSDCC; +}; + + +class ProcessListChain : public QObject +{ + Q_OBJECT + + public: + ProcessListChain( ProcessOptionsList pol, KTechlab *parent, const char *name = 0l ); + + signals: + /** + * Emitted if successful + */ + void successful(); + /** + * Emitted if not successful + */ + void failed(); + + protected slots: + void slotProcessChainSuccessful(); + void slotProcessChainFailed(); + + protected: + ProcessOptionsList m_processOptionsList; + KTechlab * m_pKTechlab; +}; + +#endif diff --git a/src/languages/sdcc.cpp b/src/languages/sdcc.cpp new file mode 100644 index 0000000..553e974 --- /dev/null +++ b/src/languages/sdcc.cpp @@ -0,0 +1,205 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "asminfo.h" +#include "languagemanager.h" +#include "logview.h" +#include "microinfo.h" +#include "microlibrary.h" +#include "sdcc.h" +#include "src/core/ktlconfig.h" + +#include <klocale.h> +#include <kmessagebox.h> +#include <kprocess.h> + +SDCC::SDCC( ProcessChain * processChain, KTechlab * parent ) + : ExternalLanguage( processChain, parent, "SDCC" ) +{ + m_successfulMessage = i18n("*** Compilation successful ***"); + m_failedMessage = i18n("*** Compilation failed ***"); +} + + +SDCC::~SDCC() +{ +} + + +void SDCC::processInput( ProcessOptions options ) +{ + resetLanguageProcess(); + + MicroInfo * info = MicroLibrary::self()->microInfoWithID( options.m_picID ); + if (!info) + { + outputError( i18n("Could not find PIC with ID \"%1\".").arg(options.m_picID) ); + return; + } + + m_processOptions = options; + + *m_languageProcess << ("sdcc"); + + + //BEGIN Pass custom sdcc options +#define ARG(text,option) if ( KTLConfig::text() ) *m_languageProcess << ( QString("--%1").arg(option) ); + // General + ARG( sDCC_nostdlib, "nostdlib" ) + ARG( sDCC_nostdinc, "nostdinc" ) + ARG( sDCC_less_pedantic, "less-pedantic" ) + ARG( sDCC_std_c89, "std-c89" ) + ARG( sDCC_std_c99, "std-c99" ) + + // Code generation + ARG( sDCC_stack_auto, "stack-auto" ) + ARG( sDCC_int_long_reent, "int-long-reent" ) + ARG( sDCC_float_reent, "float-reent" ) + ARG( sDCC_fommit_frame_pointer, "fommit-frame-pointer" ) + ARG( sDCC_no_xinit_opt, "no-xinit-opt" ) + ARG( sDCC_all_callee_saves, "all-callee-saves" ) + + // Optimization + ARG( sDCC_nooverlay, "nooverlay" ) + ARG( sDCC_nogcse, "nogcse" ) + ARG( sDCC_nolabelopt, "nolabelopt" ) + ARG( sDCC_noinvariant, "noinvariant" ) + ARG( sDCC_noinduction, "noinduction" ) + ARG( sDCC_no_peep, "no-peep" ) + ARG( sDCC_noloopreverse, "noloopreverse" ) + ARG( sDCC_opt_code_size, "opt-code-size" ) + ARG( sDCC_opt_code_speed, "opt-code-speed" ) + ARG( sDCC_peep_asm, "peep-asm" ) + ARG( sDCC_nojtbound, "nojtbound" ) + + // PIC16 Specific + if ( info->instructionSet()->set() == AsmInfo::PIC16 ) + { + ARG( sDCC_nodefaultlibs, "nodefaultlibs" ) + ARG( sDCC_pno_banksel, "pno-banksel" ) + ARG( sDCC_pstack_model_large, "pstack-model=large" ) + ARG( sDCC_debug_xtra, "debug-xtra" ) + ARG( sDCC_denable_peeps, "denable-peeps" ) + ARG( sDCC_calltree, "calltree" ) + ARG( sDCC_fstack, "fstack" ) + ARG( sDCC_optimize_goto, "optimize-goto" ) + ARG( sDCC_optimize_cmp, "optimize-cmp" ) + ARG( sDCC_optimize_df, "optimize-df" ) + } +#undef ARG + + if ( !KTLConfig::miscSDCCOptions().isEmpty() ) + *m_languageProcess << ( KTLConfig::miscSDCCOptions() ); + //END Pass custom sdcc options + + + *m_languageProcess << ("--debug"); // Enable debugging symbol output + *m_languageProcess << ("-S"); // Compile only; do not assemble or link + + QString asmSwitch; + switch ( info->instructionSet()->set() ) + { + case AsmInfo::PIC12: + // Last time I checked, SDCC doesn't support Pic12, and probably never will, but whatever... + asmSwitch = "-mpic12"; + break; + case AsmInfo::PIC14: + asmSwitch = "-mpic14"; + break; + case AsmInfo::PIC16: + asmSwitch = "-mpic16"; + break; + } + + *m_languageProcess << (asmSwitch); + + *m_languageProcess << ( "-"+options.m_picID.lower() ); + + *m_languageProcess << ( options.inputFiles().first() ); + + *m_languageProcess << ("-o"); + *m_languageProcess << ( options.intermediaryOutput() ); + + if ( !start() ) + { + KMessageBox::sorry( LanguageManager::self()->logView(), i18n("Compilation failed. Please check you have sdcc installed.") ); + processInitFailed(); + return; + } +} + + +bool SDCC::isError( const QString &message ) const +{ + return false; +} + + +bool SDCC::isStderrOutputFatal( const QString & message ) const +{ + if ( message.startsWith("Processor:") ) + return false; + + return true; +} + + +bool SDCC::isWarning( const QString &message ) const +{ + return false; +} + + +ProcessOptions::ProcessPath::Path SDCC::outputPath( ProcessOptions::ProcessPath::Path inputPath ) const +{ + switch (inputPath) + { + case ProcessOptions::ProcessPath::C_AssemblyRelocatable: + return ProcessOptions::ProcessPath::None; + + case ProcessOptions::ProcessPath::C_Library: + return ProcessOptions::ProcessPath::AssemblyRelocatable_Library; + + case ProcessOptions::ProcessPath::C_Object: + return ProcessOptions::ProcessPath::AssemblyRelocatable_Object; + + case ProcessOptions::ProcessPath::C_PIC: + return ProcessOptions::ProcessPath::AssemblyAbsolute_PIC; + + case ProcessOptions::ProcessPath::C_Program: + return ProcessOptions::ProcessPath::AssemblyRelocatable_Program; + + case ProcessOptions::ProcessPath::AssemblyAbsolute_PIC: + case ProcessOptions::ProcessPath::AssemblyAbsolute_Program: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Library: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Object: + case ProcessOptions::ProcessPath::AssemblyRelocatable_PIC: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Program: + case ProcessOptions::ProcessPath::FlowCode_AssemblyAbsolute: + case ProcessOptions::ProcessPath::FlowCode_Microbe: + case ProcessOptions::ProcessPath::FlowCode_PIC: + case ProcessOptions::ProcessPath::FlowCode_Program: + case ProcessOptions::ProcessPath::Microbe_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Microbe_PIC: + case ProcessOptions::ProcessPath::Microbe_Program: + case ProcessOptions::ProcessPath::Object_Disassembly: + case ProcessOptions::ProcessPath::Object_Library: + case ProcessOptions::ProcessPath::Object_PIC: + case ProcessOptions::ProcessPath::Object_Program: + case ProcessOptions::ProcessPath::PIC_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Program_Disassembly: + case ProcessOptions::ProcessPath::Program_PIC: + case ProcessOptions::ProcessPath::Invalid: + case ProcessOptions::ProcessPath::None: + return ProcessOptions::ProcessPath::Invalid; + } + + return ProcessOptions::ProcessPath::Invalid; +} diff --git a/src/languages/sdcc.h b/src/languages/sdcc.h new file mode 100644 index 0000000..a6de933 --- /dev/null +++ b/src/languages/sdcc.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef SDCC_H +#define SDCC_H + +#include <externallanguage.h> + +/** +@author David Saxton +*/ +class SDCC : public ExternalLanguage +{ + public: + SDCC( ProcessChain * processChain, KTechlab * parent ); + ~SDCC(); + + virtual void processInput( ProcessOptions options ); + virtual ProcessOptions::ProcessPath::Path outputPath( ProcessOptions::ProcessPath::Path inputPath ) const; + + protected: + virtual bool isError( const QString & message ) const; + virtual bool isWarning( const QString & message ) const; + virtual bool isStderrOutputFatal( const QString & message ) const; +}; + +#endif diff --git a/src/languages/sourceline.cpp b/src/languages/sourceline.cpp new file mode 100644 index 0000000..9ca89bb --- /dev/null +++ b/src/languages/sourceline.cpp @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "sourceline.h" + + +//BEGIN class SourceLine +SourceLine::SourceLine() + : m_line(-1) +{ +} + + +SourceLine::SourceLine( const QString & fileName, int line ) + : m_fileName(fileName), + m_line(line) +{ +} + + +bool SourceLine::operator < ( const SourceLine & sourceLine ) const +{ + return (m_fileName < sourceLine.fileName()) || + (m_fileName == sourceLine.fileName() && m_line < sourceLine.line()); +} + + +bool SourceLine::operator == ( const SourceLine & sourceLine ) const +{ + return (sourceLine.fileName() == fileName()) && + (sourceLine.line() == line()); +} +//END class SourceLine + + diff --git a/src/languages/sourceline.h b/src/languages/sourceline.h new file mode 100644 index 0000000..d2e774d --- /dev/null +++ b/src/languages/sourceline.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef SOURCELINE_H +#define SOURCELINE_H + +#include <qstring.h> + +/** +@author David Saxton + */ +class SourceLine +{ + public: + /** + * Creates an invalid source line (line is negative). + */ + SourceLine(); + SourceLine( const QString & fileName, int line ); + + QString fileName() const { return m_fileName; } + int line() const { return m_line; } + + bool isValid() const { return m_line >= 0; } + + bool operator < ( const SourceLine & sourceLine ) const; + bool operator == ( const SourceLine & sourceLine ) const; + + protected: + QString m_fileName; + int m_line; +}; + + +#endif |