必要なのはステートフルなレクサーです。正規表現が機能しない理由は、グループが連続していないためです。
int a=3,b=5,c=4;
ここでは、文字 0..2 を Type、3..3 スペース、4..7 Name、Equal Number、および Comma、次に Name、Equal、Number、および Comma にします。それは良くないね。
解決策は、型宣言がいつ見られたかを記憶し、次のセミコロンまで続く新しいレクサーモードに入ることです。pygments のドキュメントの状態の変更を参照
してください。
以下は、CFamilyLexer を使用し、3 つの新しいレクサー状態を追加するソリューションです。したがって、function
状態中に次のような行が表示されると:
int m = 3 * a + b, x = /* comments ; everywhere */ a * a;
最初に消費します:
int
追加した新しいルールと一致するため、次のvardecl
状態になります。
m
ああ、変数の名前!lexer はvardecl
状態にあるため、これは新しく定義された変数です。NameDecl
トークンとして発行します。その後、varvalue
州に入ります。
3
ただの数。
*
ただのオペレーター。
a
ああ、変数の名前!しかし、今は変数宣言でvarvalue
はなく、通常の変数参照の状態です。
+ b
演算子と別の変数参照。
,
m
完全に宣言された変数の値。状態に戻りvardecl
ます。
x =
新しい変数宣言。
/* comments ; everywhere */
別の状態がスタックにプッシュされます。コメントでは、そうでなければ意味を持つトークン;
は無視されます。
a * a
変数の値x
。
;
状態に戻りfunction
ます。特別な変数宣言規則が実行されます。
from pygments import highlight
from pygments.formatters import HtmlFormatter, TerminalFormatter
from pygments.formatters.terminal import TERMINAL_COLORS
from pygments.lexer import inherit
from pygments.lexers.compiled import CFamilyLexer
from pygments.token import *
# New token type for variable declarations. Red makes them stand out
# on the console.
NameDecl = Token.NameDecl
STANDARD_TYPES[NameDecl] = 'ndec'
TERMINAL_COLORS[NameDecl] = ('red', 'red')
class CDeclLexer(CFamilyLexer):
tokens = {
# Only touch variables declared inside functions.
'function': [
# The obvious fault that is hard to get around is that
# user-defined types won't be cathed by this regexp.
(r'(?<=\s)(bool|int|long|float|short|double|char|unsigned|signed|void|'
r'[a-z_][a-z0-9_]*_t)\b',
Keyword.Type, 'vardecl'),
inherit
],
'vardecl' : [
(r'\s+', Text),
# Comments
(r'/(\\\n)?[*](.|\n)*?[*](\\\n)?/', Comment.Multiline),
(r';', Punctuation, '#pop'),
(r'[~!%^&*+=|?:<>/-]', Operator),
# After the name of the variable has been tokenized enter
# a new mode for the value.
(r'[a-zA-Z_][a-zA-Z0-9_]*', NameDecl, 'varvalue'),
],
'varvalue' : [
(r'\s+', Text),
(r',', Punctuation, '#pop'),
(r';', Punctuation, '#pop:2'),
# Comments
(r'/(\\\n)?[*](.|\n)*?[*](\\\n)?/', Comment.Multiline),
(r'[~!%^&*+=|?:<>/-\[\]]', Operator),
(r'\d+[LlUu]*', Number.Integer),
# Rules for strings and chars.
(r'L?"', String, 'string'),
(r"L?'(\\.|\\[0-7]{1,3}|\\x[a-fA-F0-9]{1,2}|[^\\\'\n])'", String.Char),
(r'[a-zA-Z_][a-zA-Z0-9_]*', Name),
# Getting arrays right is tricky.
(r'{', Punctuation, 'arrvalue'),
],
'arrvalue' : [
(r'\s+', Text),
(r'\d+[LlUu]*', Number.Integer),
(r'}', Punctuation, '#pop'),
(r'[~!%^&*+=|?:<>/-\[\]]', Operator),
(r',', Punctuation),
(r'[a-zA-Z_][a-zA-Z0-9_]*', Name),
(r'{', Punctuation, '#push'),
]
}
code = '''
#include <stdio.h>
void main(int argc, char *argv[])
{
int vec_a, vec_b;
int a = 3, /* Mo;yo */ b=5, c=7;
int m = 3 * a + b, x = /* comments everywhere */ a * a;
char *myst = "hi;there";
char semi = ';';
time_t now = /* Null; */ NULL;
int arr[10] = {1, 2, 9 / c};
int foo[][2] = {{1, 2}};
a = b * 9;
c = 77;
d = (int) 99;
}
'''
for formatter in [TerminalFormatter, HtmlFormatter]:
print highlight(code, CDeclLexer(), formatter())