GNU Source-highlight学习笔记

简介

GNU Source-highlight可以将C、Java等语言的源代码转换成HTML、LaTeX等格式的文档,并带有语法高亮的效果。

它主要用正则表达式来定义(或识别)语言的各类元素,并用CSS样式表为各类元素指定样式。

定义某一语言的所有正则表达式放在一个.lang文件中,如c.lang、java.lang等。因此,一个.lang文件定义了一种语言。下面就讲解如何编写.lang文件。

定义语言

基本语句

语法

element = 'regular expression'
element

定义元素名,常用的有以下几类元素:

  • keyword:关键字
  • type:类型名
  • variable:变量名
  • string:字符串
  • number:数字
  • function:函数名
  • comment:注释
'regular expression'

识别该类元素的正则表达式。表达式必须用双引号(")、单引号(')或反引号(`)包围,它们的区别如下:

"expression"

普通字符串。特殊字符|用于选择。

'expression'

正则表达式,不支持捕获分组。

`expression`

正则表达式,支持捕获分组。

例子

  1. 定义C语言的关键字:

    keyword =
        "break|case|catch|cdecl|const|continue|default|do",
        "else|enum|extern|for|goto|if|pascal",
        "register|return|sizeof|static|struct",
        "switch|typedef|union|volatile|while"
    
  2. 定义C语言的数字:

    number =
        '\<[+-]?((0x[[:xdigit:]]+)|(([[:digit:]]*\.)?[[:digit:]]+([eE][+-]?[[:digit:]]+)?))u?((int(?:8|16|32|64))|L)?\>'
    

注意

  1. 对同一元素的多条定义语句会累加,而不会覆盖。例如,下面的语句等效于例1

    keyword = "break|case|catch|cdecl|const|continue|default|do"
    keyword = "else|enum|extern|for|goto|if|pascal"
    keyword = "register|return|sizeof|static|struct"
    keyword = "switch|typedef|union|volatile|while"
    
  2. 语句和正则表达式中的换行符会被忽略,因此可以适当添加换行来提高代码可读性。例如,下面的语句等效于例2

    number =
        '\<[+-]?
    ((0x[[:xdigit:]]+)|
    (([[:digit:]]*\.)?[[:digit:]]+
    ([eE][+-]?[[:digit:]]+)?))u?((int(?:8|16|32|64))|L)?\>'
    
  3. 行中的#及其后面的字符为注释。

  4. 若多条语句匹配同一处代码,则先出现的语句优先级更高。例如,下面的定义中,keywordvariable都匹配字符串"while",但"while"keyword元素。

    keyword = "switch|typedef|union|volatile|while"
    variable = '[a-zA-Z0-9_]+'
    

start语句

语法

element start 'regexp'

表示element元素的范围从'regexp'开始直到行末。

例子

  1. 定义C++风格的注释:

    comment start "//"

delim语句

语法

element delim 'left delim' 'right delim'
    [escape "escape-character"]
    [multiline] [nested]

表示element元素的范围从'left delim'开始,到'right delim'结束。

escape "escape-character"

可选项,表示转义字符。例如,要定义C语言字符串,从"开始,到"结束。在字符串中间要表示",则要用转义字符\来转义:\"。字符串的定义见例1.

multiline

可选项,表示元素的范围可以跨行。

nested

可选项,表示元素可以嵌套。

例子

  1. 定义C语言的字符串:

    string delim "\"" "\"" escape "\\"
  2. 定义C风格的注释:

    comment delim "/*" "*/" multiline nested

include语句

语法

include "another_file.lang"

用于将其他.lang文件包含进来,类似于C语言的#include语句。它有助于定义语句的重用,例如,C、C++和Java的注释都相同,可以将注释元素的定义放到c_comment.lang文件里,然后在各语言的定义文件里写一条包含语句即可。

例子

  1. 将C/C++风格的注释包含进java.lang中:

    # java.lang
    include "c_comment.lang"

state/environment语句

有些元素只在其他元素内部才有意义,例如想对C语言注释内的URL着色时,URL元素必须出现在注释内部。state/environment语句可以解决这种问题。

语法

state|environment <standard definition> begin
    <other definitions>
end

standard definition定义的元素的范围构成了一个环境。在该环境内部时,other definitions会生效,而环境外面的定义语句会失效。

stateenvironment的区别是:state内未匹配的元素不着色,而environment内的未匹配的元素按standard definiton的元素样式着色。

该语句可以嵌套。

例子

  1. 定义注释内的URL:

    environment comment delim "/*" "*/" multiline nested begin
        include "url.lang"
    end