您的位置:首页 > 其它

语法高亮编辑控件Scintilla在MFC中的简单使用之完整示例

2011-12-07 14:37 603 查看
该示例是一个简单的NC程序编辑器,附件代码在Visual Studio .NET 2003(VC++7.1)下编译通过。

第一部分、修改Scintilla,使其支持NC程序

1.修改SciLexer.h,加上自己的token类型定义



C++代码

#define SCLEX_NCPROG 87 //淡月清风 2008年11月7日17:19:23

#define typeDefault 0x00

#define typeLineStart 0x01

#define typeG 0x02

#define typeGValue 0x03

#define typeM 0x04

#define typeMValue 0x05

#define typeX 0x06

#define typeXValue 0x07

#define typeY 0x08

#define typeYValue 0x09

#define typeI 0x0A

#define typeIValue 0x0B

#define typeJ 0x0C

#define typeJValue 0x0D

#define typeComment 0x0E //()

#define typeNCProgramStart 0x0F //%

#define typeNCDescription 0x10 //;

#define typeNCProgramEnd 0x11 //“\ESC” ASCII码是27

#define typeNCLineNumber 0x12 //行号 N

#define typeNCLineNumberValue 0x13 //行号 01201

#define typeProgramNumber 0x14

#define typeF 0x15

#define typeFValue 0x16

2.编写NC程序词法分析的Lex程序LexNCProg.cxx

这个Lex程序扫描全部字符,并标记当前字符的状态,它使用的是状态机技术(类似于状态模式)。

C++代码

//Scintilla source code edit control

/** @file LexNCProg.cxx
** Lexer for NC Program.

**/
// Copyright 2008-2010 by 淡月清风 <dgx_lsyd3@163.com>

//修改记录:
// 2008年12月15日12:08:39:

// 1.使大小写不区分
// 2.G01,02等的省略写法,X,Y直接在行首无法识别的BUG

#include <stdlib.h>

#include <string.h>
#include <ctype.h>

#include <stdio.h>
#include <stdarg.h>

#include <windows.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"

#include "StyleContext.h"
#include "KeyWords.h"

#include "Scintilla.h"
#include "SciLexer.h"

#ifdef SCI_NAMESPACE

using namespace Scintilla;

#endif

static const char * const NCProgWordListDesc[] =

{
0
};

static void ColouriseNCProgDoc(

unsigned int startPos, int length, int initStyle,

WordList *keywordlists[],
Accessor &styler)
{
static int LastTokenTypeForComment = typeLineStart;

static int LastTokenType=typeLineStart;

static int nLastGCode = -1; //记录本行之前的G代码。

char szLastGCode[100];

memset(szLastGCode, 0, 100);

StyleContext sc(startPos, length, initStyle, styler);
sc.SetState(typeLineStart);
for (; sc.More(); sc.Forward())

{
//char szText[4];

//sprintf(szText,"%c",sc.ch);

//OutputDebugString(szText);

int ch = sc.ch;

int chNext = sc.chNext;

int chPrev = sc.chPrev;

if (isalpha(ch))

{
ch = toupper(ch);
}
if (isalpha(chNext))

{
chNext = toupper(chNext);
}
if (isalpha(chPrev))

{
chPrev = toupper(chPrev);
}

// 重点关注:从这里开始执行词法分析代码

// 若注释可以出现在任何位置

// 当前字符是注释开始

if (ch == '(')

{
LastTokenTypeForComment = sc.state;
sc.SetState(typeComment);
}
//当前状态是注释

else if (sc.state == typeComment || LastTokenType==typeComment)

{
sc.SetState(typeComment);
if (ch == ')')

{
sc.ForwardSetState(LastTokenTypeForComment);

}
}
else
{
if (ch == '\n' || ch == '\r')

{
sc.SetState(typeLineStart);
}
//当前状态是行首

else if (sc.state == typeLineStart)

{
if (ch == 'O' || ch == 'P')//EIA的行号以大写的'O'开始,PA的是P。字母o和数字0混在一起,认不出来了,呵呵

{
if (isdigit(chNext))

{
sc.SetState(typeProgramNumber);

}
}
else if (ch == 'M')

{
if (isdigit(chNext))

{
sc.SetState(typeM);
}
}
else if (ch == 'G')

{
if (isdigit(chNext))

{
memset(szLastGCode, 0, 100);

sc.SetState(typeG);
}
}
else if (ch == '%')

{
sc.SetState(typeNCProgramStart);

}
else if (ch == ';')

{
sc.SetState(typeNCDescription);

}
else if (ch == '\x1B')//\ESC

{
sc.SetState(typeNCProgramEnd);

}
else if (ch == 'N')

{
if (isdigit(chNext))

{
sc.SetState(typeNCLineNumber);

}
}
//行首就是XY等坐标数据,那么看上几行的G代码是否包含G00,G01,G02,G03等

else if (nLastGCode == 0 || nLastGCode == 1 || nLastGCode == 2 || nLastGCode == 3)

{
//注意这里:省略了G指令的写法,我们要将他补上

if (ch == 'X')

{
if (isdigit(chNext))

sc.SetState(typeX);
}
else if (ch == 'Y')

{
if (isdigit(chNext))

sc.SetState(typeY);
}
else if (ch == 'I')

{
if (isdigit(chNext))

sc.SetState(typeI);
}
else if (ch == 'J')

{
if (isdigit(chNext))

sc.SetState(typeJ);
}
}
}
//当前状态是程序号

else if (sc.state == typeProgramNumber)

{
if (isdigit(ch))

{
sc.SetState(typeProgramNumber);

}
}
//当前状态是行号

else if (sc.state == typeNCLineNumber)

{
if (isdigit(ch))

{
sc.SetState(typeNCLineNumberValue);

}
}
//当前状态是行号的值

else if (sc.state == typeNCLineNumberValue)

{
if (isdigit(ch))

{
sc.SetState(typeNCLineNumberValue);

}
else if (ch == 'M')

{
if (isdigit(chNext))

sc.SetState(typeM);
}
else if (ch == 'G')

{
if (isdigit(chNext))

{
memset(szLastGCode, 0, 100);
sc.SetState(typeG);
}
}
//行号后紧接着就是XY等坐标数据,那么就要看上几行的G代码是否包含G00,G01,G02,G03等

else if (nLastGCode == 0 || nLastGCode == 1 || nLastGCode == 2 || nLastGCode == 3)

{
//注意这里:省略了G指令的写法,我们要将他补上

if (ch == 'X')

{
if (isdigit(chNext))

sc.SetState(typeX);
}
else if (ch == 'Y')

{
if (isdigit(chNext))

sc.SetState(typeY);
}
else if (ch == 'I')

{
if (isdigit(chNext))

sc.SetState(typeI);
}
else if (ch == 'J')

{
if (isdigit(chNext))

sc.SetState(typeJ);
}
else if (ch == 'F')

{
if (isdigit(chNext))

sc.SetState(typeF);
}
}
}
//当前状态是M

else if (sc.state == typeM)

{
if (isdigit(ch))

{
sc.SetState(typeMValue);
}
}
//当前状态是M的值

else if (sc.state == typeMValue)

{
if (isdigit(ch))

{
sc.SetState(typeMValue);
}
}
//当前状态是G

else if (sc.state == typeG)

{
if (isdigit(ch))

{
sc.SetState(typeGValue);
char szChar[10];

memset(szChar, 0, 10);
sprintf(szChar, "%c", (char)ch);

//itoa(UpperLowerChar,szChar,10);

strcat(szLastGCode, szChar);
}
}
else if (sc.state == typeF)

{
if (isdigit(ch))

{
sc.SetState(typeFValue);
}
}
//当前状态是G的值

else if (sc.state == typeGValue)

{
if (isdigit(ch))

{
sc.SetState(typeGValue);
char szChar[10];

memset(szChar, 0, 10);
sprintf(szChar, "%c", (char)ch);

//itoa(UpperLowerChar,szChar,10);

strcat(szLastGCode, szChar);
}
else if (ch == 'X')

{
if (isdigit(chNext))

sc.SetState(typeX);
}
else if (ch == 'Y')

{
if (isdigit(chNext))

sc.SetState(typeY);
}
else if (ch == 'I')

{
if (isdigit(chNext))

sc.SetState(typeI);
}
else if (ch == 'J')

{
if (isdigit(chNext))

sc.SetState(typeI);
}
}
//当前状态是X

else if (sc.state == typeX)

{
if (isdigit(ch))

{
sc.SetState(typeXValue);
}

}
//当前状态是X的值

else if (sc.state == typeXValue)

{
if (isdigit(ch))

{
sc.SetState(typeXValue);
}
else if (ch == 'Y')

{
if (isdigit(chNext))

sc.SetState(typeY);
}
else if (ch == 'I')

{
if (isdigit(chNext))

sc.SetState(typeI);
}
else if (ch == 'J')

{
if (isdigit(chNext))

sc.SetState(typeJ);
}
else if (ch == 'F')

{
if (isdigit(chNext))

sc.SetState(typeF);
}
}
//当前状态是Y

else if (sc.state == typeY)

{
if (isdigit(ch))

{
sc.SetState(typeYValue);
}
}
//当前状态是Y的值

else if (sc.state == typeYValue)

{
if (isdigit(ch))

{
sc.SetState(typeYValue);
}
else if (ch == 'I')

{
if (isdigit(chNext))

sc.SetState(typeI);
}
else if (ch == 'J')

{
if (isdigit(chNext))

sc.SetState(typeJ);
}
else if (ch == 'F')

{
if (isdigit(chNext))

sc.SetState(typeF);
}
}
//当前状态是I

else if (sc.state == typeI)

{
if (isdigit(ch))

{
sc.SetState(typeIValue);
}
}
//当前状态是I的值

else if (sc.state == typeIValue)

{
if (isdigit(ch))

{
sc.SetState(typeIValue);
}
else if (ch == 'J')

{
if (isdigit(chNext))

sc.SetState(typeJ);
}
else if (ch == 'F')

{
if (isdigit(chNext))

sc.SetState(typeF);
}
}
//当前状态是J

else if (sc.state == typeJ)

{
if (isdigit(ch))

{
sc.SetState(typeJValue);
}
}
//当前状态是J的值

else if (sc.state == typeJValue)

{
if (isdigit(ch))

{
sc.SetState(typeJValue);
}
else if (ch == 'F')

{
if (isdigit(chNext))

sc.SetState(typeF);
}
}
else

{
sc.SetState(typeDefault);
}
}
nLastGCode = atoi(szLastGCode);
LastTokenType=sc.state;
}
sc.Complete();
}

LexerModule lmNCProg(SCLEX_NCPROG, ColouriseNCProgDoc, "NCProg", 0, NCProgWordListDesc);

3.修改KeyWords.cxx,加上:

C++代码

LINK_LEXER(lmNCProg);

编译即可。

源代码如下:

Scintilla(NCProg).rar


第二部分、在项目中使用

具体参看如下源代码和说明。



NcEditDemo.rar




封装Scintilla的简单NC编辑器控件应用文档.pdf
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: