posts - 76,  comments - 621,  trackbacks - 0
编辑器制作之语法加亮基本原理在上一篇文章里,我简单的提及了语法加亮的基本思路,下面在总结概括一下。

笔者认为,对于编辑器而言,如果支持非常严格的语法加亮的话,那么扩展性是很低的。那么在扩展性和正确性之间,我们应该取得一个平衡。这个平衡就是既要保证编辑器的高效率运转,又要保持文本配置文件的可编辑性。

首先,几乎所有的编程语言都具有某种共性,这些共性概括如下:
1.关键字
2.注释
3.字符串
4.Delimiters
5.普通字符
那么对于一个字符串序列,我们应该如何做呢?任何一个人都会很自然的想到:从前往后扫描。对,那么如何扫描呢?我用的手段是状态机。或者不能完全称之为状态机,因为在我的状态机里面用到了预先判断,对于一个长度为N的字符串,最坏的情况下会扫描M*N*L次(其中M为某些块的起始或者结束标记的长度,L为块的个数,关于什么是块,参加我的上一篇文章),所以对于我的这个状态机,称之为状态模式更贴切一些。状态模式是个好东西,对于状态模式乃何物以及如何构造,本文不作详细阐述。

如果仅仅是识别上面这些东西的话,那么语法加亮是非常容易实现的。但事与愿违,事情并不是如此简单。举个例子html.在最开始的时候html的确让我伤透了脑筋,因为他可以嵌入各种各样的语言,并且每种语言的schema并不一样,比如可以嵌入css,或者js,或者vbs,当然还有php, java, c#代码等等。这个时候该如何做呢? 我用的手段是分块之后,对于不同的子语言应用不同的schema,这么做并不是完全对的(和Lex分析相比),或多或少会出现某种问题,不过大多数情况下表现的都非常好,这个点就叫平衡。

再说一下状态分析,定义如下函数: 伪代码
//根据起始状态,分析字符串line的第index字符应该是何种状态
state NextState( string line, int index, state start_state ){
 switch( start_state ){
  case .
  return some_state;
  case .
  return some_state;
  case .
  return some_state;
  case .
  return some_state;
 }
}

//分析一行字符串的某一个字符应该是何种状态,并预存入cache
state ParseLine( string line, int index, state start_state ){
 for( i=index; i<line.Length; i++ ){
  start_state = NextState( line, i, start_state );
  siwtch( start_state ){
   //set text attributes
  }
 }
 //分析完之后,在进行分析一遍,进行一些细节匹配
 DetailMatch(...)
 //分析完之后,我们要返回该行的最后的状态,用来作为下一行的起始状态
 return start_state;
}

//这个函数主要用来对于分完块之后的代码进行细节匹配,比如匹配注释中的email和url
//或者普通字符中的数字等等
void DetailMatch(...){
 //use regex to match some details, such as number or email
}
上面这几个函数都简单明了,比较容易理解,对于ParseLine我们发现在进行行跳转的时候DetailMatch并不是必须的。什么叫行跳转呢?比如打开一个代码文件,现在我要跳转到第5000行,那么很显然第5000行需要放到屏幕上头,这个时候我怎么知道第5000行的起始状态呢?当然也得从第一航开始分析,但是我们发现DetailMatch其实并不是必须的,因为我们只需要作块状识别就够了,所以速度是非常客观的。

先写这么多了,等我以后老了,我打算把这些东西写成一本书,名字就叫编辑器制作基本原理,呵呵.

不敢妄自菲薄,下面贴两个代码片段和上面的伪代码均是按照上述方法生成的,还算美观.
C++代码
#include <stdio.h>
// line comment email test@test.com 
// url:http://www.cppblog.com/megax in comment over
/*
block comment
email test@test.com url:http://www.cppblog.com/megax in comment over
*/
int main(int argc, char *argv[])
{
emailtest@test.com   http://www.cppblog.com/megax in comment over int a = Class::Somfunction(); // function char * p = "abcdef string to new line"; // string can continue, just test char* p = "abcef\"\\"; //escpae char* p = 'abcef\"\\'; //escpae, just test; asm{ ; test sub lan ; line comment email test@test.com ; url:http://www.cppblog.com/megax in comment over mov ax, 10 add ax, 0x12AD add ax, 123L jump loop1 } // number test int a = 1234; int b = 0xA12D; int c = 1234L; float a = 123.456; return 0; }
HTML代码嵌入css,js
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="images/favicon.ico" rel="SHORTCUT ICON" />
<title>test</title>
<script type="text/javascript">
function setTab(m,n){
 var tli=document.getElementById("menu"+m).getElementsByTagName("a");
 var mli=document.getElementById("main"+m).getElementsByTagName("div");
 for(i=0;i<tli.length;i++){
  tli[i].className=i==n?"current1 current2":"";
  mli[i].style.display=i==n?"block":"none";
 } 
 var a = 0x012345678;
 var a = 0xABCDEF12345;
 // line comment test@test.com in comment  http://www.cppblog.com/megax in comment over
 /*
 block comment in js
 test@test.com in comment
 http://www.cppblog.com/megax in comment
 over
 */
}
</script> function style var
<style>
body{
 function style var
 font-size: 12px;
 font-family: "sfdsfdsf";
 /*
 block comment in css
 test@test.com in comment
 http://www.cppblog.com/megax in comment
 over
 */
}

</style>
</head>
<body>
<table>
</table>
function style var /*sdfdsfdsf*/ return var
<!-- 
block comment in html
 test@test.com in comment
 http://www.cppblog.com/megax in comment
 over
-->
</body>
</html>
下面看一下cppblog自带的代码加亮,没有c++的,用c#代替

#include <stdio.h>
// line comment email test@test.com 
// url:http://www.cppblog.com/megax in comment over
/*

block comment
email test@test.com url:
http://www.cppblog.com/megax in comment over
*/
int main(int argc, char *argv[])
{
    
int a = Class::Somfunction(); // function
    char * p = "abcdef
    string to new line"; // string can continue, just test
    char* p = "abcef\"\\"; //escpae
    char* p = 'abcef\"\\'//escpae, just test;
    asm{
        ; test sub lan
        ; line comment email test@test.com 
        ; url:http:
//www.cppblog.com/megax in comment over
        mov ax, 10
        add ax, 
0x12AD
        add ax, 
123L
        jump loop1
    }
    
// number test
    int a = 1234int b = 0xA12D;
    
int c = 1234Lfloat a = 123.456;
    
    
return 0;
}

HTML的

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="images/favicon.ico" rel="SHORTCUT ICON" />
<title>test</title>
<script type="text/javascript">
function setTab(m,n){
    
var tli=document.getElementById("menu"+m).getElementsByTagName("a");
    
var mli=document.getElementById("main"+m).getElementsByTagName("div");
    
for(i=0;i<tli.length;i++){
        tli[i].className
=i==n?"current1 current2":"";
        mli[i].style.display
=i==n?"block":"none";
    }    
    
var a = 0x012345678;
    
var a = 0xABCDEF12345;
    
// line comment test@test.com in comment  http://www.cppblog.com/megax in comment over
    /*
    block comment in js
    test@test.com in comment
    http://www.cppblog.com/megax in comment
    over
    
*/
}
</script> function style var
<style>
body
{
    function style var
    font-size
: 12px;
    font-family
: "sfdsfdsf";
    
/*
    block comment in css
    test@test.com in comment
    http://www.cppblog.com/megax in comment
    over
    
*/
}

</style>
</head>
<body>
<table>
</table>
function style var /*sdfdsfdsf*/ return var
<!-- 
block comment in html
    test@test.com in comment
    http://www.cppblog.com/megax in comment
    over
-->
</body>
</html>

posted on 2008-07-09 20:23 megax 阅读(2078) 评论(4)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理