kumirbcompilerplugin.cpp 9.39 KB
Newer Older
victor's avatar
 
victor committed
1 2 3 4 5 6
#include "kumirbcompilerplugin.h"

#include <QtCore>
#include "kumiranalizer/analizer.h"
#include "kumiranalizer/kumiranalizerplugin.h"
#include "interfaces/generatorinterface.h"
victor's avatar
 
victor committed
7
#include "dataformats/kumfile.h"
8 9 10
#include "stdlib/kumirstdlib.hpp"
#include "vm/variant.hpp"
#include "vm/vm_bytecode.hpp"
victor's avatar
 
victor committed
11
#include <iostream>
12
#include <fstream>
victor's avatar
 
victor committed
13 14 15 16

using namespace KumirBytecodeCompiler;
using namespace KumirAnalizer;

17
typedef Shared::GeneratorInterface::DebugLevel DebugLevel;
victor's avatar
 
victor committed
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47

KumirBytecodeCompilerPlugin::KumirBytecodeCompilerPlugin()
{


}


KumirBytecodeCompilerPlugin::~KumirBytecodeCompilerPlugin()
{

}


QString KumirBytecodeCompilerPlugin::initialize(const QStringList &arguments)
{
    Q_UNUSED(arguments)
    m_analizer = qobject_cast<Shared::AnalizerInterface*>(myDependency("KumirAnalizer"));
    if (m_analizer)
        return "";
    else
        return "Could not find KumirAnalizer interface";
}

#include <iostream>


void KumirBytecodeCompilerPlugin::start()
{
    QString filename;
48
    QString encoding = "";
49
    DebugLevel debugLevel = Shared::GeneratorInterface::LinesOnly;
50

victor's avatar
 
victor committed
51 52 53 54 55
    for (int i=1; i<qApp->argc(); i++) {
        const QString arg = qApp->arguments()[i];
        if ( !arg.startsWith("-") && !arg.startsWith("[") && arg.endsWith(".kum")) {
            filename = arg;
        }
56 57 58
        if ( arg.startsWith("--encoding=") ) {
            encoding = arg.mid(11).toUpper();
        }
59 60 61 62 63 64 65 66 67
        if ( arg.toLower().startsWith("--debuglevel=") ) {
            int level = arg.mid(13).toInt();
            if (level==0)
                debugLevel = Shared::GeneratorInterface::NoDebug;
            else if (level==1)
                debugLevel = Shared::GeneratorInterface::LinesOnly;
            else
                debugLevel = Shared::GeneratorInterface::LinesAndVariables;
        }
Victor Yacovlev's avatar
Victor Yacovlev committed
68 69 70 71 72 73 74 75 76
        if ( arg.toLower().startsWith("-g=") ) {
            int level = arg.mid(3).toInt();
            if (level==0)
                debugLevel = Shared::GeneratorInterface::NoDebug;
            else if (level==1)
                debugLevel = Shared::GeneratorInterface::LinesOnly;
            else
                debugLevel = Shared::GeneratorInterface::LinesAndVariables;
        }
victor's avatar
 
victor committed
77 78 79 80
    }
    if (!filename.isEmpty() && !qApp->arguments().contains("-h") && !qApp->arguments().contains("-help") && !qApp->arguments().contains("--help") && !qApp->arguments().contains("/?")) {
        filename = QFileInfo(filename).absoluteFilePath();
        QFile f(filename);
victor's avatar
 
victor committed
81
        if (f.open(QIODevice::ReadOnly)) {            
victor's avatar
 
victor committed
82
            QDataStream ts(&f);
victor's avatar
 
victor committed
83
            KumFile::Data kumFile;
84
            kumFile.sourceEncoding = encoding;
victor's avatar
 
victor committed
85
            ts >> kumFile;
victor's avatar
 
victor committed
86 87 88
            f.close();

            int id = m_analizer->newDocument();
victor's avatar
 
victor committed
89
            m_analizer->setSourceText(id, kumFile.visibleText);
90
            m_analizer->setSourceDirName(id, QFileInfo(filename).absoluteDir().dirName());
victor's avatar
 
victor committed
91 92 93
            if (kumFile.hasHiddenText) {
                m_analizer->setHiddenText(id, kumFile.hiddenText, -1);
            }
victor's avatar
 
victor committed
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
            QList<Shared::Error> errors = m_analizer->errors(id);
            const AST::Data * ast = m_analizer->abstractSyntaxTree(id);
            const QString baseName = QFileInfo(filename).baseName();
            const QString outFileName = QFileInfo(filename).dir().absoluteFilePath(
                        baseName+".dump.json");
            QFile ff(outFileName);
            if (qApp->arguments().contains("-J") && ff.open(QIODevice::WriteOnly|QIODevice::Text)) {
                QTextStream ots(&ff);
                ots.setCodec("UTF-8");
                ots.setGenerateByteOrderMark(true);
                QString modJs = ast->dump();
                modJs.replace("\t", "  ");
                ots << modJs;
                ff.close();;
            }
109

victor's avatar
 
victor committed
110 111
            for (int i=0; i<errors.size(); i++) {
                Shared::Error e = errors[i];
112 113 114 115 116 117 118 119 120 121 122
                QString errorMessage = trUtf8("Ошибка: ") +
                        QFileInfo(filename).fileName() +
                        ":" + QString::number(e.line+1) +
                        ":" + QString::number(e.start+1) + "-" + QString::number(e.start+e.len) +
                        ": " + e.code;
//                std::cerr << "Error: " <<
//                             QFileInfo(filename).fileName().toLocal8Bit().data() <<
//                             ":" << e.line+1 <<
//                             ":" << e.start+1 << "-" << e.start+e.len <<
//                             ": " << e.code.toLocal8Bit().data() << std::endl;
#ifdef Q_OS_WIN32
123 124 125 126 127 128 129
                QTextCodec * cp866 = QTextCodec::codecForName("CP866");
                if (!qApp->arguments().contains("-ansi")) {
                    std::cerr << cp866->fromUnicode(errorMessage).data();
                }
                else {
                    std::cerr << errorMessage.toLocal8Bit().data();
                }
130
#else
131
                std::cerr << errorMessage.toLocal8Bit().data();
132 133
#endif
                std::cerr << std::endl;
victor's avatar
 
victor committed
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
            }
            Shared::GeneratorInterface * generator =
                    qobject_cast<Shared::GeneratorInterface*>(myDependency("Generator"));
            Q_CHECK_PTR(generator);

            QString outKodFileName = QFileInfo(filename).dir().absoluteFilePath(baseName+".kod");
            foreach (QString arg, qApp->arguments()) {
                if (arg.startsWith("-o=")) {
                    outKodFileName = arg.mid(3);
                }
            }

            if (!outKodFileName.endsWith(".kod"))
                outKodFileName += ".kod";

            QFile binOut(outKodFileName);
150 151
            QByteArray outData;
            QPair<QString,QString> res = generator->generateExecuable(ast, outData, debugLevel);
victor's avatar
 
victor committed
152 153 154
            if (!res.first.isEmpty()) {
                std::cerr << "Error generating execuable: " << res.first.toStdString() << std::endl;
            }
155 156 157
            binOut.open(QIODevice::WriteOnly);
            binOut.write(outData);
            binOut.close();
victor's avatar
 
victor committed
158
            if (res.second==MIME_BYTECODE_BINARY && QFile::exists(outKodFileName)) {
victor's avatar
 
victor committed
159 160 161 162 163
                QFile::Permissions ps = binOut.permissions();
                ps |= QFile::ExeGroup | QFile::ExeOwner | QFile::ExeOther;
                QFile::setPermissions(outKodFileName, ps);
                if (qApp->arguments().contains("-S")) {
                    Bytecode::Data data;
164 165 166
                    std::list<char> cdata;
                    for (int i=0; i<outData.size(); i++) {
                        cdata.push_back(outData[i]);
victor's avatar
 
victor committed
167
                    }
168 169 170 171 172 173
                    Bytecode::bytecodeFromDataStream(cdata, data);
                    const QString SfileName = outKodFileName.mid(0,outKodFileName.length()-4)+".ks";
                    const char * fn = QDir::toNativeSeparators(SfileName).toLocal8Bit().constData();
                    std::ofstream Sfile(fn);
                    Bytecode::bytecodeToTextStream(Sfile, data);
                    Sfile.close();
victor's avatar
 
victor committed
174 175
                }
            }
victor's avatar
 
victor committed
176
            qApp->setProperty("returnCode", errors.isEmpty() && res.first.isEmpty()? 0 : 1);
victor's avatar
 
victor committed
177 178 179
        }
    }
    else {
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
        bool russianLanguage = false;
    #if defined(WIN32) || defined(_WIN32)
        russianLanguage = true;
    #else
        char * env = getenv("LANG");
        if (env) {
            std::string LANG(env);
            russianLanguage = LANG.find("ru")!=std::string::npos;
        }
    #endif
        QString message;
        if (russianLanguage) {
            message = QString::fromUtf8("Вызов:\n");
            message += QString::fromAscii("\t") + qApp->argv()[0]+
                    QString::fromUtf8(" [-ansi] [-o=ИМЯПРОГРАММЫ.kod] [--encoding=КОДИРОВКА] ИМЯФАЙЛА.kum\n\n");
            message += QString::fromUtf8("\t-ansi\t\tИспользовть кодировку 1251 вместо 866 в терминале (только для Windows)\n");
            message += QString::fromUtf8("\t--encoding=КОДИРОВКА\tИспользовать заданную кодировку входного файла\n");
            message += QString::fromUtf8("\t-o=ИМЯПРОГРАММЫ.kod\tИмя файла результата (по умолчанию: ИМЯФАЙЛА.kod)\n");
            message += QString::fromUtf8("\tИМЯПРОГРАММЫ.kum\tИмя файла с Кумир-программой\n");
        }
        else {
            message = QString::fromUtf8("Usage:\n");
            message += QString::fromAscii("\t") + qApp->argv()[0]+
                    QString::fromUtf8(" [-ansi] [-o=PROGRAMNAME.kod] [--encoding=SOURCECODING] FILENAME.kum\n\n");
            message += QString::fromUtf8("\t-ansi\t\tUse codepage 1251 instead of 866 in console (Windows only)\n");
            message += QString::fromUtf8("\t--encoding=SOURCECODING\tForce source file encoding usage\n");
            message += QString::fromUtf8("\t-o=PROGRAMNAME.kod\tOutput file name (default: FILENAME.kod)\n");
            message += QString::fromUtf8("\tFILENAME.kum\tKumir input file name\n");
        }
#ifdef Q_OS_WIN32
            QTextCodec * cp866 = QTextCodec::codecForName("CP866");
            if (!qApp->arguments().contains("-ansi")) {
                std::cerr << cp866->fromUnicode(message).data();
            }
            else {
                std::cerr << message.toLocal8Bit().data();
            }
#else
            std::cerr << message.toLocal8Bit().data();
#endif
victor's avatar
 
victor committed
220 221 222 223 224 225 226 227 228 229 230
        qApp->setProperty("returnCode", 127);
    }
}

void KumirBytecodeCompilerPlugin::stop()
{

}


Q_EXPORT_PLUGIN(KumirBytecodeCompilerPlugin)