该示例是一个简单的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
第二部分、在项目中使用
具体参看如下源代码和说明。