📜 ⬆️ ⬇️

QScintilla: write your lexer

Hi, Habr!

UPD : the third part of the cycle.

This is the second article of the cycle about QScintilla. The first is here . First I want to say a huge thank you to everyone who brought me out of karmoyam! And now you can start. What are we going to do today? We will write a lexer for Assembler! "In the box" it is not present - it does not matter, we will write it yourself! The process is quite lengthy, so I’m going to paint and comment a little less. Moreover, I don’t know assembly language, so the lexer will be terribly primitive and will only draw commands and comments.
')
As Gagarin said - “Let's go!”

At this stage, I believe that you have already read the first article (see above) and know how to create an editor and customize it. We continue with the same project that we edited last time and with the same set of tools (those who have not read the first article caught here).

Challenge and ideas


Write the syntax coloring for the Assembler language. But there is no default lexer (color scheme) in QScintilla. Nothing, we will write. To do this, there is a class QsciLexerCustom (in secret: it has virtual methods).

Stocking


Let's make our lexer dough . The blank looks like this:

class QsciLexerASM : public QsciLexerCustom { Q_OBJECT public: explicit QsciLexerASM(QObject *parent = 0); ~QsciLexerASM(); //!     (  ) void styleText(int start, int end); //!    (  styleText()) void paintKeywords(const QString &source, int start); void paintComments(const QString &source, int start); //!   (   ASM const char * language() const; //!    QColor defaultColor(int style) const; //!   QString description(int style) const; //!   enum { Default = 0, Comment = 1, Keyword = 2 }; private: QsciLexerASM(const QsciLexerASM &); QsciLexerASM &operator=(const QsciLexerASM &); QStringList keywordsList; }; 


Some functions listed here are not needed by us, but by QScintilla. But if they are needed by someone, then we will implement them in mainwindow.h:

 QString QsciLexerASM::description(int style) const { switch(style) { case Default: return "Default"; case Comment: return "Comment"; case Keyword: return "Keyword"; } return QString(style); } const char * QsciLexerASM::language() { return "ASM"; } 


I think everything is clear. Let's go further. Now we need to implement the default color for all styles:

 QColor QsciLexerASM::defaultColor(int style) const { switch(style) { case Comment: return Qt::darkGreen; case Keyword: return Qt::blue; } return Qt::black; } 


But now we will color our code. To do this, we need to know what keywords are in the assembler. I found a little bit on Wikipedia . To do this, set our keywordsList in the constructor:

 QsciLexerASM::QsciLexerASM(QObject *parent) : QsciLexerCustom(parent) { keywordsList << "mov" << "add" << "sub" << "imul" << "or" << "and" << "xor" << "shr" << "jmp" << "loop" << "ret" << "int"; } 


We continue. Now you have to be very careful - we have come to the place where we will color the syntax! I will list the function code styleText (), and then briefly comment on it:

 void QsciLexerASM::styleText(int start, int end) { if(!editor()) return; //        char * data = new char[end - start + 1]; //   Scintilla editor()->SendScintilla(QsciScintilla::SCI_GETTEXTRANGE, start, end, data); QString source(data); delete [] data; if(source.isEmpty()) return; //  ! paintKeywords(source, start); paintComments(source, start); } 


One moment. The last two lines of the method. The paintKeyword () and paintComments () functions are used to color keywords and comments, respectively. We call the design of teams, and only then comments. Why? Guess it.

Now everything is fine. Almost all methods are implemented. It remains only to implement paintKeyword () and paintComments ():

 void QsciLexerASM::paintKeywords(const QString &source, int start) { foreach(QString word, keywordsList) { //    if(source.contains(word)) { int p = source.count(word); //   int index = 0; //    c 0 while(p != 0) { int begin = source.indexOf(word, index); //    index = begin+1; //       startStyling(start + begin); //      setStyling(word.length(), Keyword); //   word.length   Keyword startStyling(start + begin); //   p--; } } } } void QsciLexerASM::paintComments(const QString &source, int start) { int p = source.count(";"); //     if(p == 0) return; int index = 0; //    ";"  0 while(p != 0) { int begin = source.indexOf(";", index); //    int length=0; //   index = begin+1; //       for(int k = begin; source[k] != '\n'; k++) //  source    length++; startStyling(start + begin); //      setStyling(length, Comment); //   length   Comment startStyling(start + begin); //   p--; } } 


Is done. Now our lexer can do something. You can compile. Yes you can. Yes, you can definitely compile.

Result


With the assembler, I did not work. So wildly sorry. I do not even know the basic principles of working with him. But I thought that it was perfect as an example to this article.

Here's what we got:




Some bugs can be seen, for example, in the word “dword” the occurrence of “or” is highlighted as key. As suggested by the comrade of TheHorse - you need to check that the occurrence of keywords in the text is divided by separators. But by the end of this article, I was so tired that I decided not to fix this bug, but leave it fixed to readers :)

And here is our creation: qscintilla-demo-2

Thank you, and once again I apologize for the choice of language.

Source: https://habr.com/ru/post/144714/


All Articles