语法高亮编辑控件Scintilla在MFC中的简单使用之完整示例
2011-12-07 14:37
603 查看
该示例是一个简单的NC程序编辑器,附件代码在Visual Studio .NET 2003(VC++7.1)下编译通过。
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
第一部分、修改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
相关文章推荐
- 语法高亮编辑控件Scintilla在MFC中的简单使用
- 语法高亮编辑控件Scintilla在MFC中的简单使用
- 语法高亮编辑控件Scintilla在MFC中的简单使用
- MFC表格控件的简单使用(转)
- MFC表格控件的简单使用
- 开源的源代码编辑控件Scintilla的使用
- 使用短信控件的一个简单示例
- MFC部分控件简单使用
- MFC控件 状态条的简单介绍及使用 CStatusBar
- 如何在 Windows 环境下使用 Scintilla 编辑控件?
- MFC表格控件的简单使用
- 回调函数中使用MFC类的成员或对话框控件的简单方法。
- MFC-简单使用进度条和滑动控件
- 卷二 MFC中简单控件使用
- 藏文文本在MFC编辑框控件中显示不完整,下部被截断了一部分原因分析
- MFC入门 slider控件的简单使用
- 如何在 Windows 环境下使用 Scintilla 编辑控件?收藏
- GridView控件编辑、更新、删除示例(更新包含有DropDownList控件使用)、导出Excel
- 回调函数中使用MFC类的成员或对话框控件的简单方法
- 如何在 Windows 环境下使用 Scintilla 编辑控件?收藏