編輯器制作之語法加亮基本原理在上一篇文章里,我簡(jiǎn)單的提及了語法加亮的基本思路,下面在總結(jié)概括一下。
筆者認(rèn)為,對(duì)于編輯器而言,如果支持非常嚴(yán)格的語法加亮的話,那么擴(kuò)展性是很低的。那么在擴(kuò)展性和正確性之間,我們應(yīng)該取得一個(gè)平衡。這個(gè)平衡就是既要保證編輯器的高效率運(yùn)轉(zhuǎn),又要保持文本配置文件的可編輯性。
首先,幾乎所有的編程語言都具有某種共性,這些共性概括如下:
1.關(guān)鍵字
2.注釋
3.字符串
4.Delimiters
5.普通字符
那么對(duì)于一個(gè)字符串序列,我們應(yīng)該如何做呢?任何一個(gè)人都會(huì)很自然的想到:從前往后掃描。對(duì),那么如何掃描呢?我用的手段是狀態(tài)機(jī)。或者不能完全稱之為狀態(tài)機(jī),因?yàn)樵谖业臓顟B(tài)機(jī)里面用到了預(yù)先判斷,對(duì)于一個(gè)長(zhǎng)度為N的字符串,最壞的情況下會(huì)掃描M*N*L次(其中M為某些塊的起始或者結(jié)束標(biāo)記的長(zhǎng)度,L為塊的個(gè)數(shù),關(guān)于什么是塊,參加我的上一篇文章),所以對(duì)于我的這個(gè)狀態(tài)機(jī),稱之為狀態(tài)模式更貼切一些。狀態(tài)模式是個(gè)好東西,對(duì)于狀態(tài)模式乃何物以及如何構(gòu)造,本文不作詳細(xì)闡述。
如果僅僅是識(shí)別上面這些東西的話,那么語法加亮是非常容易實(shí)現(xiàn)的。但事與愿違,事情并不是如此簡(jiǎn)單。舉個(gè)例子html.在最開始的時(shí)候html的確讓我傷透了腦筋,因?yàn)樗梢郧度敫鞣N各樣的語言,并且每種語言的schema并不一樣,比如可以嵌入css,或者js,或者vbs,當(dāng)然還有php, java, c#代碼等等。這個(gè)時(shí)候該如何做呢? 我用的手段是分塊之后,對(duì)于不同的子語言應(yīng)用不同的schema,這么做并不是完全對(duì)的(和Lex分析相比),或多或少會(huì)出現(xiàn)某種問題,不過大多數(shù)情況下表現(xiàn)的都非常好,這個(gè)點(diǎn)就叫平衡。
再說一下狀態(tài)分析,定義如下函數(shù): 偽代碼
//根據(jù)起始狀態(tài),分析字符串line的第index字符應(yīng)該是何種狀態(tài)
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;
}
}
//分析一行字符串的某一個(gè)字符應(yīng)該是何種狀態(tài),并預(yù)存入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
}
}
//分析完之后,在進(jìn)行分析一遍,進(jìn)行一些細(xì)節(jié)匹配
DetailMatch(...)
//分析完之后,我們要返回該行的最后的狀態(tài),用來作為下一行的起始狀態(tài)
return start_state;
}
//這個(gè)函數(shù)主要用來對(duì)于分完塊之后的代碼進(jìn)行細(xì)節(jié)匹配,比如匹配注釋中的email和url
//或者普通字符中的數(shù)字等等
void DetailMatch(...){
//use regex to match some details, such as number or email
}
上面這幾個(gè)函數(shù)都簡(jiǎn)單明了,比較容易理解,對(duì)于ParseLine我們發(fā)現(xiàn)在進(jìn)行行跳轉(zhuǎn)的時(shí)候DetailMatch并不是必須的。什么叫行跳轉(zhuǎn)呢?比如打開一個(gè)代碼文件,現(xiàn)在我要跳轉(zhuǎn)到第5000行,那么很顯然第5000行需要放到屏幕上頭,這個(gè)時(shí)候我怎么知道第5000行的起始狀態(tài)呢?當(dāng)然也得從第一航開始分析,但是我們發(fā)現(xiàn)DetailMatch其實(shí)并不是必須的,因?yàn)槲覀冎恍枰鲏K狀識(shí)別就夠了,所以速度是非常客觀的。
先寫這么多了,等我以后老了,我打算把這些東西寫成一本書,名字就叫編輯器制作基本原理,呵呵.
不敢妄自菲薄,下面貼兩個(gè)代碼片段和上面的偽代碼均是按照上述方法生成的,還算美觀.
C++代碼
#include <stdio.h>
// line comment email test@test.com
// url:http://www.shnenglu.com/megax in comment over
/*
block comment
email test@test.com url:http://www.shnenglu.com/megax in comment over
*/
int main(int argc, char *argv[])
{
email: test@test.com
http://www.shnenglu.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.shnenglu.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.shnenglu.com/megax in comment over
/*
block comment in js
test@test.com in comment
http://www.shnenglu.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.shnenglu.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.shnenglu.com/megax in comment
over
-->
</body>
</html>
下面看一下cppblog自帶的代碼加亮,沒有c++的,用c#代替
#include <stdio.h>
// line comment email test@test.com
// url:http://www.shnenglu.com/megax in comment over
/*
block comment
email test@test.com url:http://www.shnenglu.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.shnenglu.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的
<!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.shnenglu.com/megax in comment over
/*
block comment in js
test@test.com in comment
http://www.shnenglu.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.shnenglu.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.shnenglu.com/megax in comment
over
-->
</body>
</html>
posted on 2008-07-09 20:23
megax 閱讀(2139)
評(píng)論(4) 編輯 收藏 引用